Convert PNG to black and white GIF with gd or imagemagick - php

I am generating barcodes in a PHP webpage with the Picqer library, which can output to PNG, JPG, SVG or HTML.
On-screen they look great and are readable with the wand, but when printing they are apparently dithered, preventing them from being read.
If I save the generated PNG image to a file and use Photoshop to convert it to GIF (no transparency, 0 dither, 2 colors), then re-open the image with the browser and print, I get a perfect, crisp image with no dithering.
So I tried converting directly to GIF with the gd library in PHP:
// Create a GD image from the PNG generated by getBarcode. ($result = the Picqer\Barcode\BarcodeGeneratorPNG::getBarcodeoutput
$gd_image = imagecreatefromstring($result);
// Convert to palette image with no dithering and 2 colors
imagetruecolortopalette($gd_image, false, 2);
// Output the image as a GIF:
header('Content-Type: image/gif');
imagegif($gd_image, false); // Output directly to browser
However, this generates an exact duplicate of the PNG - when printed, it's dithered.
How can I fix this in order to generate a 2-color GIF with no dithering and no transparency? I think this would solve the output clarity issue. If there's a better way, I'm open to it.
I'm also open to using other image processing libraries like Imagick if that would be a better choice.
Thanks!
UPDATE #1:
OK so I have made some progress: I switched to Image Magick and performed the following conversion from the original PNG file to a 2-color, non-dithered GIF, which renders a beautifully clean and crisp black and white image:
$im = new Imagick();
$im->readImageBlob($result); // convert string to Imagic
// Quantize:
$im->quantizeImage(2, imagick::COLORSPACE_GRAY, 1, false, false);
// Output image as GIF
$im->setIMageFormat('gif');
header("Content-Type: image/gif");
echo $im->getImageBlob();
PROBLEM: this method seems to be very resource-intensive. When I request a page filled with barcode images (20-30 qty) several of the images appear as "broken", generating http 500 errors "end of script output before headers".
I assume this means the Imagick routines are using hefty memory/cpu resources, so when the browser requests lots of images at once, PHP is reaching the limits of its resources.
UPDATE #2:
Performance tests reveal that Imagick is the bottleneck:
Generating 133 barcodes on a single HTML page, in PNG format:
Average time to execute getBarcode() function: 733uS
Average time to echo result: 13uS
Generating same 133 barcodes using the Imagick conversion listed above:
getBarcode() - avg 1mS
Conversion to GIF: avg 0.76 S
So I wonder why Imagick is so slow... ? These are tiny files, on the order of 200 bytes (PNG).
SAMPLE INPUT PNG IMAGE:

Related

PDF to PNG from iMagick is very bad quality

I am converting PDF files to PNG files using imagick in PHP.
For this example I have a PDF file with only 5 lines of text on the first (and only) page. This PDF is generated from a Word file (it's not scanned in).
My code to convert the file looks like this:
$im = new Imagick();
$im->setResolution(200,200);
$im->readImage($_SERVER['DOCUMENT_ROOT'] . '/codeigniter/vrm/documents/uploaded_documents/2020/04/buddy_voor_lennert-01042020130414.pdf[0]');
$im->scaleImage(500,500);
$im->setImageFormat('png');
$im->writeImage($_SERVER['DOCUMENT_ROOT'] . '/codeigniter/vrm/documents/images/thumbnails/lennert.png');
$im->clear();
$im->destroy();
After this, the png is created, but the quality of the text is horrible, it becomes unreadable, see the screenshot i attached below.
How do I retain the same quality? I want to generate a thumbnail and a normal size image. So the thumbnail can be of lower quality, but the normal size image should be at least of a readable quality.
I've tried putting the resolution down to 50x50 or tried using the following methods, to no avail:
$im->setImageCompressionQuality(0); (also to 100)
$im->resizeImage(500, 500, Imagick::FILTER_LANCZOS, 0, true);

PHP Imagick ReadImage WriteImage different quality

I am scaling images with php-imagick. The image I want to scale is a jpg without exif data (1600x1200+0+0 8-bit sRGB). The quality of the scaled image is lower than the original. By quality I mean that the image has more artifacts (visible quality). So I made a test where I simply read an image and write it under another filename without chaning anything else:
$im = new Imagick();
$im->readImage(realpath('./a.jpg')); // image quality checked with $im->getImageCompressionQuality() 50
$im->writeImage('./b.jpg'); // image quality checked with $im->getImageCompressionQuality() 50
The result is:
Image a.jpg > 254kb (original image)
Image b.jpg > 183kb
So by simply writing the image to a new file, php-imagick changes something that I don't want.
Can anyone explain to me:
What happens to the generated image?
How can I write the image without changing any other stuff except scaling?
Thanks

Imagick - When resizing, image gets blurry

I am trying to resize a pdf (which i converted from image), and I am trying to resize (increase) the image in its ratio.
$imagick = new \Imagick();
$imagick->readImage($path);
$imagick->resizeImage(595,842,\Imagick::FILTER_CUBIC, 1, true);
// and this:
// $imagick->adaptiveResizeImage(595,842, true);
$imagick->setImageFormat('pdf');
$imagick->writeImage($endpath);
But the image is getting blurry. However, it's not a bad quality image and the image can go that size without getting disturbed. (For example, if I let Twilio to do it (via fax api), the same image can get to that scale).
I have also tried with putting blur parameter of resizeImage between '1' and '0.1'
Original pdf (you can also see it here, if you want to try):
My resized pdf (with blur 1):
My "adaptive resized" pdf:
You are starting with a very small pdf if rasterized and enlarging. So that would cause blurring. But if you increase the input density, it works fine for me in ImageMagick as
convert -density 600 input.pdf -resize 595x842 result.png
I do not know Imagick well, but try the following. Reduce the blur value in resizeImage as desired to make it sharper.
$imagick = new \Imagick();
$imagick->readImage($path);
$imagick->Imagick::setImageResolution( 600, 600 );
$imagick->resizeImage(595,842,\Imagick::FILTER_CATROM, 1, true);
$imagick->setImageFormat('pdf');
$imagick->writeImage($endpath);

Convert PDF (with transparency *and* CMYK) to jpg

I need to generate jpg images from PDF files (first page only). The PDF files are user generated, so they can contain anything. I'm currently using the following code:
// Load PDF.
$i = new Imagick;
// Create thumbnail of first page of PDF.
$i->setResolution(150, 150);
$i->loadImage("test.pdf[0]");
$i->thumbnailImage(640, 480, true);
// Remove transparency, fill transparent areas with white rather than black.
$i->setImageBackgroundColor("white");
$i->setImageAlphaChannel(11); // Imagick::ALPHACHANNEL_REMOVE
$i->mergeImageLayers(Imagick::LAYERMETHOD_FLATTEN);
// Output.
$i->writeImage("test.jpg");
This works as expected in that transparency becomes white instead of black. However, I've run into problems with some generated jpg images, so I ran jpeginfo on them:
$ jpeginfo -c test.jpg
test.jpg 960 x 480 32bit JFIF N 9481 Unsupported color conversion request [ERROR]
It turns out that some source PDFs actually use CMYK, and apparently are not converted to RGB when saved as jpg. So I changed my code to the following (addition of a single line) to explicitly convert to RGB:
// Load PDF.
$i = new Imagick;
// Create thumbnail of first page of PDF.
$i->setResolution(150, 150);
$i->loadImage("test.pdf[0]");
$i->thumbnailImage(640, 480, true);
// Remove transparency, fill transparent areas with white rather than black.
$i->setImageBackgroundColor("white");
$i->setImageAlphaChannel(11); // Imagick::ALPHACHANNEL_REMOVE
$i->mergeImageLayers(Imagick::LAYERMETHOD_FLATTEN);
// Convert to RGB to prevent creating a jpg with CMYK colors.
$i->setImageColorspace(Imagick::COLORSPACE_RGB);
// Output.
$i->writeImage("test.jpg");
This creates a jpeg with an RGB color profile, all right. However, for some obscure reason it results in an image with a black background again. In other words: the transparency problem is back. Why does Imagick do this, and more importantly, what's the solution to both the transparency problem and the CMYK problem?
The correct function to use is transformImageColorspace not setImageColorspace. transformImageColorspace is used for existing images, setImageColorspace is for new images e.g. svg drawing..
I've added it to the manual and it should show up soon.

php imagick won't save PNG compressed but shows compressed in browser

I have the following code in PHP to take the screenshot of first page of the PDF.
$name = getcwd()."\\testfile";
$img = new imagick();
$img->setResolution(200,200);
$img->readImage($name.'.pdf[0]');
$img->setImageResolution(100,100);
$img->resampleImage(100,100,imagick::FILTER_LANCZOS,1);
$img->setImageCompression(\Imagick::COMPRESSION_ZIP );
$img->setImageCompressionQuality('0');
$img->setImageFormat('png8');
$img->writeImage($name.".png");
header("Content-type : image/png");
echo $img;
This code produces the PNG of 62kb only in the Google Chrome's Resource monitor tab. But the image which is written by Imagick() is above 114kb. Just to make sure image isn't compressed and or any other issues i have used a online service called TinyPNG and they compressed the image shrinking it to exactly 62kb i get in browser...
What could be wrong in this code? Also i am using PNG8 format because thats more efficient.
Best
Ahsan
I think this is caused by your writeImage statement. If you write a PNG image without specifying png8: specifically in the filename your image will not be stored in that format. In essence setImageFormat will only affect when you retrieve the image as a string (echo $img).
If you do the following:
$img->writeImage ('png8:' . $name . ".png");
it should be stored as a png8. You can verify this with identify -verbose and checking the Depth / Channel Depth.
These are the default compression methods used for the following common image formats:
PNG: Imagick::COMPRESSION_ZIP
JPEG: Imagick::COMPRESSION_JPEG
GIF: Imagick::COMPRESSION_LZW

Categories