How to determine an image's encoding - image

I have an image with a PNG extension.
I suspect it's not really a PNG though (I think it might be a GIF).
How can I confirm an image's encoding?
NB: A solution for Windows would be preferable

on Linux, you can use file command
$ file branches.gif
branches.gif: PNG image data, 1257 x 782, 8-bit/color RGBA, non-interlaced
or ImageMagick part called identify
identify branches.gif
branches.gif PNG 1257x782 1257x782+0+0 8-bit sRGB 114KB 0.000u 0:00.000

You need to do a quick check of the file's internals.
The first 8 bytes of a PNG image are always
137 80 78 71 13 10 26 10
It is vanishingly unlikely that a non-malicious non-PNG has the same 8 bytes.

For windows open the file in a text editor, e.g. Sublime, and the first part should be the png magic number 89 50 4e 47 0d 0a 1a 0a.

One can use https://exiftool.org/ (gratis, portable, works on Microsoft Windows, macOS and Linux).
Demo, running the command exiftool.exe test.png in cmd:
Microsoft Windows [Version 10.0.19042.1706]
(c) Microsoft Corporation. All rights reserved.
C:\PortableProgs\exiftool-12.44>"exiftool(-k).exe" test.png
ExifTool Version Number : 12.44
File Name : test.png
Directory : .
File Size : 1837 kB
Zone Identifier : Exists
File Modification Date/Time : 2022:08:07 17:15:39-07:00
File Access Date/Time : 2022:08:07 18:55:55-07:00
File Creation Date/Time : 2022:08:07 18:55:55-07:00
File Permissions : -rw-rw-rw-
File Type : PNG
File Type Extension : png
MIME Type : image/png
Image Width : 2123
Image Height : 1134
Bit Depth : 8
Color Type : RGB with Alpha
Compression : Deflate/Inflate
Filter : Adaptive
Interlace : Noninterlaced
SRGB Rendering : Perceptual
Gamma : 2.2
Pixels Per Unit X : 9448
Pixels Per Unit Y : 9448
Pixel Units : meters
Exif Byte Order : Big-endian (Motorola, MM)
Orientation : Horizontal (normal)
Date/Time Original : 2022:08:07 14:24:32
User Comment : Screenshot
Color Space : sRGB
Exif Image Width : 2160
Exif Image Height : 1620
XMP Toolkit : XMP Core 6.0.0
Date Created : 2022:08:07 14:24:32
Image Size : 2123x1134
Megapixels : 2.4
-- press ENTER --

Related

Exiftool from remote sources

I'm trying to get image metadata from the internet using exiftool and tried to follow along with the piping example provided in exiftools docs, which I've linked below. This does not work as expected and instead returns an error of no file specified. I've tried putting the URL into quotes, changing around the command to use curl as an input into exiftool instead of piping, nothing seems to work. Any help would be appreciated.
https://exiftool.org/exiftool_pod.html#PIPING-EXAMPLES
Works just fine for me. Make sure to add the - to indicate reading from stdin. Here is an example:
> curl -s "https://www.gravatar.com/avatar/1f20f72dba83a169c623fbe652657a32?s=48&d=identicon&r=PG" | exiftool -
ExifTool Version Number : 11.88
File Type : PNG
File Type Extension : png
MIME Type : image/png
Image Width : 48
Image Height : 48
Bit Depth : 8
Color Type : RGB with Alpha
Compression : Deflate/Inflate
Filter : Adaptive
Interlace : Noninterlaced
Pixels Per Unit X : 3780
Pixels Per Unit Y : 3780
Pixel Units : meters
Image Size : 48x48
Megapixels : 0.002

ImageMagick "Channel distortion: Undefined" message

I installed imagemagick for Windows from official site. I am trying to generate a diff image from two PNG images using ImageMagick. I am using following command:
compare file2.png file1.png -compose Src "diff.png"
But command exits with EXIT code "1". When run with -verbose flag, below message gets printed.
Image:file2.png Channel distortion: Undefined
I searched google for possible reason, but haven't found any answer. There is official ImageMagick documentation on distortion, but that is too wide and technical (and I am a novice).
Any idea why this message is thrown by imagemagick utility?
There is no real error. That message comes up when you do not specify -metric XXX with compare and take the default. The exit code 1 is what ImageMagick produces on success, I believe. See if you have an output file called diff.png. If you add -metric rmse, for example, you should not get that message. If I run the following without -metric XXX, I get:
compare -verbose lena.png lena.jpg -compose src diff.png
lena.png PNG 256x256 256x256+0+0 8-bit sRGB 118327B 0.010u 0:00.004
lena.jpg JPEG 256x256 256x256+0+0 8-bit sRGB 31640B 0.000u 0:00.002
Image: lena.png
Channel distortion: Undefined
lena.png=>diff.png PNG 256x256 256x256+0+0 8-bit sRGB 3c 1322B 0.130u 0:00.039
So it works fine. The message is telling you that it does not know which metric to use to give you difference statistics. I am not sure what it uses to generate the output. The term distortion may be a poor choice and perhaps should have been difference statistics.
If I add -metric rmse, then I get:
compare -verbose -metric rmse lena.png lena.jpg -compose src diff.png
lena.png PNG 256x256 256x256+0+0 8-bit sRGB 118327B 0.010u 0:00.004
lena.jpg JPEG 256x256 256x256+0+0 8-bit sRGB 31640B 0.000u 0:00.001
Image: lena.png
Channel distortion: RMSE
red: 810.821 (0.0123723)
green: 658.701 (0.0100511)
blue: 945.653 (0.0144297)
all: 813.547 (0.0124139)
Similar or same resulting image, but now the compare scores are reported since a specific metric is specified.
See the section about comparison statistics here

How to read jpeg image with Adobe RGB colorspace in OpenCV?

I am trying to read and write jpegs wth Adobe RGB colorspace in OpenCV. OpenCV assumes the jpeg has sRGB colorspace and when displaying or writing to file, the image loses some of its color intensity. I found this intensity loss was due to colorspace difference by answers given to my previous question.
Is there anyway I can make OpenCV to read Adobe RGB colorspace without casting it to sRGB?
Some information that is hopefully useful for anyone looking for a work-around for dealing with ICC and other profiles...
You can see what profiles are present in an image using ImageMagick which is installed on most Linux distros and is available for macOS and Windows. In the Terminal, or Command Prompt on Windows, run:
magick identify -verbose frog.jpg | grep 'Profile-.*bytes'
Profile-icc: 578 bytes
That tells you this image has a 578 byte ICC profile embedded.
If you are on Windows and don't have grep, you can equally use the following, though you may need to double up the percent sign, or prefix it with a caret (^) or somehow escape it:
magick identify -format "%[profiles]" frog.jpg
icc
You can extract that profile from the image, using this command:
magick frog.jpg frog.icc
And, you'll get a 578 byte ICC profile:
ls -l *icc
-rw-r--r-- 1 mark staff 578 24 Apr 10:36 frog.icc
You can check that the profile looks correct using the file command:
file *icc
frog.icc: ColorSync color profile 2.1, type ADBE, RGB/XYZ-mntr device by ADBE, 560 bytes, 11-8-2000 19:51:59 "Adobe RGB (1998)"
You can apply that profile to some other file like this:
magick other.jpg -profile "icc:frog.icc" otherWithProfile.jpg
Once you have extracted the profile using the above method, you can apply it to an image that you plan to use with OpenCV using PIL/Pillow's ImageCMS Module.
For that, I think you need to use these steps or something very similar, though I have not tested it:
from PIL import Image, ImageCMS
import numpy as np
# Open frog with PIL/Pillow
im = Image.open('frog.jpg')
iccp = PIL.ImageCms.getOpenProfile("profile.icc")
rgbp = ImageCms.createProfile("sRGB")
icc2rgb = ImageCms.buildTransformFromOpenProfiles(rgbp, iccp, "RGB", "RGB")
result = ImageCms.applyTransform(im, icc2rgb)
You should then be able to convert the resulting image to a Numpy array that OpenCV can work with using:
OpenCVim = np.array(result)
and remember to then convert from RGB ordering to BGR with cv2.cvtColor().
Rather than detect and extract the ICC profile with ImageMagick, you could equally use PIL/Pillow like this:
from PIL import Image
im = Image.open('frog.jpg')
# Now look at "im.info"
{'jfif': 257,
'jfif_version': (1, 1),
'dpi': (72, 72),
'jfif_unit': 1,
'jfif_density': (72, 72),
'icc_profile': b'\x00\x00\x020ADBE\x02\x10\x00\x00mntrRGB XYZ \x07\xd0\x00\x08\x00\x0b\x00\x13\x003\x00;acspAPPL\x00\x00\x00\x00none\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf6\xd6\x00\x01\x00\x00\x00\x00\xd3-ADBE\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\ncprt\x00\x00\x00\xfc\x00\x00\x002desc\x00\x00\x010\x00\x00\x00kwtpt\x00\x00\x01\x9c\x00\x00\x00\x14bkpt\x00\x00\x01\xb0\x00\x00\x00\x14rTRC\x00\x00\x01\xc4\x00\x00\x00\x0egTRC\x00\x00\x01\xd4\x00\x00\x00\x0ebTRC\x00\x00\x01\xe4\x00\x00\x00\x0erXYZ\x00\x00\x01\xf4\x00\x00\x00\x14gXYZ\x00\x00\x02\x08\x00\x00\x00\x14bXYZ\x00\x00\x02\x1c\x00\x00\x00\x14text\x00\x00\x00\x00Copyright 2000 Adobe Systems Incorporated\x00\x00\x00desc\x00\x00\x00\x00\x00\x00\x00\x11Adobe RGB (1998)\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00XYZ \x00\x00\x00\x00\x00\x00\xf3Q\x00\x01\x00\x00\x00\x01\x16\xccXYZ \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00curv\x00\x00\x00\x00\x00\x00\x00\x01\x023\x00\x00curv\x00\x00\x00\x00\x00\x00\x00\x01\x023\x00\x00curv\x00\x00\x00\x00\x00\x00\x00\x01\x023\x00\x00XYZ \x00\x00\x00\x00\x00\x00\x9c\x18\x00\x00O\xa5\x00\x00\x04\xfcXYZ \x00\x00\x00\x00\x00\x004\x8d\x00\x00\xa0,\x00\x00\x0f\x95XYZ \x00\x00\x00\x00\x00\x00&1\x00\x00\x10/\x00\x00\xbe\x9c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'}
Here's the frog.jpg image:
Keywords: Python, ImageMagick, image, image processing, profile, ICC profile, extract, insert, apply, transform, PIL, Pillow, OpenCV, CMS, pyCMS.

PDF: extracted images are sliced / tiled

Image extraction with pdfimages and mupdf/mutool works fine so far.
Images in PDFs produced with FreePDF are always sliced, so one image results in multiple image files.
Is there a trick to avoid this? How can I use the results of pdfshow?
Are there coordinates to know the position and height and width to
cut/crop the image after converting the PDF to a PNG or JPEG?
The most likely reason why your images are "sliced" after extracting them is this: they were "sliced" already before extracting them -- as their way of living within the PDF file itself.
Don't ask me why some PDF generating software does this.
MS Powerpoint is infamous for this -- background images showing some gradient often get sliced up into tens of thousands of 1x1, 1x2 or 1x8 pixels and similarly-sized mini images inside the PDF.
Update
1. Identify the scope of the problem
The image fragments of the sample PDF can be identified with the pdfimages -list command (this requires a recent version of pdfimages based on the Poppler fork, not the xpdf one!):
pdfimages -list so-28023312-test1.pdf
page num type width height color comp bpc enc interp objectID x-ppi y-ppi size ratio
------------------------------------------------------------------------------------------
1 0 image 271 271 rgb 3 8 jpeg no 18 0 163 163 26.7K 12%
1 1 image 271 271 rgb 3 8 jpeg no 19 0 163 163 21.7K 10%
1 2 image 271 271 rgb 3 8 jpeg no 30 0 163 163 22.9K 11%
1 3 image 271 271 rgb 3 8 jpeg no 31 0 163 163 21.8K 10%
1 4 image 132 271 rgb 3 8 jpeg no 32 0 162 163 9895B 9.2%
1 5 image 271 271 rgb 3 8 jpeg no 33 0 163 163 22.5K 10%
1 6 image 271 271 rgb 3 8 jpeg no 34 0 163 163 16.5K 7.7%
1 7 image 271 271 rgb 3 8 jpeg no 35 0 163 163 16.9K 7.9%
1 8 image 271 271 rgb 3 8 jpeg no 36 0 163 163 20.3K 9.4%
1 9 image 132 271 rgb 3 8 jpeg no 37 0 162 163 14.5K 14%
1 10 image 271 271 rgb 3 8 jpeg no 20 0 163 163 17.1K 8.0%
1 11 image 271 271 rgb 3 8 image no 21 0 163 163 107K 50%
1 12 image 271 271 rgb 3 8 image no 22 0 163 163 96.7K 45%
1 13 image 271 271 rgb 3 8 image no 23 0 163 163 119K 56%
1 14 image 132 271 rgb 3 8 jpeg no 24 0 162 163 10.7K 10%
1 15 image 271 99 rgb 3 8 jpeg no 25 0 163 161 7789B 9.7%
1 16 image 271 99 rgb 3 8 jpeg no 26 0 163 161 6456B 8.0%
1 17 image 271 99 rgb 3 8 jpeg no 27 0 163 161 7202B 8.9%
1 18 image 271 99 rgb 3 8 jpeg no 28 0 163 161 8241B 10%
1 19 image 132 99 rgb 3 8 jpeg no 29 0 162 161 5905B 15%
Because there are only 20 different fragments on 1 page, it is easy to...
...first extract them all and convert them to JPEGs, and
...then stitch them together again.
2. Extract the fragments as JPEGs
The following command will extract the fragments and try to save them as JPEGs (-j) 28023312:
pdfimages so-28023312-test1.pdf 28023312
There are 3 images which came out as PPM. Use ImageMagick's convert to make JPEGs from them (not strictly required, but it simplifies the 'stitching' command line:
for i in 11 12 13; do
convert 28023312-0${i}.ppm 28023312-0${i}.jpg
done
Here are the first three fragments, 280233312-000.jpg, 280233312-001.jpg and 280233312-002.jpg:
3. Stitch the 20 fragments together again
ImageMagick can stitch the 20 images together again. When looking at the PDF page as well as at the 20 JPEGs it is easy to determine the order they need to be put together:
convert \
\( 28023312-0{00,01,02,03,04}.jpg +append \) \
\( 28023312-0{05,06,07,08,09}.jpg +append \) \
\( 28023312-0{10,11,12,13,14}.jpg +append \) \
\( 28023312-0{15,16,17,18,19}.jpg +append \) \
-append \
complete.jpg
Dissecting the command:
The +append image operator appends all listed images in a horizontal order.
The \( ... \) lines indicate an 'aside' processing of the resprective part of the image stack (which needs to be separated by the escaped parentheses). The result of this horizontal appending operation will then replace the individual fragments inside the current image stack.
The final -append image operator appends the current images vertically.
Here is the resulting JPEG, fully stitched together again:
Could this be automated?
In theory we could automate this process. For this we would have to analyse the PDF source code. However, that is rather difficult, because the content stream may be compressed.
In order to uncompress all or most of the content streams and to get a nicer representation of the PDF file structure, we could use mutool clean -d, podofouncompress or qpdf --qdf.
I prefer qpdf, the 'structural, content-preserving PDF file transformer'. Here is the command:
qpdf --qdf --object-streams=disable so-28023312-test1.pdf qdf.pdf
The resulting PDF file, qdf.pdf is more easy to analyse, because most (but not all) previously binary sections are now in ASCII. When you search for the occurrences of Do inside this file, you will see where images are inserted (however, I cannot give you a complete PDF analysing tutorial here, sorry...).
The following command prints all lines where Do occurs, plus the preceding line (-B 1):
grep -a -B 1 " Do" qdf.pdf
1002 0 0 1002 236 5776.67 cm
/Im0 Do
--
1001 0 0 1002 1237 5776.67 cm
/Im1 Do
--
120.12 0 0 120.24 268.44 693.2004 cm
/Im2 Do
--
[...skipping 15 other output segments...]
--
1002 0 0 369 3237 3406.67 cm
/Im18 Do
--
490 0 0 369 4238 3406.67 cm
/Im19 Do
--
1 0 0 1 204.9037018 508.5130005 cm
/Fm0 Do
All the /ImNN Do lines insert images (the /Fm0 Do line refers to a form object not an image).
The preceding lines, for example 490 0 0 369 4238 3406.67 cm set up the current transformation matrix. From this line alone, one can sometimes conclude the position of the image and its size. In the case of this file, it is not enough -- the contents of more preceding lines would be required in order to determine the current 'drawing position'.
FreePDF uses Ghostscript and creates a 'virtual printer'. When you 'print to PDF' what actually happens is that your application prints to the Windows print pipeline, which sends the graphics primitives to the Windows PostScript printer driver, which sends the PostScript to the Port Monitor. The FreePDF Port Monitor stores this PostScript program on disk. When the output is complete, it starts up Ghostscript which interprets the PostScript and produces a PDF file.
Now, unless you are using a spectacularly old version of Ghostscript (which is possible, you should check!) this will take whatever was in the input and put it in the output. It won't slice up images.
Which means that, as Kurt and David said above, that the real reason for the problem is that the PostScript program has sliced up images in it, before Ghostscript ever saw it.
Now I know that's not generally the case, but it depends heavily on what PostScript printer driver you have installed, how its configured, what version of Windows you are using and what the application driving the printer is.
As David rightly says, Microsoft Office applications have a bad habit of drawing certain kinds of patterns this way (to get a 'translucent effect' they use a pattern where the cell is an imagemask, the 'white' pixels are transparent).
Also if you have large photographs (for example) and the PostScript printer is configured with minimal memory, the driver might split up the image in order not to exhaust the printer's memory. Obviously that's a configuration problem because on a desktop PC you would have to be using monster images to overwhelm Ghostscript.
So basically, we need a lot more information from you before we can answer this fully, but the principle is that the damage was done before it got to FreePDF. The version of Ghostscript used to create the PDF file will be in the PDF file metadata, unless FreePDF chose to erase/overwrite it.
Finally, as Kurt pointed out, you should post a link to the PDF file, and ideally the application file and intermediate PostScript file which was used to produce the PDF.

Determine bit depth of bmp file on os x

How can I determine the bit depth of a bmp file on Mac OS X? In particular, I want to check if a bmp file is a true 24 bit file, or if it is being saved as a greyscale (i.e. 8 bit) image. I have a black-and-white image which I think I have forced to be 24 bit (using convert -type TrueColor), but Imagemagick gives conflicting results:
> identify -verbose hiBW24.bmp
...
Type: Grayscale
Base type: Grayscale
Endianess: Undefined
Colorspace: Gray
> identify -debug coder hiBW24.bmp
...
Bits per pixel: 24
A number of other command-line utilities are no help, it seems:
> file hi.bmp
hi.bmp: data
> exiv2 hiBW24.bmp
File name : hiBW24.bmp
File size : 286338 Bytes
MIME type : image/x-ms-bmp
Image size : 200 x 477
hiBW24.bmp: No Exif data found in the file
> mediainfo -f hi.bmp
...[nothing useful]
If you want a commend-line utility try sips (do not forget to read the manpage with man sips). Example:
*terminal input*
sips -g all /Users/hg/Pictures/2012/03/14/QRCodeA.bmp
*output is:*
/Users/hg/Pictures/2012/03/14/QRCodeA.bmp
pixelWidth: 150
pixelHeight: 143
typeIdentifier: com.microsoft.bmp
format: bmp
formatOptions: default
dpiWidth: 96.000
dpiHeight: 96.000
samplesPerPixel: 3
bitsPerSample: 8
hasAlpha: no
space: RGB
I think the result contains the values you are after.
Another way is to open the image with the previewer preview.app and the open the info panel.
One of the most informative programs (but not easy to use) is exiftool by Phil Harvey http://www.sno.phy.queensu.ca/~phil/exiftool/ , which also works very well on MacOSX for a lot of file formats but maybe an overkill for your purpose.
I did this to investigate:
# create a black-to-white gradient and save as a BMP, then `identify` it to a file `unlim`
convert -size 256x256 gradient:black-white a.bmp
identify -verbose a.bmp > unlim
# create another black-to-white gradient but force 256 colours, then `identify` to a second file `256`
convert -size 256x256 gradient:black-white -colors 256 a.bmp
identify -verbose a.bmp > 256
# Now look at difference
opendiff unlim 256
And the difference is that the -colors 256 image has a palette in the header and has a Class:PseudoClass whereas the other has Class:Direct

Resources