php imagick setGravity function doesn't work with compositeImage() function - php

I'm using php Imagick class for a project
I try to composite an image changing the gravity of the image
What I mean is, I want to composite the target image to middle or to the top center
I use
....
$imageOrg->setGravity(imagick::GRAVITY_CENTER); //I wrote this for an example, position will be set by the visitor
$imageOrg->compositeImage($over, Imagick::COMPOSITE_DEFAULT, 0, 0);
....
But either setGravity() or setImageGravity() functions don't work.
Please help!

$imageOrg->compositeImage($over, Imagick::COMPOSITE_DEFAULT, (((($imageOrg->getImageWidth()) - ($over->getImageWidth())))/2), (((($imageOrg->getImageHeight()) - ($over->getImageHeight())))/2));
Basically what you're doing is setting the left offset of your image to your Container's width, minus your composite image's width, divided by two, this will offset it enough to center horizontally. Then you do the exact same thing for the height, and it's centered vertically.
I had the same type of problem, best I can figure Gravity settings only apply to Drawing contexts, ie: Text, annotations

Related

PHP: How do I change a color in an 8 bit PNG (png has transparency) using GD Library

I have an 8 bit PNG (original is here: https://i.ibb.co/s3024Y8/1000x1500-autumn-leaves.png) and I want to change the colour of the leaves.
I have a list of the hex colours that need to be changed and a list of the colours they need to be changed to - all to be done dynamically. I'm working towards a solution that has to work off those lists - but that can wait. For this question, being able to change the colour of just one leaf will do.
After changing the colour of the leaf I need the image to retain its transparent areas (so I can lay it on top of another image - that part I can do).
I am quite new to the GD library and am getting confused. I understand that an 8-bit PNG (as created in Photoshop) has full alpha - and that needs to be preserved.
That leads me to the start of my code:
$im = ImageCreateFromPNG('https://i.ibb.co/s3024Y8/1000x1500-autumn-leaves.png');
ImageAlphaBlending($im, false);
imagesavealpha($im, true);
Everything I've tried after that fails miserably. By that, I mean that the colour doesn't change. No error message, just no change in colour. It seems that the following has no effect when using that image:
$myColourToChange = imagecolorallocatealpha($im, 100, 24, 11, 0); // colour of dark brown leaf
imagecolorset($im, $myColourToChange, 255, 0, 0, 0); // try changing it to red, fully opaque
I've even tried (which gives 6559755)
$myColourToChange = imagecolorresolvealpha($im, 100, 24, 11, 0);
I think things are failing (ie the colour doesn't change) because the image I'm using isn't a paletted image in the way that GD needs it to be, in order for me to use imagecolorset
I've tried converting it to one using imagetruecolortopalette but that gives unpredictable results on the image, with all sorts of artifacts not visibly present in the original image - and the colour values change slightly.
Note that the following are representations if you want to experiment, use the image link above.
Original image before imagetruecolortopalette - dark brown leaf colour: #64180B
After imagetruecolortopalette - dark brown leaf colour: #631A0C
So how do I specify the colour that needs to be changed and then change it to the given colour? If it means I must use imagetruecolortopalette how do I deal with the artifacts and the colour change I get when using it?
(I won't know in advance the location of colours that need changing, so imagecolorat won't help)
Thanks in advance :)

How to create png from array of pixel color data in PHP?

Lets say I have an arrays of pixels. Basically an array of this data {x,y,r,g,b,a} for each pixel.
How would I go about converting all this data into an actual image file (png preferably)?
Could not find a solution. Any help would be very appreciated.
I had some time to code up a little example. You should be able to see and note that:
the red component increases towards the bottom of the image
the green component increases towards the right of the image
the blue component is absent
the alpha channel is random and between 0 (opaque) and 127 (fully transparent)
// Define width and height
$w=800;
$h=600;
// Create truecolour image so we can have infinitely many colours rather than a limited palette
$img=imagecreatetruecolor($w,$h);
imagesavealpha($img,true);
imagealphablending($img,false);
// Iterate over all pixels
for($y=0;$y<$h;$y++){
for($x=0;$x<$w;$x++){
$r = round(255*$y/$h);
$g = round(255*$x/$w);
$b = 0;
$alpha = rand(0,127);
$color = imagecolorallocatealpha($img,$r,$g,$b,$alpha);
imagesetpixel($img,$x,$y,$color);
}
}
// Save result
imagepng($img,"result.png");
I'll admit I haven't actually used this API, but looks like PHP has what you're looking for.
You create an image identifier with imagecreate or one of the related functions, then color in each pixel with imagesetpixel, using a color identifier created with imagecolorallocatealpha. From there you should be able to output as a PNG with imagepng.
It's worth noting that this image library seems to support drawing lines and shapes and other structures higher than the per-pixel level, so I'd also look into whether your code necessarily needs to build a big pixel array, rather than drawing the image some other way.

PHP ImageMagick positioning center aligned text

I am using PHP ImageMagick (Imagick) for creating images consisting of multiple images and texts, uploaded and added by visitors of my website. It's actually a kind of canvas where a user can upload their images, position them, optionally add some text and after a click on the button, all the images and texts will be bundled to one image.
Everything works fine, but right now I want to add another feature: text-align: center. I want my user to be abled to add text aligned in the center.
For adding normal (left aligned) text is use this code:
$text_temp = new ImagickDraw();
$text_temp->setGravity(Imagick::GRAVITY_NORTHWEST);
...
$image->annotateImage($text_temp, $new_left, $new_top, $angle, html_entity_decode($item->text));
$new_left, $new_top, $angle are calculated in between and are correct. When I left align the text, this are the results:
Input and output as they should be
But, here comes the problem. I want the text to be centered. So I changed my code to this:
$text_temp = new ImagickDraw();
if($item->textalign == 'center') {
$text_temp->setGravity(Imagick::GRAVITY_NORTHWEST);
$text_temp->setTextAlignment(Imagick::ALIGN_CENTER);
}
...
$image->annotateImage($text_temp, $new_left, $new_top, $angle, html_entity_decode($item->text));
The text is indeed centered, but the position is not correct anymore.
See the input and output results: Strange positions when text is aligned in the center
The reason I use setGravity is because I can position the text from the top left. But right now it looks like it's positioning from the center again and I have no idea what I'm doing wrong.
The $new_left and $new_top variables are positive numbers, multiplied by a positive factor, so there is no way the x- or the y-positions are negative.
Does anyone have an idea?
UPDATE:
#MarkSetchell Thanks for your reply, it putted me in the right direction. I didn't do it exactly like you, but I fixed the problem by adding a wrapper (span) around the user text. I already saved the width and height of images, so it was easy to do the same with texts. With these information I can determine the center of the text, and thus position it from center. This worked for horizontal positioning:
$text_temp->setTextAlignment(Imagick::ALIGN_CENTER);
$new_left = $new_left + ($new_width / 2);
//$new_top = $new_top + ($new_height / 2);
$new_top = $new_top + ($new_fontsize);
But it didn't for vertical positioning. Still don't know why, but I handle it now as if I position from top (not center). Then add one time the font size of the text. I can't explain why this is working, but it works. Can somebody tell me?

php image filter "colorize" destroys image details

i am trying to to colorize a black and white picture on my server.
i have tried doing this with multiple methods and the only one that kind-of-works is gd imagefilter via filter IMG_FILTER_COLORIZE.
it does kind of colorize the image in exactly the same color that i want, but it loses all the details on the image, as if it just trimmed black dots that were not black enough and thinned all the black lines, making them almost invisible. here is what i'm talking about:
this result was achieved with this code
$im=imagecreatefromjpeg($orig_file);
imagefilter($im, IMG_FILTER_COLORIZE, 71, 92, 10);
imagejpeg($im, $output_file, 95);
why is this happening? are there any other methods how i could colorize the image? my original image is quite large and i can't iterate over it as it is too slow; that's why i'm trying to use a library that would do this
i have managed to achieve the desired result with help of Imagick and compositeImage. here is the result
how i achieved it is kind of a trick that works only in a very specific condition- which is the need to have the background white and only black/gray objects in front (or the exact opposite). this technique wouldn't work on a background with transparency
the idea is to have 2 layers- underneath is the layer with original grayscale image and the top layer- fully filled with the desired color. then you composite these images using "COMPOSITE_LIGHTEN" (you might use other methods, like darken for example- if you have white objects on a black background)
this is the code
$base_color="#475c0a";
$im=new Imagick($orig_file);
$im2 = new Imagick();
$im2->newImage($im->getImageWidth(), $im->getImageHeight(), new ImagickPixel($base_color) );
$im->compositeImage($im2, Imagick::COMPOSITE_LIGHTEN, 0, 0);
$im->writeImage($new_image_path);
hope this will help someone out

Rotate image *without* resizing it

I would like to rotate an image (with a user-defined angle of rotation), but without making the image smaller.
is what happens already, saving the shaded area as a smaller image
is what I would like, the dashed line being the new image size.
The server has PHP 5.3+. Links, code and explanations all very welcome.
This is not complete answer but I would take the four corners as coordinates rotate them by your angle and then calculate the new bounding box based on the extent of the new coordinates.
(assuming coordinates with origin on the bottom left).
corners = rotate_each ( [(left,top) (left,bottom), (right,top), (right,bottom)], angle)
new_bb_left = min([corners[0].x, corners[1].x, corners[2].x, corners[3].x])
new_bb_right = max([corners[0].x, corners[1].x, corners[2].x, corners[3].x])
new_bb_bottom = min([corners[0].y, corners[1].y, corners[2].y, corners[3].y])
new_bb_top = max([corners[0].y, corners[1].y, corners[2].y, corners[3].y])
This could be a way to do it. Calculate the diagonal width.
PHP has a Square root function: http://se2.php.net/manual/en/function.sqrt.php
In that way you should have the diagonal width which you could apply on the transformed image.
There are many solutions including the trigonometric formulas but this library seems to be the shortcut.
http://wideimage.sourceforge.net/
Example: http://wideimage.sourceforge.net/wp-content/current/demo/index.php?demo=rotate&output=preset%20for%20demo&colors=255&dither=1&match_palette=1

Categories