Exploding Animated GIF and Manipulating Frames (GD Library) - php

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

Related

PHP Imagick converting SVG without antialiasing

I'm trying to write a PHP function to convert an SVG image without any antialiasing (so that the final PNG is blocky and contains only the colours specified in the SVG).
The command line equivalent is:
convert +antialias /path/to.svg /path/to.png
I'm assuming that I need to use PHP's Imagick::setOption method to pass in "+antialias", but the documentation is very sparse.
The following snippet will write a PNG file, but none of the options prevents antialiased pixels being rendered:
$image = new Imagick();
// None of these have any affect - output image is always antialiased.
$image->setOption('+antialias', true);
$image->setOption('-antialias', true);
$image->setOption('+antialias', 'true');
$image->setOption('-antialias', 'true');
$image->setOption('antialias', true);
$image->setOption('antialias', false);
$image->setOption('antialias', 'true');
$image->setOption('antialias', 'false');
$image->readImage('/path/to.svg');
$image->writeImage('/path/to.png');
Any help would be great, thanks.
That is not a good way to anti-alias a vector file such as SVG. The proper way in command line would be to set the desired density before reading the file and then resize back to compensate for a large magnification when using a large density. So for example
convert -density 288 image.svg -resize 25% image.png
Nominal density (default) is 72. So 288 = 72*4. Thus we resize afterwards by 1/4 = 25%, unless you want a larger output. Then resize by a larger value.
In PHP Imagick, you can create a new Imagick() instance. Then set the desired density. Then read the input SVG. Then resize. Then set the PNG format and save to disk. See setImageResolution for setting the density in Imagick. See https://www.php.net/manual/en/imagick.setimageresolution.php
I don't think what you want is possible, unfortunately. ImageMagick shells out to Inkscape to render SVGs, and Inkscape has no command-line option to disable antialiasing.
https://graphicdesign.stackexchange.com/questions/138075/export-svg-without-anti-aliasing-in-inkscape-1-0-by-command-line
You could render at high resolution and then do nearest-neighbour downsampling. It would reduce the visible antialiasing, but you would still get some colours not in the SVG file.

How efficient is a PHP image resource?

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/

Imagemagick resizing control quality and extension

I am trying to learn Imagemagick, php.net docs are terrible T_T, and I cannot seem to find any answers to my questions. I am wanting to allow people to upload images then resize them and lose EXIF data.
Heres what I have currently.
$thumbnail = new Imagick("http://4.bp.blogspot.com/-hsypkqxCH6g/UGHEHIH43sI/AAAAAAAADGE/0JBu9izewQs/s1600/luna-llena1.jpg");
$thumbnail->thumbnailImage( 100, 100, true );
$thumbnail->writeImage( "avatar/thumbnail.jpg" );
Now how do I control the image file that it is being saved as? Lets say the user submits a gif/png/jpg how would I go about taking that image then saving it as the same input format or changing them all to .png?
This IMO produces the best results for imagick thumbnails;
Load the picture
$img = new imagick( $_FILES['Picture']['tmp_name'] );
Trim an excess off the picture
$img->trimImage(0);
Create the thumbnail, in this case, I'm using 'cropThumbnailImage'
$img->cropThumbnailImage( 180, 180 );
Set the format so all pics can now be the same standard format
$img->setImageFormat( 'jpeg' );
Set the Image compression to that of a jpg
$img->setImageCompression(Imagick::COMPRESSION_JPEG);
Set the quality to be 100
$img->setImageCompressionQuality(100);
The resulting thumbnail is then a little bit blury IMO, so I add a slight sharpening effect to make it 'sharper'. . play around with these settings, but I like..
$img->unsharpMaskImage(0.5 , 1 , 1 , 0.05);
I agree, the PHP.net docs are not very helpful. I've found that it's easiest to find how to do things using commands, then match the commands up with the PHP methods. I'm a little late replying so you might have figured it out by now, but if not, or for the benefit of anyone else:
If you want to change the image format before saving, add this before your writeImage line:
$thumbnail->setImageFormat('png');
Then change the extension in your writeImage line to match, e.g. thumbnail.png
To change the quality, write:
$thumbnail->setImageCompressionQuality(40); // Adjust the number 40
In some cases you might also want to set the compression type by writing:
$thumbnail->setImageCompression(Imagick::COMPRESSION_JPEG);
You can find the COMPRESSION constants here: http://www.php.net/manual/en/imagick.constants.php
Note: These are just examples. This compression would not actually work with a png file.

Add round corners to a jpeg file

I am trying to add round corners to a jpeg file, but the problem is that after adding round corners, I am getting a black background color. Somehow I am not able to change it to any other color (white, transparent, red). It just simply shows black background where the image has rounded corners.
The code that I am using is:
<?php
$image = new Imagick('example.jpg');
$image->setBackgroundColor("red");
$image->setImageFormat("jpg");
$image->roundCorners(575,575);
$image->writeImage("rounded.jpg");
header('Content-type: image/jpeg');
echo $image;
?>
I cannot use png as the jpeg files are huge, about 5 MB, so if I used png, the file size would go up to 26 MB, even though the png adds transparent round corners.
Also the IMagick version that i am using is:
ImageMagick 6.6.2-10 2010-06-29 Q16 http://www.imagemagick.org
Also the output(image generated) will get printed so I don't know if css will work over here.
Sorry, I am trying to actually create a new jpeg file with rounded corners from an already existing jpeg file that doesn't have round corners this is actually a photograph taken from a camera, so there are multiple/too many colors so I can't use gif as well.
Also my site will only just generate the round corner image then afterwards it will get downloaded using a FTP program by the admin of the site and then using a system software will get printed, so in short my website will not be printing the image but rather just generate it
Try this:
<?php
$input = 'example.jpg';
$size = getimagesize($input);
$background = new Imagick();
$background->newImage($size[0], $size[1], new ImagickPixel('red'));
$image = new Imagick($input);
$image->setImageFormat("png");
$image->roundCorners(575,575);
$image->compositeImage($background, imagick::COMPOSITE_DSTATOP, 0, 0);
$image->writeImage("rounded.jpg");
?>
I may get downvoted, but I say let css deal with the corners and take some load off of your server :)
CSS rounded corners.
JPG doesn't have a transparent color(s) (alpha channels) in its palette.
The output image must use either PNG or GIF (or another image format that supports alpha channels).
setImageBackgroundColor is another option if you want an opaque background.
EDIT
Your comment reminds me that you could try to use the command line; shell_exec() will run a command line argument from PHP. The command in the ImageMagick API you'll need to start with is convert example.jpg, and then you can pass flags with the various parameters you want.
Since ImageMagick is already installed, it will work right away. You may need to point your system PATH to the ImageMagick directory where all of the executables are.
There's plenty of questions and forums dedicated to rounded corners with this method so I'll leave that up to you.
Here's a helpful tip though - there is a silly confusion with the convert command, since Windows also has a convert.exe that is rarely used, but will confuse your command line, so make sure you're calling the right convert. ;) To test if it's working, try convert example.jpg example.gif (which should convert your example to a gif).
To get output from your command line, finish all commands with 2>&1 which will pipe cmd output back into PHP.

php reverse imagecreatefromstring

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.

Categories