I have a very large PNG image, and I am writing a method to get the value for a color at a specific (but changing) pixel of that image. When I create the image using:
$image = imagecreatefrompng('map.png');
Is the whole image loaded into memory (not ideal), or does it just read the meta data and prepare for other calls so that when I call:
int imagecolorat ( resource $image , int $x , int $y )
Will it file seek to the right pixel or pull from memory? If I'm trying to optimize this routine to be called repeatedly, would I be better off converting the image data I need into some raw binary format and using file seek? I'd like to avoid repeatedly loading the whole file into memory if possible.
You need a big php memory to play with php image resources.
Use graphicsMagick instead. http://www.graphicsmagick.org/
Related
I have a large PNG file that I would like to print it over the ESCPOS-PHP library. I knew there is something like MODE_DOUBLE_WIDTH, but my image is already in a large size so I want to make it smaller.
However I have been looking for the parameter of setting the dimension of a image file, is there any parameter to resize (set the size like 20x20) the image programmatically.
mike42/escpos-php will not have a function to convert the size of image data.
The documentation doesn't mention it, and the source code doesn't have that functionality.
If you want to convert some image data file into data of specific vertical and horizontal dot size, please use another library other than mike42/escpos-php or the function of language.
documentation:
graphics(EscposImage $image, $size)
Print an image to the printer.
Parameters:
EscposImage $img: The image to print.
int $size: Output size modifier for the image.
Size modifiers are:
IMG_DEFAULT (leave image at original size)
IMG_DOUBLE_WIDTH
IMG_DOUBLE_HEIGHT
The function bitImage() takes the same parameters, and can be used if your printer doesn't support the newer graphics commands. As an additional fallback, the bitImageColumnFormat() function is also provided.
source code:
escpos-php/src/Mike42/Escpos/EscposImage.php
escpos-php/src/Mike42/Escpos/GdEscposImage.php
escpos-php/src/Mike42/Escpos/ImagickEscposImage.php
The specification of IMG_DEFAULT, IMG_DOUBLE_WIDTH, IMG_DOUBLE_HEIGHT is the value specified in the parameter of the ESC/POS command, not the function of converting the image data.
ESC *
GS /
GS Q 0
GS v 0
So since animated GIFs are a series of GIFs concatenated together with "\x00\x21\xF9\x04", I am able to explode the GIF and implode it to take it apart and build it again. However I can't seem to get GD to create an image from the data.
Is there something I need to append in order to have GD recognize the data?
$im = file_get_contents('test.gif'); //get the data for the file
$imgarray = explode("\x00\x21\xF9\x04", $im); //split up the frames
foreach ($imgarray as $frame) {
$img[] = imagecreatefromstring($frame); //this is the line that fails
}
$new_gif = implode("\x00\x21\xF9\x04", $img); //this should work but imagecreatefromstring fails
$new_gif = implode("\x00\x21\xF9\x04", $imgarray); (Does work as it just puts the image back together)
A GIF does not contain just separate images appended after each other. A frame in a GIF may change just a part of the image - it does not have to cover the whole frame. It can also contain a local palette, but otherwise it relies on the global palette of the image - which is stored for the file itself and not just the frame.
I.e. - you can't just explode the file and decode each segment separately and except to get useful images from GD.
You'll at least have to add the gif header to each set of image data, but I strongly recommend using the PHP ImageMagick interface instead if possible - it has far better support for iterating through frames in an image.
Another option is using a pure PHP implementation that does what you want, such as GifFrameExtractor.
The relevant code is located at line 137 of the source file:
$img = imagecreatefromstring(
$this->fileHeader["gifheader"] .
$this->frameSources[$i]["graphicsextension"] .
$this->frameSources[$i]["imagedata"] .
chr(0x3b)
);
As you can see, there is far more data necessary (the header, the extension (87a vs 89) and a terminating character) to make it valid GIF data.
In Imagemagick, this is pretty trivial. You can coalesce the image to fill out any frames that have been optimized, then do your processing, then optimize it again.
Input:
convert bunny.gif -coalesce -resize 50% -layers optimize bunny_small.gif
I know I can compare two images (to check whether they are visually the same, not to check their file format, EXIF, etc.) using compareImages( Imagick $compare , int $metric ) function of ImageMagick library in PHP (also available in several other programming languages).
Sample codes to compare 2 images in PHP:
<?php
$image1 = new imagick("image1.png");
$image2 = new imagick("image2.png");
// TODO: have to resize 2 images to same dimension first
$result = $image1->compareImages($image2, Imagick::METRIC_MEANSQUAREERROR);
$result[0]->setImageFormat("png");
header("Content-Type: image/png");
echo $result[0]; // display the result
// TODO: Add exception handling
?>
But with thousands of images to compare against, this function seems to be inefficient, as it can only compare one by one. Is there any function that I can use to make a fingerprint (something like that) of an image, so that I can easily search in the database?
Methods I can think of:
Convert the image to Base64 string
Fetch few sample pixels from each image, store the colors in the database (but this method is not accurate)
Use Image recognition library (something like Machine Learning) to add some tags for each image, then search by tag (this method is not accurate as well)
(anything else?)
All suggestions are welcomed.
p.s. programming language does not necessary to be in PHP.
You could use the getImageSignature function, which will return a string containing the SHA-256 hash of the file.
So either loop over all images and add the image signature to your database of images, or just add the signature on every comparisson you perform.
Hope that helps.
Is there a way to turn a jpg to string, reverse of imagecreatefromstring?
I have to communicate to a server which needs binary of image, i saw plenty of jpg to binary but not the other way around.
Just a shot in the dark here... No real experience with this, just my thoughts after looking through some documentation...
I see in the documentation of imagecreatefromstring() an example is given where a base64 encoded string is converted into an image. Taking that example and flipping it around might just be what you are looking for.
$image = file_get_contents('image_file.jpg');
$imageString = base64_encode($image);
imagecreatefromstring takes a string which contains the binary data of an image and turns it into a gd image resource so you can manipulate it with the gd image library. Literally the "reverse" of that would be imagejpeg, which saves a gd image resource to a jpeg image.
I guess what you really want though is simply the initial string, which contains the binary data of the image to begin with. I.e.:
$imageString = file_get_contents('image.jpg');
$gd = imagecreatefromstring($imageString);
Just skip step 2.
I am using a the standard PHP functions imagecopytruecolor and imagejpeg
to rescale and produce uploaded images from a standard HTML form. The images appear at the correct size however the image filesize is quite high (e.g. 540px * 350px = 250kb)
When compared to Photoshop's Save for Web using JPEG high quality settings the same files are come out at about 60kb, so about 4 times as small.
Is there anything I can do to reduce the filesize?
You can set $qualityin imageJPEG. From the manual:
bool imagejpeg ( resource $image [, string $filename [, int $quality ]] )
quality is optional, and ranges from 0 (worst quality, smaller file) to 100 (best quality, biggest file). The default is the default IJG quality value (about 75).
In my experience, it is not advisable to go much under 70%, though.
You may want to try whether you can get better results with smaller file sizes from other image processing engines like ImageMagick, if you can use that. I often have the feeling that GD's JPG encoder is not top of the line, but that's nothing more than a subjective impression at the moment.
No image library I've ever seen comes anywhere close to how efficiently Photoshop compresses a file. You could try using another library like ImageMagick (aka Imagick) which might saves smaller files at the same quality size than the default stuff your using, but keep in mind you'll never get a 60K image from these libraries at this res.
You can change the quality setting (3rd argument of imagejpeg, see the docs). The default is only 75% though, which should already be rather small.
From the docs
bool imagejpeg ( resource $image [, string $filename [, int $quality ]] )
experiment with $quality