Opening Tif file with PIL "PIL.UnidentifiedImageError: cannot identify image file" - python

I've a huge TIF file of shape (39906, 30365, 4). I want to use it on PyQt5, however when I use PIL to open the image it gives the error "PIL.UnidentifiedImageError: cannot identify image file".
I've searched and it seems that PIL can open TIF/TIFF files, but it has to be 8bit and my image is 8bit.
What could I do fix it? Is the file to large to be open by PIL? Is there another option to open a huge TIF to be used with PyQt5?
It's not necessary to open the whole image. Actually, if I could open a 25% scaled version of the original would be better.
Pillow version = 7.2.0

If you are having issues handling very large images, consider using libvips, either in your Python code or in the Terminal. It is very fast and frugal with memory.
Here's an example for Terminal:
vipsthumbnail BIGBOY.TIF --size 10000x -o small.tif # reduce width to 10000px
And see usingVIPSandShrink() here.

Related

How open a stack of .tif images with python

i have a file with 300 .tif images, i want to open it with python and save them into an array, list or any similar structure. I´ve tried the code below but only appears 3 images. ¿Any solution?. Thanks.
raw = cv2.imread('sen_15Hz_500Hz_6_6A.tif')
print(np.shape(raw))
I´ve tried with PIL and cv2 too.
If you really have one single TIFF file with 300 images in it, the simplest is to open it with tifffile.
with TiffFile('temp.tif') as tif:
for page in tif.pages:
image = page.asarray()
If you want to use PIL look at the section "Image Sequences" here.

Read in image as grayscale, but need the number of colour channels in the original colour image

I am using OpenCV Python to read in images. I read them in as grayscale as reading in the full colour image is expensive. However, I still need to identify the number of colour channels in the original image.
Is there a simple method of extracting the number of colour channels in an image using EXIF tags, PIL or any other libraries without reading in the full colour image?
imagemagick: $ magick identify -ping <file> reads as little as possible of a file and dumps a few basic properties of the picture file. discussion: https://legacy.imagemagick.org/discourse-server/viewtopic.php?t=18042
you can run and read that using python's subprocess module. check_output() is probably most useful here.
I've just tried that on a 5 GB TIFF file and it runs in no time at all.
you will have to interpret that line somewhat. it says here "8-bit sRGB", which would imply three channels. sRGB is an RGB color space.
you can pass -format ... and a format string to get custom output.
imagemagick has a command line interface but I hear it also has APIs you can call from python. other answer with details on that: Can I access ImageMagick API with Python?
if that's unsuitable you will need to use specific libraries (libjpeg, libpng, libtiff, ...)

Save 32-bit floating point TIFF image

I'm trying to save a 32-bit floating point image (stored as a Numpy array) as a TIFF file using tifffile.py.
import numpy as np
import tifffile
image = np.random.rand(500, 500, 3).astype(np.float32)
tifffile.imsave('image.tiff', image)
However, when viewing the output of the above code in Eye of Gnome, the image is entirely blank.
I think the problem is that not all tools support multi-channel TIFFs with 32-bits per channel. For example, as far as I can tell Python's PIL library does not. But I think tifffile.py does, because if I use your code I get a TIFF that opens, and looks reasonable, in GIMP:
From what I read, Photoshop can read 32-bit TIFFs too. So I think the TIFF file contains your image, but whether it works for you or not depends on what you want to do with it next.
This question might be relevant too, although it's about using 16-bit integers not floats: Python: Read and write TIFF 16 bit , three channel , colour images

How to convert SVG to PNG or JPEG in Python?

I'm using svgwrite and generating svg-files, how do I convert them to PNG or JPEG?
pyvips supports SVG load. It's free, fast, needs little memory, and works on macOS, Windows and Linux.
You can use it like this:
import pyvips
image = pyvips.Image.new_from_file("something.svg", dpi=300)
image.write_to_file("x.png")
The default DPI is 72, which might be a little low, but you can set any DPI you like. You can write to JPG instead in the obvious way.
You can also load by the pixel dimensions you want like this:
import pyvips
image = pyvips.Image.thumbnail("something.svg", 200, height=300)
image.write_to_file("x.png")
That will render the SVG to fit within a 200 x 300 pixel box. The docs introduce all the options.
The pyvips SVG loader has some nice properties:
It uses librsvg for the actual rendering, so the PNG will have high-quality anti-aliased edges.
It's much faster than systems like ImageMagick, which simply shell out to inkscape for rendering.
It supports progressive rendering. Large images (more than a few thousand pixels a side) are rendered in sections, keeping memory use under control, even for very large images.
It supports streaming, so you can render an SVG directly to a huge Deep Zoom pyramid (for example) without needing any intermediate storage.
It supports input from memory areas, strings and pipes as well as files.
Rendering from strings can be handy, eg.:
import pyvips
x = pyvips.Image.svgload_buffer(b"""
<svg viewBox="0 0 200 200">
<circle r="100" cx="100" cy="100" fill="#900"/>
</svg>
""")
x.write_to_file("x.png")
For converting svg to png, there are 2 ways I can think of:
1.
Here is lib which can do what you need: https://cairosvg.org/documentation/
$ pip3 install cairosvg
python3 code:
cairosvg.svg2png(url="/path/to/input.svg", write_to="/tmp/output.png")
Have used it on linux (debian 9+ and ubuntu 18+) and MacOS. It works as expect for large files about 1MB svg. Example: world map. Lib also allow to export pdf file.
Tip: cairosvg provide scaling up of png output image as default size looks blurry after working with vector graphics svg :) . I couldn't get DPI option working for me.
2.
There is another method to do same by using browser to open svg file and take screenshot using Selenium webdriver either with Firefox or other browser. You can save screenshot as png.
One can use Pillow to convert png to jpeg: Convert png to jpeg using Pillow
On Windows, you get errors like libgobject-2.0-0.dll, libvips-42.dll, etc. not found when trying to import pyvips. To get pyvips working on Windows, do the following:
Download the zip file for Windows from https://github.com/libvips/libvips/releases and unzip to a folder
pip install pyvips
In code do this:
import os
# The bin folder has the DLLs
os.environ['path'] += r';C:\Path\ToYour\VIPsFolder\bin'
import pyvips
image = pyvips.Image.thumbnail("test.svg", 200)
image.write_to_file("test.png")
I recommend using pyvips over cairosvg. From my tests it's much faster than cairosvg, especially for large SVGs. You need to something similar to the above to get cairosvg working on Windows anyway.
I looked several methods, including cairo (which I could not make it work on Windows), svglib+reportlab (dpi cannot be changed) and even inkscape (from command line).
At the end this is the best method I found. I tested it on python 3.7.
def convert(method, svg_file, png_file, resolution = 72):
from wand.api import library
import wand.color
import wand.image
with open(svg_file, "r") as svg_file:
with wand.image.Image() as image:
with wand.color.Color('transparent') as background_color:
library.MagickSetBackgroundColor(image.wand,
background_color.resource)
svg_blob = svg_file.read().encode('utf-8')
image.read(blob=svg_blob, resolution = resolution)
png_image = image.make_blob("png32")
with open(png_file, "wb") as out:
out.write(png_image)
I had to install the wand package (using pip) and then ImageMagick for Windows (http://docs.wand-py.org/en/latest/guide/install.html#install-imagemagick-on-windows).

Can you reduce memory consumption by ReportLab when embedding very large images, or is there a Python PDF toolkit that can?

Right now reportlab is making PDFs most of the time. However when one file gets several large images (125 files with a total on disk size of 7MB), we end up running out of memory and crashing trying to build a PDF that should ultimately be smaller than 39MB. The problem stems from:
elif mode not in ('L','RGB','CMYK'):
im = im.convert('RGB')
self.mode = 'RGB'
Where nice b&w (bitonal) images are converted to RGB and when you have images with sizes in the 2595x3000, they consume a lot of memory. (Not sure why they consume 2GB, but that point is moot. When we add them to reportlab our entire python memory footprint is about 50MB, when we call
doc.build(elements, canvasmaker=canvasmaker)
Memory usage skyrockets as we go from bitonal PNGs to RGB and then render them onto the page.
While I try to see if I can figure out how to inject bitonal images into reportlab PDFs, I thought I would see if anyone else had an idea of how to fix this problem either in reportlab or with another tool.
We have a working PDF maker using PODOFO in C++, one of my possible solutions is to write a script/outline for that tool that will simply generate the PDF in a subprocess and then return that via a file or stdout.
Short of redoing PIL you are out of luck. The Images are converted internally in PIL to 24 bit color TIFs. This is not something you can easily change.
We switched to Podofo and generate the PDF outside of python.

Categories