PHP/Imagick/PDFlib Flop Image Changes its Bit Depth - php

I am Having PNG Image And Trying To Flop (Mirror) by imagick function of php It Gets Flop Exactly But The
Base Image is In Format 24 Bit RGB
and after Convertion It Gets To
8 Bit Pallated
. So the Main Problem is that when I use to place both images in my pdflib pages one of the image(converted) displays curly....
Original Image
Output After Flop(Mirror) by Imagick and Rendered in PDFlib ->
My Code Is Simple ---->
$im = new Imagick($background_image);
$im->flopImage();
$im->writeimage($background_image."_flop.png");
Modified Date => 29 Oct 2013
Original Image -> Size 4.68 KB Bit Depth 32
Flopped Image -> Size 7.99 KB Bit Depth 64
Automatically Changes It's Properties
ORIGINAL
Converted

Imagick is using the smallest format possible to save the image. Saving in these formats all produce the same image but have the sizes:
Palette - 3.38kB
RGBA 32bit - 6.14kB
RGBA 64bit - 8.09kB
Saving to the smallest possible file is usually what people desire. However you can disable this in a couple of ways.
You can tell Imagick to use the same PNG format as the source image by setting the png:format option to png00. e.g.
$imagick = new Imagick(realpath("../images/FlopOriginal.png"));
$imagick->flopImage();
$imagick->setOption('png:format', 'png00');
$imagick->writeImage("../images/Flop.png");
The full options for png:format are png8, png24, png32, png48, png64, and png00.
Alternatively you can explicitly set the image format to use when saving the PNG file, through the png:bit-depth and png:color-type e.g.
$imagick = new Imagick(realpath("../images/FlopOriginal.png"));
$imagick->flopImage();
$imagick->setOption('png:bit-depth', '8');
$imagick->setOption('png:color-type', 6);
$imagick->writeImage("../images/Flop.png");
The color type values come from the libpng.h and are:
PNG_COLOR_TYPE_GRAY 0
PNG_COLOR_TYPE_RGB 2
PNG_COLOR_TYPE_PALETTE 3
PNG_COLOR_TYPE_GRAY_ALPHA 4
PNG_COLOR_TYPE_RGB_ALPHA 6
Both those methods produce a flopped image that is RGBA 32bit like the original image.

Related

My php image server using Imagick produces much larger png8 files after cropping / scaling down

I'm trying to set up a simple PHP image server to allow me to add just large file for each of my images and then scale and crop them as needed. For my test file I start with a png8 exported via "save for web" from illustrator of size 2400 x 1200, which has a filesize of 21.6KB.
When I use Imagick's cropThumbnailImage function to reduce it to 600 x 600 the resulting file is 62.1KB (three times the size for a substantially smaller image). A 600 x 600 crop of the same image saved from illustrator clocks in at about 8.2KB. I can accept a modest file size increase for the added convenience, but an ~8x increase is just too much.
When saving the file I make sure to force the output to png8 so it doesn't default to a lossless png format, but other than that I'm clueless as to how to resolve it.
Here is my processing code:
//create working image
$image = new Imagick( $this->orig_file );
// Set Compression
$image->setImageCompressionQuality( 9 );
//scale image to height
$image->cropThumbnailImage ( $this->w, $this->h );
// strip extra data
$image->stripImage();
// save file
$image->writeImage( 'png8:'.$this->output_file );
Here are my test files:
Original Full scale image outputted by illustrator.
Cropped 600 x 600 image generated by imagick.
[EDIT: As per Mark's suggestion below I added the following changes]
// replacing cropThumbnailImage with:
$image->resizeImage(0, $this->h, imagick::FILTER_TRIANGLE, 1);
// crop
$start = ($image->getImageWidth() / 2) - ($this->w / 2);
$image->cropimage($this->w, $this->h, $start, 0);
// reduce colors to 20
$image->quantizeImage($this->q, 1, 0, true, false); // using 20 as $this->q
The end result goes from 62.1KB to 50.4KB, better but still over double the size of the fullsized image, and many times larger that the illustrator save for web version at that size.
600x600 image reduced to 20 colors and resized not thumbnailed
Your original image has 33 colours and weighs in at 22kB.
If you resize like this (albeit at the command line):
convert jabba.png -resize 600x600 -strip png8:result.png
the output file will be 6.6kB.
If you resize like I suggested with -scale:
convert jabba.png -scale 600x600 -strip png8:result.png
the output file will be 5.0kB.
If you retain -quality 9 in there, you will end up with > 25kB.

How do I stop Image Magick stripImage() from removing resolution data

I'm uploading images to my website and optimising them by removing EXIF data using Image Magick's stripImage() function.
$img = new Imagick($image);
$img->stripImage();
$img->writeImage($image);
$img->destroy();
It works quite well, I get reduced file sizes as expected. However, if I open the image in Photoshop, photoshop reads the image as having a resolution of 1 Pixel per Inch.
It seems that stripImage is removing the EXIF data that photoshop uses to determine resolution.
How do I prevent this behaviour while stripping everything else?
The short answer is that I don't think you can selectively remove parts of the EXIF data with ImageMagick, so you will probably need to extract the original density, clear the EXIF, then put back whatever Photoshop needs... not sure though, if Photoshop uses the standard density in a JPEG header or a value from the EXIF data.
Anyway, to work out the answer, you can get all density type settings in an image with EXIFtool like this:
exiftool "-*resolution*" image.jpg
X Resolution : 72
Y Resolution : 72
Resolution Unit : inches
Exiftool is described here. Or, as you know, and love ImageMagick, you can use identify like this:
identify -verbose IMG_3942.JPG | grep -i reso
Resolution: 72x72
exif:ResolutionUnit: 2
exif:thumbnail:ResolutionUnit: 2
exif:thumbnail:XResolution: 72/1
exif:thumbnail:YResolution: 72/1
exif:XResolution: 72/1
exif:YResolution: 72/1
You can also set the density with ImageMagick after you have stripped the EXIF data like this:
# Strip EXIF then add in resolution
convert IMG_3942.JPG -strip -density 180x180 180.jpg
# Check what happened
exiftool "-*resolution*" 180.JPG
Resolution Unit : inches
X Resolution : 180
Y Resolution : 180
You can also modify the EXIF data with libexif if you look here.

PHP GD imagejpeg: output file size is bigger size than original

The following script is supposed to create an image with lower quality and so smaller file size (kb), instead it create an image with lower quality but bigger file size.
On my test the original is about 300kb, using 90% quality the output is almost the double and using 100% quality, the output is more than 1mb ...
<?php
$quality = 90;
$path = '/var/www/TEST/';
$inputSrc = $path . 'original.jpg';
$outputSrc = $path . 'after' . $quality . '.jpg';
$handler = imagecreatefromjpeg($inputSrc);
imagejpeg($handler, $outputSrc, $quality);
I assume the issue is related to imagejpeg bad implementation ...
is there any way to workaround this ?
isImageMagicka better solution ?
Thanks
Update
I was curious so I gave a try to ImageMagick and unfortunately I have similar result (slightly better).
Full test results:
Original size: 294.6Kb
GD (imagejpeg) 90%: 581.7Kb
GD (imagejpeg) 100%: 1.1Mb
ImageMagick 90%: 431.7Kb
ImageMagick 100%: 780.9kb
Update 2
I did some more test with GIMP and looks that in order to obtain a file with very similar size to the original one you have to check the option use quality setting from original image.
Now I'm confused more ... since when I select that setting Gimp automatically change the output quality to 74% (for the example image).
I was assuming that the JPEG quality value, if lower that 100%, decrease the image quality at every iteration of a save ... but I start to think I'm wrong here.
Update 3
With ImageMagick is not necessary to specify the quality of the sample and if you leave it emptyImageMagick will use the same quality detected in the input image.
So for the example image it is detected as a quality of 69 and the outfile is 326kb. That is the best result so far.
Here the image I'm using:
I had a little look at this. You can work backwards in ImageMagick and, rather than define the quality and see what size results, you can define the size and see what quality results. So, for a concrete example, you can say you want the output file not to exceed 100kB, like this:
convert MShRR.jpg -define jpeg:extent=100k out.jpg
and you get 99kB like this:
-rw-r--r--# 1 mark staff 294608 14 Jan 09:36 MShRR.jpg
-rw-r--r--# 1 mark staff 99989 14 Jan 09:44 out.jpg
To my eyes, the resulting image is a little posterised:
You can often add a tiny amount of blur to disguise this, as follows:
convert MShRR.jpg -blur x0.5 -define jpeg:extent=100k out.jpg
YMMV - Your Mileage May Vary !!!

How to convert CMYK/RGB TIFF to RGB JPEG using PHP IMagick

I have a PHP application which needs to deal with incoming TIFF files. I have neither control nor knowledge over the colorspaces of this TIFFs and the application should store all incoming images as RGB JPEGs.
Problem is, incoming TIFF files are anything: CMYK, RGB, some sort of YCbCr wrapped in sRGB, and so on, and I need to convert them somehow to RGB JPEGs before saving.
I need some sort of a conversion function in PHP which uses IMagick extension which can get any binary TIFF data and convert it to proper RGB JPEG binary data. It needs to handle different colorspaces inside TIFF images correctly. Output format (RGB JPEG) stays the same for any input file.
The following obvious solution converts some CMYK TIFFs correctly, some CMYK TIFFs get inverted colors and YCbCr RGB TIFFs get totally corrupted by red overlay:
$converter = new IMagick();
$converter->setResourceLimit(6, 1);
$converter->readImageBlob($data);
if ($converter->getImageColorspace() != IMagick::COLORSPACE_RGB
&& $converter->getImageColorspace() != IMagick::COLORSPACE_GRAY
) {
$icc_rgb = file_get_contents('sRGB_v4_ICC_preference.icc');
$converter->profileImage('icc', $icc_rgb);
$converter->setImageColorspace(IMagick::COLORSPACE_RGB);
}
$converter->setImageFormat('jpeg');
$converter->setImageCompression(Imagick::COMPRESSION_JPEG);
$converter->setImageCompressionQuality(60);
$converter->resizeImage(1000, 1000, IMagick::FILTER_LANCZOS, 1, true);
$converter->stripImage();
$result = $converter->getImagesBlob();
This solution is taken from there: http://blog.rodneyrehm.de/archives/4-CMYK-Images-And-Browsers-And-ImageMagick.html Obviously, it doesn't work for all colorspaces, because it doesn't detect them reliably. As you can see, it even uses the sRGB_v4 ICC color profile downloaded from it's homepage.
Google finds me one particular solution to the red overlay problem (just one of the conversion screw-ups), but it's only for console and when you know beforehand that you deal with YCbCr images:
convert some.tif -set colorspace YCbCr -colorspace RGB some.jpg
I can live with passthru-ing convert and pass to convert all the magical switches needed, but I suppose I need to detect the source image's colorspace beforehand and call a identify | grep before every convert in an otherwise PHP application is an overkill.
I've experienced this same issue.
It also came up in the imagick forums and the correction was pushed into ImageMagick 6.8.0-4 .
So upgrading should solve this issue. I've upgraded to ImageMagick 6.8.1-9 and haven't encountered this since.

How to check a PNG for grayscale/alpha color type?

PHP and GD seem to have trouble creating images from PNGs of type greyscale with alpha when using imagecreatefrompng(). The results are incredibly distorted.
I was wondering if anyone knew of a way to test for the colour type in order to notify the user of the incompatibility?
Example:
Original Image: http://dl.dropbox.com/u/246391/Robin.png
Resulting Image: http://dl.dropbox.com/u/246391/Robin_result.png
Code:
<?php
$resource = imagecreatefrompng('./Robin.png');
header('Content-type: image/png');
imagepng($resource);
imagedestroy($resource);
Cheers,
Aron
The colour type of a PNG image is stored at byte offset 25 in the file (counting from 0). So if you can get hold of the actual bytes of the PNG file, simply look at byte 25 (I don't do PHP, so I don't know how to do that):
0 - greyscale
2 - RGB
3 - RGB with palette
4 - greyscale + alpha
6 - RGB + alpha
The preceding byte (offset 24) gives the number of bits per channel. See the PNG spec for more details.
In a slight twist a PNG file may have "1-bit alpha" (like GIFs) by having a tRNS chunk (when it is colour type 0 2 or 3).
i landed here today searching for a way to tell (via php) if a specific .png image is an alpha-png one -
David Jones' answer points to the right direction, really easy to implement in php:
file_get_contents to load just that 25' byte (there it is, indeed!), and
ord() to get its ASCII value, to test it (against '6' in my case)
if(ord(file_get_contents($alpha_png_candidate, NULL, NULL, 25, 1)) == 6) {
is_alpha_png_so_do_something();
}
actually i needed that for assuring backward compatibility with ie6
within cms-user-generated-pages, to replace all alpha-png < img > tags with inline-block < spans > - the alpha-png file will then be served as variable for the ms-proprietary css property filter
.alpha_png_span{
filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(
src='$alpha_png_candidate', sizingMethod='crop')
}
...and it all works, so thanks!
paolo
see this answer
:
Another usefull note for those using ImageCreateFromPng:
PHP and GD do not recognize grayscale/alpha images.
So if you use grayscale images with transparency between 0% and 100%, then save the image as RGB.
At least this is true for PHP Version 4.4.2-1 and in 5.1.2-1 with pictures made with GIMP 2.2.8.
url :
http://php.net/manual/en/function.imagecreatefrompng.php

Categories