24

I'm trying to rotate an image in Python using PIL and having the expand argument to true. It seems that when the background of my image is black, the resulting image saved as a bmp will be a lot smaller than if I have a white background for my image, and then I replace the black due to expand with white. In either case, my original image is always of two colors, and right now i need the file size to be small, since I'm putting these images on an embedded device.

Any ideas if i can force rotate to fill in another color when expanding or if there is another way to rotate my picture in order to make it small?

Alex B
  • 1,575
  • 5
  • 16
  • 19

3 Answers3

36

If your original image has no alpha layer, you can use an alpha layer as a mask to convert the background to white. When rotate creates the "background", it makes it fully transparent.

# original image
img = Image.open('test.png')
# converted to have an alpha layer
im2 = img.convert('RGBA')
# rotated image
rot = im2.rotate(22.2, expand=1)
# a white image same size as rotated image
fff = Image.new('RGBA', rot.size, (255,)*4)
# create a composite image using the alpha layer of rot as a mask
out = Image.composite(rot, fff, rot)
# save your work (converting back to mode='1' or whatever..)
out.convert(img.mode).save('test2.bmp')
Paul
  • 42,322
  • 15
  • 106
  • 123
  • 1
    Why does `rot` used 2 times in `composite`? – Dims Jul 11 '18 at 19:34
  • @Dims http://pillow.readthedocs.io/en/3.1.x/reference/Image.html#PIL.Image.composite The third arg uses only the alpha layer of `rot` as a mask. – Paul Jul 11 '18 at 22:10
  • Still don't understand. Why not just put rotated image onto white? – Dims Jul 11 '18 at 22:37
  • @Dims I don't think the mask argument is optional for `composite`. I'm sure `paste` or some other method would work equally well if that is your point. – Paul Jul 12 '18 at 02:40
10

There is a parameter fillcolor in a rotate method to specify color which will be use for expanded area:

white = (255,255,255)
pil_image.rotate(angle, PIL.Image.NEAREST, expand = 1, fillcolor = white)

https://pillow.readthedocs.io/en/stable/reference/Image.html#PIL.Image.Image.rotate

Deil
  • 492
  • 4
  • 14
0

Here is a working version, inspired by the answer, but it works without opening or saving images and shows how to rotate a text.

The two images have colored background and alpha channel different from zero to show what's going on. Changing the two alpha channels from 92 to 0 will make them completely transparent.

from PIL import Image, ImageFont, ImageDraw

text = 'TEST'
font = ImageFont.truetype(r'C:\Windows\Fonts\Arial.ttf', 50)
width, height = font.getsize(text)

image1 = Image.new('RGBA', (200, 150), (0, 128, 0, 92))
draw1 = ImageDraw.Draw(image1)
draw1.text((0, 0), text=text, font=font, fill=(255, 128, 0))

image2 = Image.new('RGBA', (width, height), (0, 0, 128, 92))
draw2 = ImageDraw.Draw(image2)
draw2.text((0, 0), text=text, font=font, fill=(0, 255, 128))

image2 = image2.rotate(30, expand=1)

px, py = 10, 10
sx, sy = image2.size
image1.paste(image2, (px, py, px + sx, py + sy), image2)

image1.show()
stenci
  • 8,290
  • 14
  • 64
  • 104