Resizing QRCode from base64 png in PHP - php

I get a QRCode png as base64 from a remote service and need to display it on the web. When blowing the picture up without the "vector" data, it blurs:
I write the base64 to disk with
fwrite($ifp, base64_decode($this->getQRCode()));
The resulting png is a bit small (29x29 pixels). When I open it with e.g. Photoshop, I can blow it up without loss so it looks like the "vector" data is intact. Note the "pixels":
How can I do this on the server side before writing it down to disk and linking to it from the web.

You don't say how you are "blowing the picture up." Have you tried rescaling the image in PHP?
$image = imagecreatefrompng($filename);
$bigimage = imagescale($image, 128, 128, IMG_NEAREST_NEIGHBOUR);
header("Content-Type: image/png");
//dumps directly to output
imagepng($bigimage, null, 0);
Edit: you can try various interpolation modes as specified here, if IMG_NEAREST_NEIGHBOUR isn't suitable. (Also, note the British/Canadian spelling of neighbour.)

The old school way of blowing up images was to (ideally) double pixels. Smoothing the rough edges that were the result of that process was invented later. So now I go with this:
imagescale($image, 128, 128, IMG_NEAREST_NEIGHBOUR);

Related

How to use PHP GD to create 1 bit bitmaps (black and white only, no gray)

My goal
I have an existing PNG. It currently has anti-aliasing, or in other words, shades of gray. I want the image to be 1 bit, or in other words, only using the colors black and white. My aim is to do this with PHP GD. I have to do this with an existing image, and can not create the image from scratch using imagecreatetruecolor.
What I'm trying
The function I've found that seems best for the job is imagetruecolortopalette
http://php.net/manual/en/function.imagetruecolortopalette.php
Here is a simple version of what I'm trying to do
$user_design = base64_decode($_POST['input']);
$design_file = fopen('path/filename.png', 'w') or die("Unable to open file!");
imagetruecolortopalette($design_file, false, 1);
fwrite($design_file, $user_design);
fclose($design_file);
With this being the key line. The 1 being the "maximum number of colors that should be retained in the palette."
imagetruecolortopalette($design_file, false, 1);
Behavior I'm getting
The image appears unchanged. I'm not sure if I'm using PHP GD correctly, or if this function doesn't do what I think it does.
Other ideas
These also seem promising.
imagecolordeallocate seems like I may be able to use it to deallocate colors, but not sure how to do this without calling it 254 times.
http://php.net/manual/en/function.imagecolordeallocate.php
imagecolorset seems like I may be able to use it to set the palette, but I'm not sure how to do this for existing images.
http://php.net/manual/en/function.imagecolorset.php
Mostly I suspect imagetruecolortopallette is the best bet, but any and all ideas welcome.
$im = imagecreatefromstring($user_design);
imagefilter($im, IMG_FILTER_GRAYSCALE);
imagefilter($im, IMG_FILTER_CONTRAST, -1000);
imagepng($im, 'path/filename.png');
imagedestroy($im);
How do you convert an image to black and white in PHP

Strange artefacts with imagecreatefrompng and imagepng compression

My simple goal was to compress PNG files with the following code:
$image = imagecreatefrompng("test.png");
imagepng($image, "result.png", 9, PNG_ALL_FILTERS);
I've also tried with zero and default compression, with the same results.
Original file is like this:
But the result on some (not all) images was like this:
The only way, I can produce good results is with this additional code:
imagealphablending($image, false);
imagesavealpha($image, true);
Why does this simple image manipulation produce this kind of artefacts? And by saving full alpha information, do I get into troubles with some browsers or unneeded filesize?
Is there any other foolproof solution, which would losslessly compress png files?

php imagerotate() ruins alpha on png?

I've been bashing my head agains something simple..
// ....all prev code is fine....
$pasteboard =imagecreatetruecolor($imgs['bg']["width"],$imgs['bg']["height"]);
imagealphablending($pasteboard, false);
imagecopyresampled($pasteboard, $imgs['bg']["img"],0,0,0,0,$imgs['bg']["width"],$imgs['bg']["width"],imagesx($imgs['bg']["img"]),imagesy($imgs['bg']["img"]));
imagecopyresampled($pasteboard, $imgs['photo']["img"],20,20,0,0,$imgs['photo']["width"],$imgs['photo']["width"],imagesx($imgs['photo']["img"]),imagesy($imgs['photo']["img"]));
imagesavealpha($pasteboard,true);
//send it out
$out = $pasteboard;
header('Content-type: image/png');
imagepng($out);
//then garbage collection
gives me this:
HORAY!
perfect alpha png composite...
Now I want to rotate it, so instead of the $out=$pasteboard i do this:
imagesavealpha($pasteboard,true);
//rotate it
$out = imagerotate($pasteboard,5,imagecolorexactalpha($pasteboard,255,255,255,50),0);
header('Content-type: image/png');
imagepng($out);
which sadly gives me this:
BOOOO!
Ive tried setting the color like:
imagerotate($pasteboard,5,0x00000000,0);
also the last attr like:
imagerotate($pasteboard,5,0x00000000,1);
new empty images sampled etc etc...
no dice....
Can anyone help?
I'm answering my question simply because I've tried 10-15 suggestions i've seen allover the web all of which offering 'nearly' right solutions but nothing exact, Also I've seen this question posted a few places now, and hopefully if anyone reaches this page in future it would be best to show the solution as the direct answer.
MASSIVE thanks to #cristobal for the help and efforts, if I could vote you up any more I would !
The knack seems to be:
//rotate it
$pasteboard = imagerotate($pasteboard,5,0XFFFFFF00,0); //<-- here must be RRGGBBAA, also last attr set to 0
imagesavealpha($pasteboard, true); // <-- then to save it... dont ask me why..
//send it out
header('Content-type: image/png');
imagepng($pasteboard);
produces this (it has a perfect alpha even though you cant see against the white page):
REALLY not the most fun 5 hrs of my life... hopefully it will stop someone else going through the same pain..
Using the same code above and using a blue color for the third parameter in the imagerotate operation, which will be it used to fill the uncovered zone after the rotation i.e.:
imagerotate($pasteboard, 5, 255);
We get the following image
we see the blue area is the uncovered zone which it fills, while the black color is the to be the border shadow from the image which GD does not seem to handle well along the interpolation used in the rotation.
The same image rotated using the convert for imagemagick. commmand i.e. $> convert -rotate 5 image.png image_rotated.png results in the image below
Clearly GD does not handle alpha colors well when rotating.
If you have access to use the convert commmand using exec or process, you should pipe those image operation to imagemagick instead. GD is a simple image library which has not been updated much the latest years. Otherwise try Imagemagick, Cairo or Gmagick which there are pecl plugins for too http://php.net/manual/en/book.image.php.
Last resort somebody made a function that which uses GD http://www.exorithm.com/algorithm/view/rotate_image_alpha for what you are looking after but the result is not pretty since its a simple linear interpolation:
taken from How to rotate an image in GD Image Library while keeping transparency?. Perhaps if you convert the linear interpolation function to a Bicubic or Quad it will look better.
Note these answers did not work for me but this did.
$destimg = imagecreatefromjpeg("image.png");
$rotatedImage = imagerotate($destimg, 200, 0);
imagesavealpha($rotatedImage, true);
imagepng($rotatedImage,"rotated.png");

How to correctly resize png images

I use the following combination of functions
$img_r = imagecreatefrompng($src);
$dst_1 = imagecreate( $targ_w_1, $targ_h_1 );
imagecopyresampled($dst_1,$img_r,0,0,0,0,$targ_w_1,$targ_h_1,$size_test[0],$size_test[1]);
imagepng($dst_1, $final_source_1,9);
Final result comes with very low quality, as I understand imagepng max quality is 9. You cannot write 100 there. But still quality is very bad. maybe I use wrong functions to manipulate with image ? Any suggestions ?
original 220x220 image
resized image to size 120x120
resized image with the same size 220x220
SOLVED
Look in the manual. It has this to say on imagepng()'s $quality parameter:
Compression level: from 0 (no compression) to 9.
So 9 seems to be the worst quality level. Try a lower setting.
As far as I know, there is no such thing as a quality setting in the PNG-format, nor in the underlying c-library. There is compression, but since PNG is a loss-less format, compressing the image does not degenerate the quality.
The compression setting of 9 gives the best compression (=smallest file size).
The issue you run into likely is that your destination image is created with imagecreate(); a paletted image.
You are more likely looking for imagecreatetruecolor()
Problem was with alpha . After I read Jaccos comment I went to google and found this
imagealphablending($dst_1, false);
imagesavealpha($dst_1,true);
$transparent = imagecolorallocatealpha($dst_1, 255, 255, 255, 127);
imagefilledrectangle($dst_1, 0, 0,$targ_w_1, $targ_h_1, $transparent);
This peace of code must be put right after imagecreatetruecolor ad everything will be just fine :)

imagecopyresampled sometimes creating blank images

I am resizing images using:
//load file and dimensions
$obj_original_image = imagecreatefromjpeg($str_file_path);
list($int_width, $int_height, $image_type) = getimagesize($str_file_path);
//compress file
$int_thumbnail_width = 320;
$int_ratio = $int_thumbnail_width / $int_width;
$int_new_width = $int_thumbnail_width;
$int_new_height = $int_height * $int_ratio;
$obj_image = imagecreatetruecolor($int_new_width, $int_new_height);
imagecopyresampled($obj_image, $obj_original_image, 0, 0, 0, 0, $int_new_width, $int_new_height, $int_width, $int_height);
imagejpeg($obj_image, $GLOBALS['serverpath'] . '/images/uploaded/video-thumbs/'.$arr_data['thumbnail_folder'].'/' . $arr_data['id']. '.jpg', $int_compression = 85);
And this is generally working perfectly. However occasionally, it is producing a blank, white image. I have read this note at http://php.net/manual/en/function.imagecopyresampled.php:
There is a problem due to palette image limitations (255+1 colors). Resampling or filtering an image commonly needs more colors than 255, a kind of approximation is used to calculate the new resampled pixel and its color. With a palette image we try to allocate a new color, if that failed, we choose the closest (in theory) computed color. This is not always the closest visual color. That may produce a weird result, like blank (or visually blank) images. To skip this problem, please use a truecolor image as a destination image, such as one created by imagecreatetruecolor().
However, I am already using imagecreatetruecolor. I am always scaling the same sized images so it can't be a width/height issue. It is only happening sometimes, most times the image scaling is working fine. Any ideas as to how to fix this?
There's no reason to be using getimagesize() when you've already opened the image with imagecreatefromjpeg(). You can use the imagesx() and imagesy() to get the width/height. getimagesize is seperate from GD and will re-open the image, re-parse it, etc...
Also note that GD is pretty stupid and forces you to determine what image type you've got and call the appropriate createfrom function. imagecreatefromjpeg() will fail if you try to open anything OTHER than a .jpg image.
$obj_original_image = imagecreatefromjpeg($str_file_path);
if ($obj_original_image === FALSE) {
die("Unable to load $str_file_path. Not a jpg?");
}
etc... etc...
$status = imagecopyresampled($obj_image, $obj_original_image, 0, 0, 0, 0, $int_new_width, $int_new_height, $int_width, $int_height);
if ($status === FALSE) {
die("imagecopyresampled failed!");
}
As well, add some debugging to your height/width calculations - output the values you're generating. Maybe one or more of them is coming out as 0, so you end up resampling to a non-existent size.
You mentioned that the size of the image being processed is always the same, but is the resolution always the same? If you have a particularly high resolution image you're working with, you may be running out of memory for certain operations which will produce a blank white image, in my experience. If this is the case, you could try to fix it by increasing the amount of memory allocated to PHP in php.ini under the memory_limit parameter. As far as I know, that value applies to image manipulations.

Categories