Find circle and point along circle? - php

I have the following image ontop of an image that is exactly 424x318
And it is wrapped in a div that is 444x338.
And I have a "cropping tool" (the circle center piece) that is 185x185, BUT can resize to be a minimum of 50x50 and a max of about 300x300 (depending on placement).
The cropping tool has a top "border/margin" of 28 px and a left "border/margin" of 20pixels (these are the measurements that take up the tabs, and purple lines and white stuff. However it can be resized, which would increase the border/margin by the resize percentage (so if the entire thing goes to 1.5, the scale would be *1.5).
The cropping tool is also 185x185 WxH total.
The standard position is the center (which is 66x120).
Okay now that we got all those out of the way, I am having a problem trying to find the center & one point that I pass onto imagemagick to process. I currently have the following
// Get variables
$left = $val->pos['0']; // this is posted from jquery, using position();
$top = $val->pos['1']; // this is posted from jquery, using position();
$scale = $val->scale; // this is posted from jquery, using width/185
$img = $val->image; // background image
$h = $scale*185;
// CENTER OF THE CIRCLE
$c1 = ($h*.5)+$left-20;
$c2 = ($h*.5)+$top-10;
// LEFT SIDE
$c3 = $left+(20*$scale)-10;
$c4 = ($h*.5)+$top-10;
$scalesize = $c1.",".$c2." ".$c3.",".$c4;
// Crop Size WxH+X+Y
$cr1 = $h-(40*$scale)-17;
$cr2 = $h-(40*$scale)-14;
$cr3 = $left-(20*$scale)+28;
$cr4 = $top+(20*$scale)-3;
$cropsize = $cr1."x".$cr2."+".$cr3."+".$cr4;
I then pass it onto imagemagick using
$return = exec('convert -size 424x318 xc:none -fill 'filename' -draw "circle '.$scalesize.'" -crop '.$cropsize.' +repage '.newfilename);
I just cannot for the life of me figure out what I am doing wrong. I keep playing with the ##'s that I am subtracting at the end, and it ends up working for one size, but then when I resize the crop tool it messes it all up... Any help?

Try to do one step at a time:
Ensure that your tool crops in the right place (use this: Crop or mask an image into a circle);
Ensure that resize (only) works fine;
Merge those two parts.

If the margin resizes with the scale, then you must scale your constants accordingly.
Something like this:
// CENTER OF THE CIRCLE
$c1 = ($h*.5)+$left-20 * scalesize; // Apply scale to constant
$c2 = ($h*.5)+$top-10 * scalesize; // Apply scale to constant

Related

PHPThumb crop left side and right side of image

I'm trying to get an image and crop it then resize it to a thumbnail using PHPThumb. I want to crop the left side, right side, top and bottom in similar percentages. For example, crop 30% from left and 30% from right side; crop 40% from top bottomwards and 40% from bottom upwards How can I go about it. All I see in the manual is passing the SX value which I suppose only crops it mathematically from the bottom left(where x=0). I need to be able to crop from both sides towards the centre of the image. I hope you get what I mean.
I am using PHPThumb and not something custom since it has good JPEG compression when resizing, therefore the images have the clarity of the originals.
IMPORTANT EDIT: I have been notified that such a feature is not available in PHPThumb, anybody know of any such thumbnaik generator with the above cropping functions?
You could use Imagemagick -shave ( http://www.imagemagick.org/script/command-line-options.php#shave )but would need to calculate the pixels from the percentages first.
Untested code:
$size = getimagesize($input);
$horizontal = round( ($size[0]x0.3), 0);
$vertical = round( $size[1]x0.4), 0);
$cmd = "$input -shave {$horizontal}x{$vertical}";
exec("convert $cmd output.jpg");

How can I trim just the left and right side of an image using Imagemagick in PHP?

I'm trying to trim a variable amount of whitespace in an image only the left and right side using ImageMagick and PHP. Does anyone know how to do this (perhaps using something other than imagemagick?)?
Here's an example.
I have these two images:
Each has a variable amount of text that is dynamically created in a fixed width image.
What I need to do is trim the background off the right and left side so the images come out like this:
If ImageMagick can't do it, I am willing to use something else, but I will need help on how exactly because I am not much of a programmer. Thanks!
Here's my current code that trims all sides of an image:
<?php
/* Create the object and read the image in */
$i = '3';
$im = new Imagick("test".$i.".png");
/* Trim the image. */
$im->trimImage(0);
/* Ouput the image */
//header("Content-Type: image/" . $im->getImageFormat());
//echo $im;
/*** Write the trimmed image to disk ***/
$im->writeImage(dirname(__FILE__) . '/test'.$i.'.png');
/*Display Image*/
echo $img = "<img src=\"test".$i.".png\">";
?>
I think you are on the right track with ImageMagick's -trim operator 1), but the trick would be to get it tell you what it would do without actually doing it, and then modify that to do what you really want...
So, to get the trim-box ImageMagick calculates for your first image, you do this:
convert -fuzz 10% image.jpg -format "%#" info:
60x29+21+31
That is a 60x29 pixel rectangle, offset 21 across and 31 down from the top left corner. Now, we want to get these values into bash variables, so I set the IFS (Input Field Separator) to split fields on spaces, x and also + signs:
#!/bin/bash
IFS=" x+" read a b c d < <(convert -fuzz 10% image.jpg -format "%#" info:)
echo $a $b $c $d
60 29 21 31
Now I can ignore the 29 and the 31 because we are only interested in cropping the width, and crop like this:
convert image.jpg -crop "${a}x+${c}+0" out.jpg
So, for your 2 images, I get these:
and the full procedure is this:
#!/bin/bash
IFS=" x+" read a b c d < <(convert -fuzz 10% image.jpg -format "%#" info:)
convert image.jpg -crop "${a}x+${c}+0" out.jpg
Notes
1) The -format %# is just a shorthand for the -trim operator, which would be this in full
convert image.jpg -trim info:
image.jpg JPEG 72x40 200x100+16+24 8-bit sRGB 0.000u 0:00.000
From what I can see in the ImageMagick docs on cropping and borders, it doesn't seem to be possible.
you can't specify an edge for "intelligent" cropping (known as-trim on the command line), and all the cropping methods that accept a geometry argument need a fixed number for cropping.
The only idea that comes to mind is to get the colour of the shaved area in a separate call, run trimImage, and add the lost areas back using -border.
Edit: The IM manual is suggesting something similar. Check out Trimming Just One Side of an Image. I'm not familiar with IM's PHP extension to translate the code into PHP calls but it should be half-way straightforward.
The GD based library WideImage has something similar. It's called autoCrop, by default it works on all four sides.
However, you could just add another parameter and based on it only crop top/bottom or left/right.
autoCrop code
It's pretty well documented. $img is a WideImage_Image type. There is also an interactive online demo of it.
Related question: Removing black bars off video thumbnail.
Using GD:
function imageautocrop( &$img) {
$emptycol = function ( $img, $x, $min, $max) {
for( $y=$min; $y<$max; $y++) {
$col = imagecolorsforindex( $img, imagecolorat( $img, $x, $y));
if( $col['alpha'] != 127) return false;
}
return true;
}
$trim = Array('top'=>0,'bot'=>0,'lft'=>0,'rgt'=>0);
$size = Array('x'=>imagesx($img)-1,'y'=>imagesy($img)-1);
// code for affecting rows removed due to question asked
while( $emptycol( $img, $trim['lft'], $trim['top'], $size['y']-$trim['bot'])) $trim['lft']++;
while( $emptycol( $img, $size['x']-$trim['rgt'], $trim['top'], $size['y']-$trim['bot'])) $trim['rgt']++;
$newimg = imagecreate( $size['x']-$trim['lft']-$trim['rgt']+1, $size['y']-$trim['top']-$trim['bot']+1);
imagecopy( $newimg, $img, 0, 0, $trim['lft'], $trim['top'], imagesx($newimg)+1, imagesy($newimg)+1);
imagedestroy($img);
$img = $newimg;
}
It's very old code of mine, so probably not optimal, but it does the job.
It is a two step process as text is dynamically generated
Generate the text image, determine width(image)
Overlay text image into background, determine width(background)
Use one tool mentioned above, crop (width(background)-width(image)/2 on either side
The trick is figuring out the width(image). See: How can I auto adjust the width of a GD-generated image to fit the text?
Then again, if you know width(image), you can crop the width(background) first before overlay
Use cropImage() instead. Something like this, perhaps:
$img_x_size = 800; // Set these to relevant values
$img_y_size = 600;
$crop_pixels = 20; // How many pixels to crop
// cropImage(XsizeOfCrop, YsizeOfCrop, CropXPos, CropYPos)
$im->cropImage($img_x_size - $crop_pixels, $img_y_size, 0, $crop_pixels / 2);

ImageMagick: how to draw two strings with different size over image?

I want to draw a rectangle with two strings in it. I want the first string to be 15pt size (its a number), second to be 10pt size (the label). It's easy to draw single string with one size to the rectangle, I do it like this:
$image = new Imagick('someimage.png');
$draw = new ImagickDraw;
$draw->setGravity(Imagick::GRAVITY_CENTER);
$draw->setfont(__DIR__ . DS . 'TREBUCBD.TTF');
$draw->setfontsize(15);
$draw->annotation(0, 0, '50 points');
$image->drawImage($draw);
The idea here is to have "50" in "50 points" to be big.
I tried to do a $draw->push() to push the current settings to the stack then set the font size and annotation again but then the two strings overlap. I've been trying to do this for hours. Any help is very appreciated!
The above implementation is in PHP but probably I will manage to do it even by example that shows it with command line ImageMagick usage.
edit: I've started a bounty that I will award for a solution implemented in PHP.
You can use +append option to make two different text labels joined horizontally (-append - vertically):
convert -background grey -pointsize 15 -fill black label:abc \
-pointsize 10 -fill red label:cdefgh -gravity South +append test.png
This code actually produces two images sized exactly to fit font (since there's no explicit size specified), and then this two images are horizontally appended together:
Once again: the size of this image is calculated automatically to fit your labels. You can use Imagick::labelImage and Imagick::appendImages functions to achieve this. (To make image without background, you can specify -backround transparent, e.g. via Imagick::setBackgroundColor)
After that, resulting image with labels can be composed with anything you want.
Add enough space before "points" and after the "50" so you align them nicely:
<?php
$image = new Imagick('test.png');
$draw = new ImagickDraw;
$draw->setGravity(Imagick::GRAVITY_CENTER);
$draw->setfontsize(30);
$draw->annotation(0, 0, '50 ');
$image->drawImage($draw);
$draw = new ImagickDraw;
$draw->setGravity(Imagick::GRAVITY_CENTER);
$draw->setfontsize(15);
$draw->annotation(0, 0, ' points');
$image->drawImage($draw);
file_put_contents('test.png', $image->getImageBlob());
?>

Resize panoramic image to fixed size

I want to resize the images to fixed width and height (i.e. 150px). However, theres a problem, if there is lots of difference in height and width of original photo (for example, panoramic photo), the resized thumbnail looks bad. Is there any any smart solution to resize the photos to a fixed width and height? For example, please have a look at this
image:
Here's my code:
<?php
$params = getimagesize($tempFile);
$width = $params[0];
$height = $params[1];
$newwidth=150;
$newheight= 150;
$tmp=imagecreatetruecolor($newwidth,$newheight);
imagecopyresampled($tmp,$src,0,0,0,0,$newwidth,$newheight,$width,$height);
imagejpeg($tmp,$img_name,80);
imagedestroy($src);
imagedestroy($tmp);
?>
Is there any smart way to resize the images in smart way?
Thanks.
There's a smart solution, it's called Seam Carving, and if your server supports ImageMagick, you do it like this:
<?php
$im = new Imagick( 'image.jpg' );
$im->liquidRescaleImage( 600, 100, 3, 25 );
header( 'Content-Type: image/jpg' );
echo $im;
?>
Or alternatively, if it doesn't support, use exec() (carefully) in order to pass image as an argument to executable which can perform seam carving.
BTW it looks like twitpic just crop's the squared image extract.
In one of my previous projects I used following code:
if ($image->width > $image->height){
//crop image in proportions 4/3, then resize to 500x300 (or proportionally lower resolution),
//sharp it a little and decrease quality.
//I used one of the Yii framework extensions.
$image->crop($image->width, $image->width/4*3)->resize(500, 300, Image::WIDTH)->sharpen(15)->quality(75);
}
It looks like twitpic is finding out how long the short axis is, then takes a square centered on the original image with sides equal to the short axis length, then shrinking that down to 150x150.
Not, resmaple, get only center 150x150 pixels.
You will need to calculate the appropriate coordinates for the original area you want to copy:
imagecopyresampled($tmp,$src,0,0,[THIS VALUE],[THIS VALUE],$newwidth,$newheight, [THIS VALUE],[THIS VALUE]);
As of now, you take the area from 0,0 (x,y) to width,height (x,y) of the original area and try to cramp it into 150x150.
you will need to calculate which of width and height that is the "biggest" and crop that and make sure that the ratio is the same as your resulting image (in your case, ratio is 1.0 because of 150x150).
In your example, where width is 1050 and height is 317 pixels so you want a portion of the original image that is 317x317 (ratio 1.0), you need to:
subtract 317 from 1050 = 733; // this is the excessive area for both sides
divide by 2 =~ 366; // to get the excessive area for one side
Now, use first x coordinate 366, to start 366 pixels from the left.
Use second x coordinate 1050 - 366 start 366 pixels from the right.
So your example should be (just guessing here):
imagecopyresampled($tmp,$src,0,0,366,0,$newwidth,$newheight, $width - 366, 0);
You will of course need some logic in order to calculate this correctly for any other size.

Php Gd rotate image

HEllo,
I am trying to rotate a circular image around the center and then cut off the sides. I see the imagerotate function, but it does not seem to rotate about centre.
Anyone have any suggestions?
Thank you.
Update: Since it is a circle, I want to cut off the edges and keep my circle in the same dimensions.
The documentation says that it does rotate around the center.
Unfortunately it also says that it will scale the image so that it still fits. That means that whatever you do this function will change the size of your internal circular image.
You could (relatively easily) calculate how much scaling down will happen and then prescale the image up appropriately beforehand.
If you have the PHP "ImageMagick" functions available you can use those instead - they apparently don't scale the image.
I faced successfully that problem with the following code
$width_before = imagesx($img1);
$height_before = imagesy($img1);
$img1 = imagerotate($img1, $angle, $mycolor);
//but imagerotate scales, so we clip to the original size
$img2 = #imagecreatetruecolor($width_before, $height_before);
$new_width = imagesx($img1); // whese dimensions are
$new_height = imagesy($img1);// the scaled ones (by imagerotate)
imagecopyresampled(
$img2, $img1,
0, 0,
($new_width-$width_before)/2,
($new_height-$height_before)/2,
$width_before,
$height_before,
$width_before,
$height_before
);
$img1 = $img2;
// now img1 is center rotated and maintains original size
Hope it helps.
Bye
According to the PHP manual imagerotate() page:
The center of rotation is the center
of the image, and the rotated image is
scaled down so that the whole rotated
image fits in the destination image -
the edges are not clipped.
Perhaps the visible center of the image is not the actual center?

Categories