Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>To my knowledge the built-in Tkinter Canvas class scale will not auto-scale images. If you are unable to use a custom widget, you can scale the raw image and replace it on the canvas when the scale function is invoked.</p> <p>The code snippet below can be merged into your original class. It does the following:</p> <ol> <li>Caches the result of <code>Image.open()</code>.</li> <li>Adds a <code>redraw()</code> function to calculate the scaled image and adds that to the canvas, and also removes the previously-drawn image if any.</li> <li>Uses the mouse coordinates as part of the image placement. I just pass <code>x and y</code> to the <code>create_image</code> function to show how the image placement shifts around as the mouse moves. You can replace this with your own center/offset calculation.</li> <li>This uses the Linux mousewheel buttons 4 and 5 (you'll need to generalize it to work on Windows, etc).</li> </ol> <p>(<strong>Updated</strong>) Code:</p> <pre><code>class GUI: def __init__(self, root): # ... omitted rest of initialization code self.canvas.config(scrollregion=self.canvas.bbox(ALL)) self.scale = 1.0 self.orig_img = Image.open(File) self.img = None self.img_id = None # draw the initial image at 1x scale self.redraw() # ... rest of init, bind buttons, pack frame def zoom(self,event): if event.num == 4: self.scale *= 2 elif event.num == 5: self.scale *= 0.5 self.redraw(event.x, event.y) def redraw(self, x=0, y=0): if self.img_id: self.canvas.delete(self.img_id) iw, ih = self.orig_img.size size = int(iw * self.scale), int(ih * self.scale) self.img = ImageTk.PhotoImage(self.orig_img.resize(size)) self.img_id = self.canvas.create_image(x, y, image=self.img) # tell the canvas to scale up/down the vector objects as well self.canvas.scale(ALL, x, y, self.scale, self.scale) </code></pre> <p><strong>Update</strong> I did a bit of testing for varying scales and found that quite a bit of memory is being used by resize / create_image. I ran the test using a 540x375 JPEG on a Mac Pro with 32GB RAM. Here is the memory used for different scale factors:</p> <pre><code> 1x (500, 375) 14 M 2x (1000, 750) 19 M 4x (2000, 1500) 42 M 8x (4000, 3000) 181 M 16x (8000, 6000) 640 M 32x (16000, 12000) 1606 M 64x (32000, 24000) ... reached around ~7400 M and ran out of memory, EXC_BAD_ACCESS in _memcpy </code></pre> <p>Given the above, a more efficient solution might be to determine the size of the viewport where the image will be displayed, calculate a cropping rectangle around the center of the mouse coordinates, crop the image using the rect, then scale just the cropped portion. This should use constant memory for storing the temporary image. Otherwise you may need to use a 3rd party Tkinter control which performs this cropping / windowed scaling for you.</p> <p><strong>Update 2</strong> Working but oversimplified cropping logic, just to get you started:</p> <pre><code> def redraw(self, x=0, y=0): if self.img_id: self.canvas.delete(self.img_id) iw, ih = self.orig_img.size # calculate crop rect cw, ch = iw / self.scale, ih / self.scale if cw &gt; iw or ch &gt; ih: cw = iw ch = ih # crop it _x = int(iw/2 - cw/2) _y = int(ih/2 - ch/2) tmp = self.orig_img.crop((_x, _y, _x + int(cw), _y + int(ch))) size = int(cw * self.scale), int(ch * self.scale) # draw self.img = ImageTk.PhotoImage(tmp.resize(size)) self.img_id = self.canvas.create_image(x, y, image=self.img) gc.collect() </code></pre>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload