I have a script that processes dozens of image files (using Pillow). Recently, I've noticed that my script fails with TIF (CMYK/16) format. So I've created a test case.
images = [
"cmyk-8.tif",
"cmyk-16.tif",
"rgb-8.tif",
"rgb-16.tif",
]
for img_name in images:
path = img_dir + "\\" + img_name
try:
img = Image.open(path)
except OSError as e:
print(e)
else:
print("success: " + img_name)
This produces the following output:
success: cmyk-8.tif
cannot identify image file '...\\cmyk-16.tif'
success: rgb-8.tif
success: rgb-16.tif
So the problem is definitely with the TIF (CMYK/16) format.
How can I open this specific format, or convert it to a openable(?) format (that is RGB/8, RGB/16, CMYK/8) first, and then open it?
In another QA, GDAL was suggested to solve the problem. I've tried it (install GDAL, associate it with Python, and make it work with the current script), but eventually gave up (too problematic). So I've decided just to focus on gdal_translate.
I've installed "gdal-203-1911-x64-core.msi"
from GISInternals, and tried to do the conversion:
"C:\Program Files\GDAL\gdal_translate.exe" -scale -ot byte -of JPEG "C:\Users\%username%\Documents\GitHub\dump\python\tif-cmyk-16\images\cmyk-16.tif" "cmyk-16.jpg"
but it didn't work. I got incorrect conversion:
I'm not familiar with GDAL, so I must be doing something wrong. How do I get it to do the conversion correct?
Also, this is the cmd output:
ERROR 1: Can't load requested DLL: C:\Program Files\GDAL\gdalplugins\ogr_MSSQLSpatial.dll
126: The specified module could not be found.
ERROR 1: Can't load requested DLL: C:\Program Files\GDAL\gdalplugins\ogr_MSSQLSpatial.dll
126: The specified module could not be found.
Input file size is 200, 200
0...10...20...30...40...50...60...70...80...90...100 - done.
Press any key to continue . . .
It seems something is missing, and I don't know if the inccorect conversion is related to this.
Related scripts and output files can be found here.
Seems like the other images are working, so I will focus on the 16 bit cmyk tif conversion to 8 bit rgb jpeg. I guess this approach will apply for other conversions too with a few tweaks.
Here are a few ways to convert it. The first two uses GDAL since you suggested that, the last approach uses libtiff, which i think is a slightly more appropriate for your use case.
GDAL from command line
From pure command line I got it working with two commands and an intermediate tif.
First convert the 16 bit tif to an 8 bit tif
gdal_translate -scale -ot byte -of GTIFF cmyk-16.tif cmyk-out.tif -co PHOTOMETRIC=CMYK
The file cmyk-out.tif is now in 8 bit. It can now be converted into jpeg with the following command
gdal_translate -of JPEG cmyk-out.tif cmyk-out.jpg
Hence you can just create a batch script chaining the two commands (and maybe deleting the intermediate tif)
GDAL (and numpy and PIL) from python
If the problem seems to be that the image can not be opened by PIL, you could use GDAL for the opening, numpy for the conversion to 8 bit and PIL for the conversion to RGB.
from osgeo import gdal
import numpy as np
from PIL import Image
def reduceDepth(image, display_min, display_max):
image -= display_min
image = np.floor_divide(image, (display_min - display_max + 1) / 256)
image = image.astype(np.uint8)
return image
raster = gdal.Open("cmyk-16.tif")
c = raster.GetRasterBand(1).ReadAsArray()
m = raster.GetRasterBand(2).ReadAsArray()
y = raster.GetRasterBand(3).ReadAsArray()
k = raster.GetRasterBand(4).ReadAsArray()
cmyk = np.dstack((c, m, y, k))
cmyk8 = reduceDepth(cmyk, 0, 65536)
im = Image.fromarray(cmyk8)
im = im.convert('RGB')
im.save("cmyk-out.jpeg")
Using libtiff instead of GDAL
You can also use libtiff to open the tif instead of gdal. Then the above script will look like this
import numpy as np
from PIL import Image
from libtiff import TIFF
input = TIFF.open("cmyk-16.tif").read_image()
def reduceDepth(image, display_min, display_max):
image -= display_min
image = np.floor_divide(image, (display_min - display_max + 1) / 256)
image = image.astype(np.uint8)
return image
v8 = reduceDepth(input, 0, 65536)
im = Image.fromarray(v8)
im = im.convert('RGB')
im.save("cmyk-out.jpeg")
来源:https://stackoverflow.com/questions/50761021/how-to-open-a-tif-cmyk-16-bit-image-file