Ticket #4076: 0001-Rotate-Zoom-and-center-the-image.patch

File 0001-Rotate-Zoom-and-center-the-image.patch, 7.1 KB (added by humitos, 12 years ago)
  • ImageView.py

    From d08bb7d4373b09cd3d4e6b0077f92205e614e6ad Mon Sep 17 00:00:00 2001
    From: Manuel Kaufmann <humitos@gmail.com>
    Date: Tue, 23 Oct 2012 10:34:49 -0300
    Subject: [PATCH ImageViewer] Rotate, Zoom and center the image
    
    Improves the rotation by centering the image on the screen when it is
    smaller than the screen size.
    
    Optimal zoom is calculated for images than are higher in hight when
    they are rotated as well.
    
    Fixed rotation (anti)clockwise. X, Y axis + angles in gradians are
    handled different by cairo.
    
    Signed-off-by: Manuel Kaufmann <humitos@gmail.com>
    ---
     ImageView.py           | 113 ++++++++++++++++++++++++++++++++++---------------
     ImageViewerActivity.py |   4 +-
     2 files changed, 82 insertions(+), 35 deletions(-)
    
    diff --git a/ImageView.py b/ImageView.py
    index 30b19ac..cbc5516 100644
    a b import logging 
    2727import cairo
    2828import random
    2929import time
     30import math
    3031
    3132ZOOM_IN_OUT = 0.1
    3233
    class ImageViewer(Gtk.DrawingArea): 
    7172        self._fast = True
    7273        self._redraw_id = None
    7374        self._is_touching = False
     75        self._switched = False
    7476
    7577    def do_get_property(self, pspec):
    7678        if pspec.name == 'zoom':
    class ImageViewer(Gtk.DrawingArea): 
    123125        h = int(self.surface.get_height() * self.zoom)
    124126        logging.error('W: %s, H: %s', w, h)
    125127
    126         ctx.save()
    127128        if self._fast:
    128129            ctx.set_antialias(cairo.ANTIALIAS_NONE)
    129         if self.angle != 0:
    130             logging.error('Rotating: %s', self.angle)
    131             ctx.translate(0.5 * w, 0.5 * h)
    132             ctx.rotate(self.angle)
    133             ctx.translate(-0.5 * w, -0.5 * h)
    134130
    135131        scrolled_window = self.get_parent()
    136132        rect = scrolled_window.get_allocation()
    137133        x = y = 0
    138         if rect.width >= w:
    139             x = int((rect.width - w) / 2)
    140         elif self._is_touching:
    141             hadj = int((w - rect.width) / 2)
    142             hadjustment = scrolled_window.get_hadjustment()
    143             hadjustment.set_value(hadj)
    144 
    145         if rect.height >= h:
    146             y = int((rect.height - h) / 2)
    147         elif self._is_touching:
    148             vadj = int((h - rect.height) / 2)
    149             vadjustment = scrolled_window.get_vadjustment()
    150             vadjustment.set_value(vadj)
     134        if self.angle != 0:
     135            logging.error('Rotating: %s', self.angle)
     136            ctx.rotate(self.angle)
     137
     138            if self.angle == math.pi:
     139                ctx.translate(-w, -h)
     140
     141                if rect.width > w:
     142                    x = -(rect.width - w) / 2
     143                if rect.height > h:
     144                    y = -(rect.height - h) / 2
     145
     146            elif self.angle == math.pi / 2:
     147                ctx.translate(0, -h)
     148
     149                # center the image
     150                if rect.height > w:
     151                    x = (rect.height - w) / 2
     152                if rect.width > h:
     153                    y = -(rect.width - h) / 2
     154
     155            elif self.angle == math.pi * 3 / 2:
     156                ctx.translate(-w, 0)
     157
     158                if rect.height > w:
     159                    x = -(rect.height - w) / 2
     160                if rect.width > h:
     161                    y = (rect.width - h) / 2
     162
     163        else:
     164            if rect.width > w:
     165                x = int((rect.width - w) / 2)
     166            if rect.height > h:
     167                y = int((rect.height - h) / 2)
     168        ctx.translate(x, y)
     169
     170        if self._is_touching:
     171            if self._switched:
     172                w, h = h, w
     173
     174            if rect.height < h:
     175                vadj = int((h - rect.height) / 2)
     176                vadjustment = scrolled_window.get_vadjustment()
     177                vadjustment.set_value(vadj)
     178
     179            if rect.width < w:
     180                hadj = int((w - rect.width) / 2)
     181                hadjustment = scrolled_window.get_hadjustment()
     182                hadjustment.set_value(hadj)
    151183
    152184        if self.zoom != 1:
    153185            logging.error('Scaling: %s', self.zoom)
    154             ctx.translate(x, y)
    155186            ctx.scale(self.zoom, self.zoom)
    156187
    157188        ctx.set_source_surface(self.surface, 0, 0)
    class ImageViewer(Gtk.DrawingArea): 
    171202    def _redraw_high_quality(self):
    172203        self._fast = False
    173204        self._redraw_id = None
    174         self.queue_draw()
     205        self._redraw()
    175206        return False
    176207
     208    def _redraw(self):
     209        # README: this is a hack to not raise the 'draw' event (again)
     210        # when we request more space to show the scroll bars
     211        w = int(self.surface.get_width() * self.zoom)
     212        h = int(self.surface.get_height() * self.zoom)
     213
     214        self._switched = False
     215        if (self.angle / (math.pi / 2)) % 2 == 1:
     216            # change image dimensions if it's rotated
     217            w, h = h, w
     218            self._switched = True
     219
     220        self.set_size_request(w, h)
     221
    177222    def set_zoom(self, zoom):
    178223        self._optimal_zoom_flag = False
    179224        self._set_zoom(zoom)
    class ImageViewer(Gtk.DrawingArea): 
    191236    def set_angle(self, angle):
    192237        self._optimal_zoom_flag = True
    193238
    194         self.angle = angle
    195         self.queue_draw()
     239        self.angle = angle % (2 * math.pi)
     240        self._redraw()
    196241        self.emit('angle-changed')
    197242
    198243    def zoom_in(self):
    class ImageViewer(Gtk.DrawingArea): 
    238283        width = rect.width
    239284        height = rect.height
    240285
    241         if width < self.surface.get_width() or \
    242                 height < self.surface.get_height():
     286        surface_width = self.surface.get_width()
     287        surface_height = self.surface.get_height()
     288
     289        if self._switched:
     290            surface_width, surface_height = \
     291                surface_height, surface_width
     292
     293        if width < surface_width or \
     294                height < surface_height:
    243295            # Image is larger than allocated size
    244             zoom = min(width / self.surface.get_width(),
    245                     height / self.surface.get_height())
     296            zoom = min(width / surface_width,
     297                    height / surface_height)
    246298        else:
    247299            zoom = 1
    248300
    class ImageViewer(Gtk.DrawingArea): 
    251303
    252304    def _set_zoom(self, zoom):
    253305        self.zoom = zoom
    254 #        # README: this is a hack to not raise the 'draw' event (again)
    255 #        # when we request more space to show the scroll bars
    256         self._fast = True
    257         w = int(self.surface.get_width() * self.zoom)
    258         h = int(self.surface.get_height() * self.zoom)
    259         self.set_size_request(w, h)
     306        self._redraw()
    260307        self.emit('zoom-changed')
    261308
    262309
  • ImageViewerActivity.py

    diff --git a/ImageViewerActivity.py b/ImageViewerActivity.py
    index f17d4cf..3b36103 100644
    a b class ImageViewerActivity(activity.Activity): 
    310310        self.view.set_zoom(1)
    311311
    312312    def __rotate_anticlockwise_cb(self, button):
    313         angle = self.view.angle + math.pi / 2
     313        angle = self.view.angle - math.pi / 2
    314314        self.view.set_angle(angle)
    315315
    316316    def __rotate_clockwise_cb(self, button):
    317         angle = self.view.angle - math.pi / 2
     317        angle = self.view.angle + math.pi / 2
    318318        self.view.set_angle(angle)
    319319
    320320    def __fullscreen_cb(self, button):