If color values of original image are given as array
image[x][y]
Then color values of zoomed image are
image[x+zf*(px-x)][y+zf*(py-y)]
Regarding the windows size/image size - initial preparation of image should take care of that: zoom the image up to the point that it would not fit the window any more and fill the remaining pixels with your preferred background colour.
In python you can do something like
def naivezoom(im, px, py, zf, bg):
out = Image.new(im.mode, im.size)
pix = out.load()
iw, ih = im.size
for x in range(iw):
for y in range(ih):
xorg = x + zf*(px - x)
yorg = y + zf*(py - y)
if xorg >= 0 and xorg < iw and yorg >= 0 and yorg < ih:
pix[x,y] = im.getpixel( (xorg , yorg) )
else:
pix[x,y] = bg
return out
after you set
im = Image.open("filename.ext")
with objects from
import Image
EDIT:
Given stackoverflow logo you will get
for zf = 0.3, around point 25,6
for zf = 0.96, around the same point
Images were obtained with following code
#!/bin/env python
from Tkinter import *
import Image
import ImageTk
def naivezoom(im, p, zf, bg):
out = Image.new(im.mode, im.size)
pix = out.load()
iw, ih = im.size
for x in range(iw):
for y in range(ih):
xorg = x + zf*(p[0] - x)
yorg = y + zf*(p[1] - y)
if xorg >= 0 and xorg < iw and yorg >= 0 and yorg < ih:
pix[x,y] = im.getpixel( (xorg , yorg) )
else:
pix[x,y] = bg
return out
class NaiveTkZoom:
def __init__(self, parent=None):
root = Tk()
self.im = Image.open('logo.jpg')
self.zf = 0.0
self.deltazf = 0.02
self.p = ( 0.1*self.im.size[0],0.1*self.im.size[1])
self.bg = 255
canvas = Canvas(root, width=self.im.size[0]+20 , height=self.im.size[1]+20)
canvas.pack()
root.bind('<Key>', self.onKey)
self.canvas = canvas
self.photo = ImageTk.PhotoImage(self.im)
self.item = self.canvas.create_image(10, 10, anchor=NW, image=self.photo)
def onKey(self, event):
if event.char == "+":
if self.zf < 1:
self.zf += self.deltazf
elif event.char == "-":
if self.zf > 0:
self.zf -= self.deltazf
self.out = naivezoom(self.im, self.p, self.zf, self.bg)
self.photo = ImageTk.PhotoImage(self.out)
self.canvas.delete(self.item)
self.item = self.canvas.create_image(10, 10, anchor=NW, image=self.photo)
print self.p, self.zf
if __name__ == "__main__":
NaiveTkZoom()
mainloop()
The libraries used and pixel by pixel approach are not the fastest in the world, but will give you enough material to play with.
Also the above code is not very clean.
EDIT2(and3, centered the formula):
Here's another attempt, added translation, but I have a feeling this is not final either (don't have the time to check the formulas). Also the speed of the translation is constant, but that may lead to zooming to slow and showing background (if the point to which you are zooming is too close to the edge).
I've also added a point on the original image so that it is visible what happens with it without need to paint on original image.
#!/bin/env python
from Tkinter import *
import Image
import ImageTk
def markImage(im, p, bg):
pix = im.load()
pix[ p[0], p[1] ] = bg
def naiveZoom(im, p, zf, bg):
out = Image.new(im.mode, im.size)
pix = out.load()
iw, ih = im.size
for x in range(iw):
for y in range(ih):
xorg = x + zf*(p[0]+0.5-x) + zf*(1-zf)*(p[0]-iw/2)
yorg = y + zf*(p[1]+0.5-y) + zf*(1-zf)*(p[1]-ih/2)
if xorg >= 0 and xorg < iw and yorg >= 0 and yorg < ih:
pix[x,y] = im.getpixel( (xorg , yorg) )
else:
pix[x,y] = bg
return out
class NaiveTkZoom:
def __init__(self, parent=None):
root = Tk()
self.im = Image.open('py.jpg')
self.zf = 0.0
self.deltazf = 0.05
self.p = (round(0.3*self.im.size[0]), round(0.3*self.im.size[1]) )
self.bg = 255
markImage(self.im, self.p, self.bg)
canvas = Canvas(root, width=self.im.size[0]+20 , height=self.im.size[1]+20)
canvas.pack()
root.bind('<Key>', self.onKey)
self.canvas = canvas
self.photo = ImageTk.PhotoImage(self.im)
self.item = self.canvas.create_image(10, 10, anchor=NW, image=self.photo)
self.change = False
def onKey(self, event):
if event.char == "+":
if self.zf < 1:
self.zf += self.deltazf
self.change = True
elif event.char == "-":
if self.zf > 0:
self.zf -= self.deltazf
self.change = True
if self.change:
self.out = naiveZoom(self.im, self.p, self.zf, self.bg)
self.photo = ImageTk.PhotoImage(self.out)
self.canvas.delete(self.item)
self.change = False
self.item = self.canvas.create_image(10, 10, anchor=NW, image=self.photo)
print self.p, self.zf
if __name__ == "__main__":
NaiveTkZoom()
mainloop()
There is quite a lot in the above that could be improved. :)