[Image-SIG] proposal for additional method...
kcazabon
kcazabon" <kcazabon@home.com
Fri, 18 Feb 2000 22:48:49 -0800
This is a multi-part message in MIME format.
------=_NextPart_000_000D_01BF7A62.52808000
Content-Type: text/plain;
charset="iso-8859-1"
Content-Transfer-Encoding: 7bit
In a lot of the image processing I've needed to do, there is the need to
crop and resize an image to a different aspect ratio. Doing so has been a
bit of a pain, so I've written a little function that will do so for you, as
well as providing a few extra capabilities.
It is similar to the im.thumbnail() method, but instead of fitting entirely
within the size you give, it will crop to fill the exact size you want. The
method of cropping is user-definable as well (from the center, from the
side, 30% from the top, whatever you want).
This way (assuming my function was implemented as a method in PIL), if you
had for example a 300x400 pixel image that you wanted to center-crop and
resize to be 512x768 (without distorting it), you could simply use:
im = im.fit((512,768))
alternatively, you could be a little more specific, setting the following
options:
-"method" of interpolation when resizing (0,2,3, same as in
im.resize((size), method) )
-"bleed", a default amount (in decimal percent, 0.0 - 0.49999) to crop off
all edges, useful for removing the edges of a scanned image that may include
frame edges, etc.
-"centering" to control where the crop happens, and if it's centered or
biased towards cropping more from some sides than others
I've attached my 'ImageFit' module that demonstrates these functions. The
only difference is that the first argument needs to be a PIL image object.
Feel free to try it out, and if it's easy to implement, I'd like to see it
as part of the standard PIL methods.
Kevin Cazabon.
------=_NextPart_000_000D_01BF7A62.52808000
Content-Type: text/plain;
name="ImageFit.py"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: attachment;
filename="ImageFit.py"
import Image
def fit(inputImage, outputSize, method=3D0, bleed=3D0.0, =
centering=3D[0.50,0.50]):
"""=20
This method returns a sized and cropped version of the image, =
cropped to the aspect ratio and
size that you request. It can be customized to your needs with =
"method", "bleed", and "centering"
as required.
=20
inputImage =3D an PIL Image object, could easily be changed to =
"self" to make this a method of an Image object.
outputSize =3D (width, height) in pixels of image to return
method =3D resizing method: 0=3D(replication), 2=3D(bi-linear), =
3=3D(bi-cubic)
bleed =3D decimal percentage (0-0.49999) of width/height to crop =
off as a minumum around the outside of the image
This allows you to remove a default amount of the =
image around the outside, for
'cleaning up' scans that may have edges of negs =
showing, or whatever.
This percentage is removed from EACH side, not a =
total amount.
centering =3D [left, top], percentages to crop of each side to =
fit the aspect ratio you require.
This function allows you to customize where the crop =
occurs, whether it is a=20
'center crop' or a 'top crop', or whatever. Default =
is center-cropped.
[0.5, 0.5] is center cropping (i.e. if cropping the =
width, take 50% off of the left side (and therefore 50% off the right =
side), and same with Top/Bottom)
[0.0, 0.0] will crop from the top left corner (i.e. =
if cropping the width, take all of the crop off of the right side, and =
if cropping the height, take all of it off the bottom)
[1.0, 0.0] will crop from the bottom left corner, =
etc. (i.e. if cropping the width, take all of the crop off the left =
side, and if cropping the height take none from the Top (and therefore =
all off the bottom))=20
=20
by Kevin Cazabon, Feb 17/2000
kcazabon@home.com=20
http://members.home.com/kcazabon """
=20
# ensure inputs are valid
if type(centering) !=3D type([]):
centering =3D [centering[0], centering[1]]
if centering[0] > 1.0 or centering[0] < 0.0:
centering [0] =3D 0.50
if centering[1] > 1.0 or centering[1] < 0.0:
centering[1] =3D 0.50
=20
if bleed > 0.49999 or bleed < 0.0:
bleed =3D 0.0
=20
if method not in [0, 2, 3]:
method =3D 0
# calculate the area to use for resizing and cropping, subtracting =
the 'bleed' around the edges =20
bleedPixels =3D (int((float(bleed) * float(inputImage.size[0])) + =
0.5), int((float(bleed) * float(inputImage.size[1])) + 0.5)) # number of =
pixels to trim off on Top and Bottom, Left and Right
liveArea =3D (bleedPixels[0], bleedPixels[1], inputImage.size[0] - =
bleedPixels[0] - 1, inputImage.size[1] - bleedPixels[1] - 1)
liveSize =3D (liveArea[2] - liveArea[0], liveArea[3] - liveArea[1])
=20
# calculate the aspect ratio of the liveArea
liveAreaAspectRatio =3D float(liveSize[0])/float(liveSize[1])
=20
# calculate the aspect ratio of the output image
aspectRatio =3D float(outputSize[0])/float(outputSize[1])
=20
# figure out if the sides or top/bottom will be cropped off
if liveAreaAspectRatio >=3D aspectRatio:
# liveArea is wider than what's needed, crop the sides
cropWidth =3D int((aspectRatio * float(liveSize[1])) + 0.5)
cropHeight =3D liveSize[1]
=20
else:
#liveArea is taller than what's needed, crop the top and bottom
cropWidth =3D liveSize[0]
cropHeight =3D int((float(liveSize[0])/aspectRatio) + 0.5)
=20
# make the crop =20
leftSide =3D int(liveArea[0] + (float(liveSize[0] - cropWidth) * =
centering[0]))
if leftSide < 0:
leftSide =3D 0
topSide =3D int(liveArea[1] + (float(liveSize[1] - cropHeight) * =
centering[1]))
if topSide < 0:
topSide =3D 0
=20
=20
outputImage =3D inputImage.crop((leftSide, topSide, leftSide + =
cropWidth, topSide + cropHeight))
=20
# resize the image and return it =20
return outputImage.resize(outputSize, method)
=20
=20
=20
=20
=20
=20
=20
=20
=20
------=_NextPart_000_000D_01BF7A62.52808000--