FFMPEG rotates images - ffmpeg

I am trying to mass-resize images using FFMPEG, and I successfully did it using bash, but I noticed that some of the portrait images got rotated to landscape. Here is the original image, but as you see below, it gets rotated.
As you see above, the image is rotated. At first, I thought this was due to the -vf scale flag that I was using to resize the images, but I tried the following command and it still rotated the image.
ffmpeg -i input.jpg output.jpg
This doesn't happen with every image, and even not all the portrait images. Also, some images rotate clockwise, while some rotate counter-clockwise. And this isn't a random occurrence, all the images that originally rotated still rotate no matter how many times I run the command.
Console Output
ffmpeg version N-79942-gdc34fa6-tessus Copyright (c) 2000-2016 the FFmpeg developers
built with Apple LLVM version 6.0 (clang-600.0.57) (based on LLVM 3.5svn)
configuration: --cc=/usr/bin/clang --prefix=/opt/ffmpeg --as=yasm --extra-version=tessus --enable-avisynth --enable-fontconfig --enable-gpl --enable-libass --enable-libbluray --enable-libfreetype --enable-libgsm --enable-libmodplug --enable-libmp3lame --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopus --enable-libschroedinger --enable-libsnappy --enable-libsoxr --enable-libspeex --enable-libtheora --enable-libvidstab --enable-libvo-amrwbenc --enable-libvorbis --enable-libvpx --enable-libwavpack --enable-libx264 --enable-libx265 --enable-libxavs --enable-libxvid --enable-libzmq --enable-version3 --disable-ffplay --disable-indev=qtkit --disable-indev=x11grab_xcb
libavutil 55. 23.100 / 55. 23.100
libavcodec 57. 38.100 / 57. 38.100
libavformat 57. 35.100 / 57. 35.100
libavdevice 57. 0.101 / 57. 0.101
libavfilter 6. 44.100 / 6. 44.100
libswscale 4. 1.100 / 4. 1.100
libswresample 2. 0.101 / 2. 0.101
libpostproc 54. 0.100 / 54. 0.100
Input #0, image2, from '/Users/jaketr00/Desktop/IMG_1902.JPG':
Duration: 00:00:00.04, start: 0.000000, bitrate: 1025494 kb/s
Stream #0:0: Video: mjpeg, yuvj422p(pc, bt470bg/unknown/unknown), 5184x3456, 25 tbr, 25 tbn
[image2 # 0x7ff751803e00] Using AVStream.codec to pass codec parameters to muxers is deprecated, use AVStream.codecpar instead.
Output #0, image2, to '/Users/jaketr00/Desktop/IMG_19022.JPG':
Metadata:
encoder : Lavf57.35.100
Stream #0:0: Video: mjpeg, yuvj422p(pc), 5184x3456, q=2-31, 200 kb/s, 25 fps, 25 tbn
Metadata:
encoder : Lavc57.38.100 mjpeg
Side data:
cpb: bitrate max/min/avg: 0/0/200000 buffer size: 0 vbv_delay: -1
Stream mapping:
Stream #0:0 -> #0:0 (mjpeg (native) -> mjpeg (native))
Press [q] to stop, [?] for help
frame= 1 fps=0.0 q=8.2 size=N/A time=00:00:00.04 bitrate=N/A speed=0.0753x frame= 1 fps=0.0 q=8.2 Lsize=N/A time=00:00:00.04 bitrate=N/A speed=0.0752x
video:554kB audio:0kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: unknown
Is there any way to stop this from happening?

i ran into the same problem and realised that the image's orientation tag was not preserved when using ffmpeg.
original image
$ exiftool -Orientation input.jpg
Orientation : Rotate 90 CW
full output:
$ identify -verbose input.jpg
Image: input.jpg
Format: JPEG (Joint Photographic Experts Group JFIF format)
Mime type: image/jpeg
Class: DirectClass
Geometry: 4160x3120+0+0
Resolution: 72x72
Print size: 57.7778x43.3333
Units: PixelsPerInch
Colorspace: sRGB
Type: TrueColor
Base type: Undefined
Endianess: Undefined
Depth: 8-bit
Channel depth:
Red: 8-bit
Green: 8-bit
Blue: 8-bit
Channel statistics:
Pixels: 12979200
Red:
min: 0 (0)
max: 255 (1)
mean: 108.185 (0.424255)
standard deviation: 61.0896 (0.239567)
kurtosis: -0.901126
skewness: -0.248333
entropy: 0.945001
Green:
min: 0 (0)
max: 255 (1)
mean: 105.661 (0.414356)
standard deviation: 60.1866 (0.236026)
kurtosis: -0.9917
skewness: -0.0344804
entropy: 0.963995
Blue:
min: 0 (0)
max: 255 (1)
mean: 93.8873 (0.368186)
standard deviation: 63.4227 (0.248716)
kurtosis: -1.00629
skewness: 0.325207
entropy: 0.958324
Image statistics:
Overall:
min: 0 (0)
max: 255 (1)
mean: 102.578 (0.402265)
standard deviation: 61.5663 (0.241436)
kurtosis: -1.03922
skewness: 0.0137682
entropy: 0.955774
Rendering intent: Perceptual
Gamma: 0.454545
Chromaticity:
red primary: (0.64,0.33)
green primary: (0.3,0.6)
blue primary: (0.15,0.06)
white point: (0.3127,0.329)
Matte color: grey74
Background color: white
Border color: srgb(223,223,223)
Transparent color: none
Interlace: None
Intensity: Undefined
Compose: Over
Page geometry: 4160x3120+0+0
Dispose: Undefined
Iterations: 0
Compression: JPEG
Quality: 98
Orientation: RightTop
Properties:
date:create: 2019-05-01T16:09:43+00:00
date:modify: 2019-05-01T16:09:43+00:00
exif:ApertureValue: 200/100
exif:BrightnessValue: 0/100
exif:ColorSpace: 1
exif:ComponentsConfiguration: 1, 2, 3, 0
exif:DateTime: 2019:05:01 10:15:04
exif:DateTimeDigitized: 2019:05:01 10:15:04
exif:DateTimeOriginal: 2019:05:01 10:15:04
exif:ExifOffset: 285
exif:ExifVersion: 48, 50, 50, 48
exif:ExposureBiasValue: 0/6
exif:ExposureMode: 0
exif:ExposureProgram: 0
exif:ExposureTime: 9994945/1000000000
exif:Flash: 0
exif:FlashPixVersion: 48, 49, 48, 48
exif:FNumber: 200/100
exif:FocalLength: 3580/1000
exif:FocalLengthIn35mmFilm: 0
exif:GPSInfo: 831
exif:ImageLength: 3120
exif:ImageWidth: 4160
exif:InteroperabilityOffset: 801
exif:Make: HMD Global
exif:MakerNote: 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 131, 37, 0, 0, 208, 7, 33, 28, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 203, 2, 104, 1, 0, 0, 0, 0
exif:MeteringMode: 0
exif:Model: Nokia 8
exif:Orientation: 6
exif:PhotographicSensitivity: 100
exif:PixelXDimension: 4160
exif:PixelYDimension: 3120
exif:ResolutionUnit: 2
exif:SceneCaptureType: 0
exif:SceneType: 0
exif:SensingMethod: 0
exif:ShutterSpeedValue: 6644/1000
exif:Software: TA-1004_00WW-user 9 PPR1.180610.011 00WW_5_14A release-keys
exif:SubSecTime: 733
exif:SubSecTimeDigitized: 733
exif:SubSecTimeOriginal: 733
exif:thumbnail:Compression: 6
exif:thumbnail:InteroperabilityIndex: R98
exif:thumbnail:InteroperabilityVersion: 48, 49, 48, 48
exif:thumbnail:JPEGInterchangeFormat: 943
exif:thumbnail:JPEGInterchangeFormatLength: 6845
exif:thumbnail:Orientation: 6
exif:thumbnail:ResolutionUnit: 2
exif:thumbnail:XResolution: 72/1
exif:thumbnail:YResolution: 72/1
exif:WhiteBalance: 0
exif:XResolution: 72/1
exif:YCbCrPositioning: 1
exif:YResolution: 72/1
jpeg:colorspace: 2
jpeg:sampling-factor: 2x2,1x1,1x1
signature: d450d8dbb135c549364b3663c8195164a73698999b8104e75c8b74564835986f
Profiles:
Profile-exif: 7794 bytes
Artifacts:
verbose: true
Tainted: False
Filesize: 6.05972MiB
Number pixels: 12979200
Pixels per second: 82.8219MP
User time: 0.150u
Elapsed time: 0:01.156
Version: ImageMagick 7.0.8-42 Q16 x86_64 2019-04-24 https://imagemagick.org
modified image
$ exiftool -Orientation output.jpg
full output:
$ identify -verbose output.jpg
Image: output.jpg
Format: JPEG (Joint Photographic Experts Group JFIF format)
Mime type: image/jpeg
Class: DirectClass
Geometry: 1800x1350+0+0
Units: Undefined
Colorspace: sRGB
Type: TrueColor
Base type: Undefined
Endianess: Undefined
Depth: 8-bit
Channel depth:
Red: 8-bit
Green: 8-bit
Blue: 8-bit
Channel statistics:
Pixels: 2430000
Red:
min: 0 (0)
max: 255 (1)
mean: 108.075 (0.423823)
standard deviation: 60.7286 (0.238152)
kurtosis: -0.889179
skewness: -0.260768
entropy: 0.940096
Green:
min: 0 (0)
max: 255 (1)
mean: 105.629 (0.414232)
standard deviation: 59.6505 (0.233924)
kurtosis: -0.993155
skewness: -0.0409431
entropy: 0.957277
Blue:
min: 0 (0)
max: 255 (1)
mean: 93.7942 (0.367821)
standard deviation: 63.0086 (0.247093)
kurtosis: -1.00904
skewness: 0.322794
entropy: 0.957105
Image statistics:
Overall:
min: 0 (0)
max: 255 (1)
mean: 102.499 (0.401958)
standard deviation: 61.1293 (0.239723)
kurtosis: -1.03828
skewness: 0.00662106
entropy: 0.951493
Rendering intent: Perceptual
Gamma: 0.454545
Chromaticity:
red primary: (0.64,0.33)
green primary: (0.3,0.6)
blue primary: (0.15,0.06)
white point: (0.3127,0.329)
Matte color: grey74
Background color: white
Border color: srgb(223,223,223)
Transparent color: none
Interlace: None
Intensity: Undefined
Compose: Over
Page geometry: 1800x1350+0+0
Dispose: Undefined
Iterations: 0
Compression: JPEG
Quality: 72
Orientation: Undefined
Properties:
comment: Lavc58.35.100
date:create: 2019-05-01T16:09:44+00:00
date:modify: 2019-05-01T16:09:44+00:00
jpeg:colorspace: 2
jpeg:sampling-factor: 2x2,1x1,1x1
signature: 76f0debf16f9a958b603a08a706b825e4700093b28b57470a34361b396da612d
Artifacts:
verbose: true
Tainted: False
Filesize: 105397B
Number pixels: 2430000
Pixels per second: 117.945MP
User time: 0.020u
Elapsed time: 0:01.020
Version: ImageMagick 7.0.8-42 Q16 x86_64 2019-04-24 https://imagemagick.org
solution
to fix this i did included some code in my bash script to read the orientation from the original file ($file). then i update the orientation for the output file ($outfile).
# read orientation from original image
orientation=$(exiftool -Orientation -n -S $file | grep -Eo '[0-9]{1,4}')
# scale image
ffmpeg -i $file -vf "scale='min($ffmpeg_maxwidth,iw)':-1" $outfile
# set orientation value for the new image
exiftool -n -Orientation=$orientation $outfile

What's probably the case here is that your files are all stored in landscape format, but some of them have EXIF tags indicating that they should be displayed rotated. (Many cameras will automatically generate these tags for pictures you take based on the orientation of the camera.) ffmpeg does not recognize these tags, so the images are read exactly as they're stored in the file.
ffmpeg is primarily a video conversion tool, not an image conversion tool, so I don't think it has any way to read EXIF tags. However, the convert tool (part of ImageMagick) does; you can use the -auto-orient flag to activate this feature.

#Jaketr00, I know this might be too late for you finding this answer, but I hope it may help others with the same problem.
All you need to do to avoid this problem is using "transpose" feature.
Lets say you want to draw a Red horizontal line in the middle of your portrait image. the following command will do the job without unwanted rotating. The output will have the same scales as your input file.
ffmpeg -i test.jpg -filter_complex "[0]transpose=1[tr]; color=red:s=300x500,geq=lum='p(X,Y)':a='if(eq(250,Y),255,0)'[c]; [tr][c]overlay=0:0:shortest=1" test_out.jpg`
The same works for any other filter as well. you just need to adapt this command with your filter of choice.

Try to add the options -noautorotate to your ffmpeg commandline.
Besides, use exiftool to backup the exif information, after apply the scale by ffmpeg, resotre the backup exif information.
for f in *.jpg
do
# save exif information
ffmpeg -noautorotate -i input.jpg -vf "scale=w:h" output.jpg
# retore exif information
done

You will have to run for all existing images on your system directory. Because there is no option available with ffmpeg to remove the need of exiftool for keeping orientation.
I didn't want to install and include ImageMagick just for this particular issue. As I was already using ffmpeg for video conversion.
Adding -noautorotate has no effect in the ffmpeg command. So here is a bit more detailed version of #alijandro answer, with nodejs script I've got to preserve meta-data for orientation using example code from here. Also this works great with your sample image.
const ffmpeg = require("ffmpeg");
const exiftool = require("node-exiftool");
const exiftoolBin = require("dist-exiftool");
const sizeOf = require("image-size");
const ep = new exiftool.ExiftoolProcess(exiftoolBin);
let metaData = {};
ep.open()
.then(() => ep.readMetadata('input-img.jpeg', ["-File:all"]))
.then((data) => {
console.log("meta read");
metaData = data;
}, console.error)
.then((data) => {
const d = sizeOf('input-img.jpeg');
const sizeFactor = d.height > d.width ? `-1:${maxH}` : `${maxW}:-1`;
exec(
`ffmpeg -noautorotate -i input-img.jpeg -vf scale="${sizeFactor}" -y output-img.jpeg`,
(err) => {
// handle error
console.log("resized");
ep.open()
.then((data) => {
console.log("meta write");
ep.writeMetadata('output-img.jpeg', metaData.data[0], ["overwrite_original"]);
}, console.error)
.then(() => ep.close())
.catch(console.error);
}
);
}, console.error)
.then(() => ep.close())
.catch(console.error);

I had a similar problem when tried to make thumbnails from photos and got wrong orientation
So i found that ffmpeg transpose works perfectly for me
But i have no idea how it is optimal from point of performance
What i did:
std::string transpose = buildTransposeCommand(exif);
sprintf((char *) commandBuf,
"%s -i \"%s\" -vf \"scale=320:-1:sws_flags=sinc, %s\" \"%s\" -y\n",
FFMPEG_PATH,
in_path_.c_str(),
transpose.c_str(),
out_path_.c_str()
);
std::string Thumbnail::buildTransposeCommand(int & exif) {
std::string transpose;
if (exif == 6) transpose = "transpose=clock";
else if (exif == 8) transpose = "transpose=cclock";
else if (exif == 3) transpose = "transpose=clock,transpose=clock";
else if (exif == 2) transpose = "transpose=clock_flip,transpose=cclock";
else if (exif == 5) transpose = "transpose=cclock_flip";
else if (exif == 7) transpose = "transpose=cclock_flip,transpose=clock,transpose=clock";
else if (exif == 4) transpose = "transpose=clock_flip,transpose=clock";
return transpose;
}
I highly recommend uses that https://github.com/ianare/exif-samples samples for testing it helped me a lot
Take a look at the orientation folder

ffmpeg doesn't seem to be the right tool for the job. Except maybe at the end, if you want to assemble the .jpg images into a video.
If you do use ffmpeg to make a video with your images, you don't need to first resize them. ffmpeg can scale them to the video size you want.
To rotate the images according to their Exif Orientation tag, and do it losslessly, you can for example use exiftran:
exiftran -a -i -b *.jpg
The meaning of the flags used:
-a Automatic (using exif orientation tag).
-i Enable in-place editing of the images.
-b Create a backup file when doing in-place editing
After that, you can use ffmpeg to assemble them into a video. For example:
ffmpeg -framerate 1/3 -pattern_type glob -i '*.jpg' \
-vf "scale=1280:720:force_original_aspect_ratio=decrease,pad=1280:720:(ow-iw)/2:(oh-ih)/2,setsar=1" \
-c:v libx264 -crf 20 -r 25 -pix_fmt yuv420p \
OUTPUT.MP4
If you do need resized jpegs with the correct orientation, you could use ImageMagick's mogrify. For example :
mogrify -path /path/to/new_images \
-auto-orient -resize "1920x1080>" \
-background black -gravity center -extent 1920x1080 *.jpg
The > at the end of the resize dimensions means to only resize larger images, not smaller ones.

Related

Converting a JPG to BMP with exact specs

I'm trying to alter the displayed boot splash of an AMLogic device (using this tool: https://github.com/steeve/aml-imgpack). I have a JPG which I convert to BMP, as the device needs (let's say https://unsplash.com/photos/SnXIF8_2oPw) but the colors are completely wrong, the image is broken in "lines" and some parts from left are to the right (a bit like repeating the image, but not completely).
The original image, have the following attributes:
$ magick identify -verbose ../original/bootup.bmp
Image:
Filename: ../original/bootup.bmp
Format: BMP (Microsoft Windows bitmap image)
Class: DirectClass
Geometry: 1920x1080+0+0
Resolution: 28.34x28.34
Print size: 67.7488x38.1087
Units: PixelsPerCentimeter
Colorspace: sRGB
Type: TrueColor
Base type: Undefined
Endianness: Undefined
Depth: 8-bit
Channel depth:
Red: 8-bit
Green: 8-bit
Blue: 8-bit
Channel statistics:
Pixels: 2073600
Red:
min: 0 (0)
max: 255 (1)
mean: 4.64305 (0.018208)
standard deviation: 31.5717 (0.12381)
kurtosis: 47.4739
skewness: 6.93758
entropy: 0.0513943
Green:
min: 0 (0)
max: 255 (1)
mean: 3.77976 (0.0148226)
standard deviation: 26.4192 (0.103605)
kurtosis: 55.8096
skewness: 7.40689
entropy: 0.0502694
Blue:
min: 0 (0)
max: 239 (0.937255)
mean: 1.81429 (0.00711485)
standard deviation: 13.2764 (0.0520643)
kurtosis: 84.5432
skewness: 8.63456
entropy: 0.0528362
Image statistics:
Overall:
min: 0 (0)
max: 255 (1)
mean: 3.41236 (0.0133818)
standard deviation: 23.7558 (0.0931598)
kurtosis: 67.5353
skewness: 8.07788
entropy: 0.0515
Rendering intent: Perceptual
Chromaticity:
red primary: (0,0)
green primary: (0,0)
blue primary: (0,0)
white point: (0.3127,0.329)
Matte color: grey74
Background color: white
Border color: srgb(223,223,223)
Transparent color: none
Interlace: None
Intensity: Undefined
Compose: Over
Page geometry: 1920x1080+0+0
Dispose: Undefined
Iterations: 0
Compression: Undefined
Orientation: Undefined
Convex hull: 931,391 932,391 1111,432 1223,484 1230,488 1247,544 1247,549 1244,551 1015,623 919,623 704,551 688,471 688,448 696,432 931,391
Minimum bounding box: 1247,391 1247,623 688,623 688,391
Properties:
date:create: 2020-10-31T22:40:38+00:00
date:modify: 2020-10-31T22:40:38+00:00
minimum-bounding-box:_p: 931,391
minimum-bounding-box:_q: 932,391
minimum-bounding-box:_v: 1015,623
minimum-bounding-box:angle: 0
minimum-bounding-box:area: 129688
minimum-bounding-box:height: 559
minimum-bounding-box:unrotate: -0
minimum-bounding-box:width: 232
signature: 31151e021e5d4cdde8d345165d8eb9cd6489f307272c8ca455d038002885d405
Artifacts:
verbose: true
Tainted: False
Filesize: 3.95515MiB
Number pixels: 2073600
Pixels per second: 79.4977MP
User time: 0.020u
Elapsed time: 0:01.026
Version: ImageMagick 7.0.10-30 Q16 x86_64 2020-09-20 https://imagemagick.org
I tried to convert using:
$ mogrify -format bmp ../new_bootup.jpg
$ mogrify -format bmp -type TrueColor ../new_bootup.jpg
$ mogrify -format bmp -define bmp:subtype=RGB565 ../new_bootup.jpg
but the image did not show correctly. The question is: which flags should I use (or which tool should I use) to achieve as close relpication of the original attributes as possible?

animated webp only has key frame?

i want to cover a mp4 to animated webp, so i use ffmpeg command:
mp4 file is http://myvideodata.oss-cn-shenzhen.aliyuncs.com/crs_bcb3f246273d4dbb8ec7f93239fbea6e.mp4
ffmpeg -i ./test.mp4 ./test.webp
it is ok, and animated webp has been created, so i use webpinfo tool (download from https://developers.google.com/speed/webp/download and build example in it, or use this one http://myvideodata.oss-cn-shenzhen.aliyuncs.com/webpInfo)
./webinfo ./test.webp
and get information like this
RIFF HEADER:
File size: 1968244
Chunk VP8X at offset 12, length 18
ICCP: 0
Alpha: 1
EXIF: 0
XMP: 0
Animation: 1
Canvas size 362 x 330
Chunk ANIM at offset 30, length 14
Background color:(ARGB) ff ff ff ff
Loop count : 1
Chunk ANMF at offset 44, length 25116
Offset_X: 0
Offset_Y: 0
Width: 362
Height: 330
Duration: 42
Dispose: 0
Blend: 0
Chunk VP8 at offset 68, length 25092
Width: 362
Height: 330
Alpha: 0
Animation: 0
Format: Lossy (1)
every frame size is about 25k, my question is: all frames in animated webp are key frames?
can any one help
Yes, all frames are marked as key frames by the libwebp_anim encoder.

Convert Color-Indexed Image to Indexes

I have a directory of images in png format, which use a fixed color index for their encoding. I'm interested in producing images whose grayscale values correspond to the index itself, not the color for that index.
For example, suppose the color index has the entry index 3 -> (255, 0, 0) (red). I want to replace every instance of (255, 0, 0) in the RGB image with the grayscale value of 3.
My first thought is to 1) hard code the reversed color index into a lookup table 2) load the image, 3) iterate over pixels, doing a replace based on the look up table.
The problem with this is hard coding the lookup table. I can get it (via imagemagick identify), but that's tedious. Are there any libraries that can do this for me? I'm looking for either 1) cmd line transformations or 2) code libraries that get the color index for a pixel.
If you open a palettised image in PHP using GD, but accidentally forget to tell GD that it is palettised, you will actually get the palette index in the blue pixel. So you could take advantage of that to create a grayscale image by creating a truecolour image the same size as your original and then writing the palette index three times, once each for the Red, Green and Blue channels. It's easier than it sounds, here is the code:
#!/usr/local/bin/php
<?php
// Read in a palettised image
$im = imagecreatefrompng("pal.png");
// Create output image same size
$out = imagecreatetruecolor(imagesx($im), imagesy($im));
for ($x = 0; $x < imagesx($im); $x++) {
for ($y = 0; $y < imagesy($im); $y++) {
$pixel = imagecolorat($im, $x, $y);
$index = $pixel & 0xFF;
$outCol = imagecolorallocate($out,$index,$index,$index);
imagesetpixel($out,$x,$y,$outCol);
// printf("[%d,%d] Palette index:%d\n",$x,$y,$index);
}
}
imagepng($out,"result.png");
?>
So, if I create a 3 pixel palettised image with ImageMagick like this:
convert xc:red xc:lime xc:blue +append pal.png
and check it has palette like this
identify -verbose pal.png | more
Image: pal.png
Format: PNG (Portable Network Graphics)
Mime type: image/png
Class: PseudoClass
Geometry: 3x1+0+0
Units: Undefined
Type: Palette <--- it has a palette
Endianess: Undefined
Colorspace: sRGB
Depth: 8/1-bit
Channel depth:
red: 1-bit
green: 1-bit
blue: 1-bit
Channel statistics:
Pixels: 3
Red:
min: 0 (0)
max: 255 (1)
mean: 85 (0.333333)
standard deviation: 120.208 (0.471405)
kurtosis: -1.5
skewness: 0.707107
entropy: 0.918296
Green:
min: 0 (0)
max: 255 (1)
mean: 85 (0.333333)
standard deviation: 120.208 (0.471405)
kurtosis: -1.5
skewness: 0.707107
entropy: 0.918296
Blue:
min: 0 (0)
max: 255 (1)
mean: 85 (0.333333)
standard deviation: 120.208 (0.471405)
kurtosis: -1.5
skewness: 0.707107
entropy: 0.918296
Image statistics:
Overall:
min: 0 (0)
max: 255 (1)
mean: 85 (0.333333)
standard deviation: 120.208 (0.471405)
kurtosis: -1.5
skewness: 0.707107
entropy: 0.918296
Colors: 3
Histogram:
1: ( 0, 0,255) #0000FF blue
1: ( 0,255, 0) #00FF00 lime
1: (255, 0, 0) #FF0000 red
Colormap entries: 4
Colormap: <--- here is the palette
0: (255, 0, 0) #FF0000 red
1: ( 0,255, 0) #00FF00 lime
2: ( 0, 0,255) #0000FF blue
3: (255,255,255) #FFFFFF white
Then check the result.png after running the PHP script, it now looks like this - i.e. greyscale and the colours match the former indices.
identify -verbose result.png
Image: result.png
Format: PNG (Portable Network Graphics)
Mime type: image/png
Class: DirectClass
Geometry: 3x1+0+0
Units: Undefined
Type: Grayscale <--- it is now greyscale, no palette
Endianess: Undefined
Colorspace: sRGB
Depth: 8-bit
Channel depth:
gray: 8-bit
Channel statistics:
Pixels: 3
Gray:
min: 0 (0)
max: 2 (0.00784314)
mean: 1 (0.00392157)
standard deviation: 0.816497 (0.00320195)
kurtosis: -1.5
skewness: 0
entropy: 1
Colors: 3
Histogram:
1: ( 0, 0, 0) #000000 gray(0)
1: ( 1, 1, 1) #010101 gray(1)
1: ( 2, 2, 2) #020202 gray(2)
Note that if your original image had very few colour palette entries, the output image will be dark so you will want to contrast-stretch or normalize it...

Why are my JPEG files larger than expected?

gm convert +profile "*" -resize 800x800 -quality 90.0 -background white -flatten test.jpg test01.jpg
the test01.jpg file size is 140262, but the test.jpg file size is 114698, I think the test01.jpg file is less than test.jpg, why?
gm identify -verbose test.jpg command info:
Image: test.jpg
Format: JPEG (Joint Photographic Experts Group JFIF format)
Geometry: 960x1280
Class: DirectClass
Type: true color
Depth: 8 bits-per-pixel component
Channel Depths:
Red: 8 bits
Green: 8 bits
Blue: 8 bits
Channel Statistics:
Red:
Minimum: 0.00 (0.0000)
Maximum: 255.00 (1.0000)
Mean: 158.69 (0.6223)
Standard Deviation: 74.34 (0.2915)
Green:
Minimum: 0.00 (0.0000)
Maximum: 255.00 (1.0000)
Mean: 142.36 (0.5583)
Standard Deviation: 72.48 (0.2842)
Blue:
Minimum: 0.00 (0.0000)
Maximum: 255.00 (1.0000)
Mean: 105.80 (0.4149)
Standard Deviation: 73.05 (0.2865)
Resolution: 72x72 pixels
Filesize: 112.0Ki
Interlace: No
Orientation: TopLeft
Background Color: white
Border Color: #DFDFDF
Matte Color: #BDBDBD
Page geometry: 960x1280+0+0
Compose: Over
Dispose: Undefined
Iterations: 0
Compression: JPEG
JPEG-Quality: 64
JPEG-Colorspace: 2
JPEG-Colorspace-Name: RGB
JPEG-Sampling-factors: 2x2,1x1,1x1
Signature: ea09bde85095c8c8b2345e5301d581a8002490ecfefa63ae81c0cb14b8c2fbf8
Profile-iptc: 40 bytes
Profile-EXIF: 86 bytes
Orientation: 1
Exif Offset: 38
Color Space: 1
Exif Image Width: 960
Exif Image Length: 1280
Tainted: False
User Time: 0.020u
Elapsed Time: 0:01
Pixels Per Second: 39.1Mi
According to the "identify" output that you presented for the input image "test.jpg", the JPEG quality was estimated to be 64. You requested quality 90 for your output image.
Higher quality means bigger filesize. The increase in quality from 64 to 90 doesn't actually improve the visual quality of the image; it only forces the compressor to faithfully reproduce the compression artifacts in the input image.

How to determine if an image has a transparent pixel

I just found a piece of code that was used to determine if an image has transparent pixels:
my $alpha = $gd->transparent;
if ($alpha < 0) {
die("The image you uploaded has no transparent pixels. (alpha = $alpha)");
}
Obviously, this does not work. I tried it with the image user-desktop.png of the open icon library which has transparent pixels. The check returned -1.
I can only guess why this command was used. GD's manpage says:
If you call this method [transparent] without any parameters, it will return the current index of the transparent color, or -1 if none.
So, as a side question: the transparent pixels can have no color index at all - right?
Then I found the thread Perl GD check if pixel is transparent. But for this solution, I have to iterate over all pixels of an image (at least in the wort case, when the only transparent pixel would be the last one).
Isn't there an easy way of checking for this information? Maybe a method like $image_object->has_transparent_pixels ?
NB: I'm not bound to GD, so other Image modules might work as well (however, I'm on Windows - it should work there).
Updated Answer
As pointed out by #ikegami (thank you), GIFs have a designated transparent "colour" pixel in their palette rather than a alpha/transparency layer in which each pixel has its own transparency value, normally between 0-255.
I have generated a 2x2 pixel GIF with one transparent pixel, one red, one green and one blue - then ran ImageMagick's identify command against it and got the following. I have marked the transparent pixel parts with an arrow.
Image: a.gif
Format: GIF (CompuServe graphics interchange format)
Mime type: image/gif
Class: PseudoClass
Geometry: 4x4+0+0
Units: Undefined
Type: PaletteAlpha
Endianess: Undefined
Colorspace: sRGB
Depth: 8/1-bit
Channel depth:
red: 1-bit
green: 1-bit
blue: 1-bit
alpha: 1-bit
Channel statistics:
Pixels: 16
Red:
min: 0 (0)
max: 255 (1)
mean: 127.5 (0.5)
standard deviation: 127.5 (0.5)
kurtosis: -2
skewness: 0
Green:
min: 0 (0)
max: 255 (1)
mean: 127.5 (0.5)
standard deviation: 127.5 (0.5)
kurtosis: -2
skewness: 0
Blue:
min: 0 (0)
max: 255 (1)
mean: 127.5 (0.5)
standard deviation: 127.5 (0.5)
kurtosis: -2
skewness: 0
Alpha:
min: 0 (0)
max: 255 (1)
mean: 191.25 (0.75)
standard deviation: 110.418 (0.433013)
kurtosis: -0.666667
skewness: 1.1547
Image statistics:
Overall:
min: 0 (0)
max: 255 (1)
mean: 111.562 (0.4375)
standard deviation: 123.451 (0.484123)
kurtosis: -1.8275
skewness: 0.271109
Alpha: srgba(255,255,255,0) #FFFFFF00
Colors: 4
Histogram:
4: ( 0, 0,255,255) #0000FF blue
4: ( 0,255, 0,255) #00FF00 lime
4: (255, 0, 0,255) #FF0000 red
4: (255,255,255, 0) #FFFFFF00 srgba(255,255,255,0)
Colormap entries: 4
Colormap:
0: (255, 0, 0,255) #FF0000 red
1: ( 0,255, 0,255) #00FF00 lime
2: ( 0, 0,255,255) #0000FF blue
3: (255,255,255, 0) #FFFFFF00 srgba(255,255,255,0) <---------
Rendering intent: Perceptual
Gamma: 0.454545
Chromaticity:
red primary: (0.64,0.33)
green primary: (0.3,0.6)
blue primary: (0.15,0.06)
white point: (0.3127,0.329)
Background color: srgba(255,255,255,0)
Border color: srgba(223,223,223,1)
Matte color: grey74
Transparent color: srgba(255,255,255,0) <---------------
Interlace: None
Intensity: Undefined
Compose: Over
Page geometry: 4x4+0+0
Dispose: Undefined
Compression: LZW
Orientation: Undefined
Properties:
date:create: 2014-10-11T10:40:09+01:00
date:modify: 2014-10-11T10:40:08+01:00
signature: 1c82b4c2e772fb075994516cc5661e9dec35b8142f89c651253d07fc3c4642bb
Profiles:
Profile-gif:xmp dataxmp: 1031 bytes
Artifacts:
filename: a.gif
verbose: true
Tainted: False
Filesize: 1.11KB
Number pixels: 16
Pixels per second: 16PB
User time: 0.000u
Elapsed time: 0:01.000
Version: ImageMagick 6.8.9-7 Q16 x86_64 2014-09-10 http://www.imagemagick.org
So, IM does know about the GIF transparent pixel - I will dig some more and see if it can be found sensibly in Perl - for now though, you could just run the following in Perl's backticks.
my $output = `identify -verbose a.gif | grep -i transparent`; # or maybe with FINDSTR on Windows
As an alternatvie, and less problematic across platforms, the %A escape tells you if an image has transparency enabled:
convert a.gif -print "%A" null:
True
convert a.jpg -print "%A" null:
False
Or, in a more Perl-y way:
#!/usr/bin/perl
use warnings;
use strict;
use Image::Magick;
my $image = Image::Magick->new();
$image->Read($ARGV[0]);
my $a = $image->Get('%A');
print $a;
perl ./script.pl a.gif
True
perl ./script.pl a.jpg
False
Original Answer
I think you may be a little confused about transparency. Images either have transparency, which is an entire layer, or they do not. In general, it is not a question of a single pixel being transparent or not. From the outset, JPEGs do not support transparency, GIF and PNG can support transparency but they are not necessarily always transparent.
So, assuming you have a PNG or a GIF, it could have a transparency layer. If it has, each pixel could either be totally transparent, totally opaque or somewhere in between. If you use ImageMagick, it is available at the command line or with PHP, Perl and other bindings.
From the command line, you can tell if an image has a transparency layer using this command:
convert InputImage.png -format "%[opaque]" info:
and it will either return true or false.
In Perl you can do this:
#!/usr/bin/perl
use warnings;
use strict;
use Image::Magick;
my $image = Image::Magick->new();
$image->Read($ARGV[0]);
my $a = $image->Get('%[opaque]');
print $a;
then run as:
perl ./script.pl ImageName.png

Resources