Drawing a semi-transparent rectangle on a jpeg file with wx.Bitmap - python

I need to load a jpeg->draw a semi-transparent rectangle->save the jpeg file
using wx.Bitmap of the python wx package.
But the rectangle appears fully opaque.
I'm using Windows 7 with 32bpp.
I checked and try the "Docs and Demos\demo\AlphaDrawing.py" wx demo, and it works well.
It draws correctly on wx.Panel a semi-transparent rectangle.
I checked on the internet for a solution for this problem, but none of the solutions worked.
I created a more simple example, to minimize the possibilities of error, and still didn't work.
Load a jpg->draw a semi-transparent rectangle->save as jpg file
wimg = wx.Image(r"N:\Images\Wallpapers\Processed\a.jpg", wx.BITMAP_TYPE_JPEG)
print wimg.HasAlpha()
wimg.InitAlpha()
print wimg.HasAlpha()
bmp = wimg.ConvertToBitmap()
print bmp.HasAlpha()
dc = wx.MemoryDC(bmp)
r, g, b = (34, 34, 34)
dc.SetPen(wx.Pen(wx.Colour(r, g, b, wx.ALPHA_OPAQUE)))
dc.SetBrush(wx.Brush(wx.Colour(r, g, b, 128)))
dc.DrawRectangle(100, 300, 200, 200)
bmp.SaveFile(r"N:\Images\Wallpapers\Processed\b.jpg", wx.BITMAP_TYPE_JPEG)
The print results are: False/True/True
And still the output it's a fully opaque rectangle
I known jpeg doesn't has alpha channels, but I don't want a 32bpp jpeg.
Just the output to show rectangle blended with the background.

Bitmap files have no Alpha channel. You must load a PNG file to use transparency.
"Unlike RGB data, not all images have an alpha channel and before using GetAlpha you should check if this image contains an alpha channel with HasAlpha. Note that currently only images loaded from PNG files with transparency information will have an alpha channel."
http://www.wxpython.org/docs/api/wx.Image-class.html

Related

Converting PNG to JPEG creates pixel noise in the background

I have to convert some PNGs with transparent bg to simple JPEGs where the transparent background turns to white (which I assumed will happen by default). I have tried all of the solutions I could find here, but after saving the PNG as JPEG the image will look like this: (the noisy area was transparent on the PNG and the black was drop shadow)
Converted image
Original image
This is the code I use:
# save the PNG
response = requests.get(image_url, headers = header)
file = open("%s-%s.png" % (slug, item_id,), "wb")
file.write(response.content)
file.close()
# open the PNG and save as a JPEG
im1 = Image.open(filepath_to_png)
rgb_im = im1.convert('RGB')
rgb_im.mode
rgb_im.save(filepath_normal)
My question is that how could I prevent the JPEG to have that corrupted background? My goal is just simply have the same image in JPEG what I had in PNG.
The method you are using to convert to RGB would work on some images that just require straight-forward conversion like the ones with hard-edged transparency masks, but for those with soft-edged masking (like the transparency shadows in your image) it is not be effective as the conversion does not know how to deal with that semi-transparency.
A better approach to handle this would be to create a new Image with the same dimensions and fill it with a white background, then you just need to paste your original image:
new_im = Image.new( "RGB", im1.size, ( 255,255,255 ) )
new_im.paste( im1, im1 )
new_im.save( filepath_normal )
I have tested this approach using an image with soft-edged masking and obtained the following result:
You could use pillow library in python.
from PIL import Image
im = Image.open("1.png")
bg = Image.new("RGB", im.size, (255,255,255))
bg.paste(im,im)
bg.save("2.jpg")
Result I got had transparent background turned to white.

python OpenCv IMREAD_UNCHANGED only return three channels

Hi guys I'm trying to figure out what's wrong with my code
I want to load my image contains alpha channel
the description from official website says that:
cv.IMREAD_UNCHANGED: If set, return the loaded image as is (with alpha channel, otherwise it gets cropped).
Here's my try:
import cv2 as cv
img2 = cv.imread( 'lbj.jpg' , cv.IMREAD_UNCHANGED)
img2.shape
And the result shows : (350, 590, 3)
Isn't is supposed to be (350,590,4)?
Thanks!
The reason there are only three channels is that the image is in jpg format, which does not have an alpha channel. If you were to load e.g. a png format image which had an alpha channel then
img2 = cv.imread( 'lbj.png' , cv.IMREAD_UNCHANGED)
with 'lbj.png' would load the image with the alpha channel included, and then
img2.shape
would show (350, 590, 4).
If you convert a jpg to png then you will still, at that point, have only three channels because the image would only have the BGR channels that were in the original jpg. However, you could at this point add an alpha channel to make it BGRA and then proceed to work with transparency options.
Adding an alpha channel is answered in python-opencv-add-alpha-channel-to-rgb-image

How to save an .EPS file to PNG with transparency in Python

I'm building a Paint-like app Since I want the freedom to reposition and modify the shape properties later, I am using Tkinter to draw shapes on Canvas instead of PIL Draw or anything else. From other answers, I found how to save a canvas as PNG by 1st creating a postscript file and then converting it to PNG using PIL.
Now the problem is the EPS file has transparent spaces but the PNG file fills those voids with a White background color. I'm not sure where I am going wrong.
Below is the function I used.
def saveImg(event):
global canvas
canvas.postscript(file="my_drawing.eps", colormode='color')
imgNew = Image.open("my_drawing.eps")
imgNew.convert("RGBA")
imgNew.thumbnail((2000,2000), Image.ANTIALIAS)
imgNew.save('testImg.png', quality=90)
Looks like transparency is not supported. From the docs:
The EPS driver can read EPS images in L, LAB, RGB and CMYK mode, but Ghostscript may convert the images to RGB mode rather than leaving them in the original color space.
When you load in RGB (instead of RGBA) the alpha channel information is discarded and converting it to RGBA later will not recover it.
Your best shot is porting it to more recent toolkits like cairo or QT or converting the file using GhostScript directly as suggested by PM2Ring.
For the GS approach in order to set the width and height of the output file you must use the -rN switch where N is the resolution in PPI (pixels per inch). You must do the math in order to get target resolution from the EPS bounding box and the desired output size.
Or you can render to a fixed resolution first, lets say, 100 PPI, see the width you got and do the math in order to get the correct resolution. For example, if rendering with -r100 gives you a file 500 pixels wide but you want it to be 1024:
desired_resolution = initial_resolution * desired_width // initial_width
In order to get a file 1024 pixels wide:
>>> 100 * 1024 // 500
204
So you must render the EPS again using -r204.
Edit 1:
I got the solution from this Question
We can set custom width and height using -gNNNNxMMMM
but the dpi value crops only a small area. I tried with the usual 72dpi and I got a decent output(I'm not sure if it's perfect or not). Now I need to find how to execute this command every time when I run the program and provide the custom image size value. :\

Python Image Library: clean Downsampling

I've been having trouble trying to get PIL to nicely downsample images. The goal, in this case, is for my website to automagically downsample->cache the original image file whenever a different size is required, thus removing the pain of maintaining multiple versions of the same image. However, I have not had any luck. I've tried:
image.thumbnail((width, height), Image.ANTIALIAS)
image.save(newSource)
and
image.resize((width, height), Image.ANTIALIAS).save(newSource)
and
ImageOps.fit(image, (width, height), Image.ANTIALIAS, (0, 0)).save(newSource)
and all of them seem to perform a nearest-neighbout downsample, rather than averaging over the pixels as it should Hence it turns images like
http://www.techcreation.sg/media/projects//software/Java%20Games/images/Tanks3D%20Full.png
to
http://www.techcreation.sg/media/temp/0x5780b20fe2fd0ed/Tanks3D.png
which isn't very nice. Has anyone else bumped into this issue?
That image is an indexed-color (palette or P mode) image. There are a very limited number of colors to work with and there's not much chance that a pixel from the resized image will be in the palette, since it will need a lot of in-between colors. So it always uses nearest-neighbor mode when resizing; it's really the only way to keep the same palette.
This behavior is the same as in Adobe Photoshop.
You want to convert to RGB mode first and resize it, then go back to palette mode before saving, if desired. (Actually I would just save it in RGB mode, and then turn PNGCrush loose on the folder of resized images.)
This is over a year old, but in case anyone is still looking:
Here is a sample of code that will see if an image is in a palette mode, and make adjustments
import Image # or from PIL import Image
img = Image.open(sourceFile)
if 'P' in img.mode: # check if image is a palette type
img = img.convert("RGB") # convert it to RGB
img = img.resize((w,h),Image.ANTIALIAS) # resize it
img = img.convert("P",dither=Image.NONE, palette=Image.ADAPTIVE)
#convert back to palette
else:
img = img.resize((w,h),Image.ANTIALIAS) # regular resize
img.save(newSourceFile) # save the image to the new source
#img.save(newSourceFile, quality = 95, dpi=(72,72), optimize = True)
# set quality, dpi , and shrink size
By converting the paletted version to RGB, we can resize it with the anti alias. If you want to reconvert it back, then you have to set dithering to NONE, and use an ADAPTIVE palette. If there options aren't included your result (if reconverted to palette) will be grainy. Also you can use the quality option, in the save function, on some image formats to improve the quality even more.

Transparent PNG in PIL turns out not to be transparent

I have been hitting my head against the wall for a while with this, so maybe someone out there can help.
I'm using PIL to open a PNG with transparent background and some random black scribbles, and trying to put it on top of another PNG (with no transparency), then save it to a third file.
It comes out all black at the end, which is irritating, because I didn't tell it to be black.
I've tested this with multiple proposed fixes from other posts. The image opens in RGBA format, and it's still messed up.
Also, this program is supposed to deal with all sorts of file formats, which is why I'm using PIL. Ironic that the first format I tried is all screwy.
Any help would be appreciated. Here's the code:
from PIL import Image
img = Image.open(basefile)
layer = Image.open(layerfile) # this file is the transparent one
print layer.mode # RGBA
img.paste(layer, (xoff, yoff)) # xoff and yoff are 0 in my tests
img.save(outfile)
I think what you want to use is the paste mask argument.
see the docs, (scroll down to paste)
from PIL import Image
img = Image.open(basefile)
layer = Image.open(layerfile) # this file is the transparent one
print layer.mode # RGBA
img.paste(layer, (xoff, yoff), mask=layer)
# the transparancy layer will be used as the mask
img.save(outfile)

Categories

Resources