How to put water mark on image without affecting the source image.
$SourceFile = '/uploadedimage/gallery/thumble/';
$DestinationFile = '/uploadedimage/gallery/thumble/image-watermark.jpg';
$WaterMarkText = 'Copyright appsbee.com';
watermarkImage ($SourceFile, $WaterMarkText, $DestinationFile);
function watermarkImage ($SourceFile, $WaterMarkText, $DestinationFile) {
list($width, $height) = getimagesize($SourceFile);
$image_p = imagecreatetruecolor($width, $height);
$image = imagecreatefromjpeg($SourceFile);
imagecopyresampled($image_p, $image, 0, 0, 0, 0, $width, $height, $width, $height);
$black = imagecolorallocate($image_p, 0, 0, 0);
$font = 'arial.ttf';
$font_size = 10;
imagettftext($image_p, $font_size, 0, 10, 20, $black, $font, $WaterMarkText);
if ($DestinationFile<>'') {
imagejpeg ($image_p, $DestinationFile, 100);
} else {
header('Content-Type: image/jpeg');
imagejpeg($image_p, null, 100);
};
imagedestroy($image);
imagedestroy($image_p);
};
If I do this the image which are present on thumble folder are effected.
Use this class, before putting water mark just make the copy of original image.
<?php
class Watermark{
# given two images, return a blended watermarked image
# given two images, return a blended watermarked image
function create_watermark( $main_img_obj, $watermark_img_obj, $alpha_level = 100 ) {
$alpha_level /= 100; # convert 0-100 (%) alpha to decimal
# calculate our images dimensions
$main_img_obj_w = imagesx( $main_img_obj );
$main_img_obj_h = imagesy( $main_img_obj );
$watermark_img_obj_w = imagesx( $watermark_img_obj );
$watermark_img_obj_h = imagesy( $watermark_img_obj );
# determine center position coordinates
$main_img_obj_min_x = floor( ( $main_img_obj_w / 2 ) - ( $watermark_img_obj_w / 2 ) );
$main_img_obj_max_x = ceil( ( $main_img_obj_w / 2 ) + ( $watermark_img_obj_w / 2 ) );
$main_img_obj_min_y = floor( ( $main_img_obj_h / 2 ) - ( $watermark_img_obj_h / 2 ) );
$main_img_obj_max_y = ceil( ( $main_img_obj_h / 2 ) + ( $watermark_img_obj_h / 2 ) );
# create new image to hold merged changes
$return_img = imagecreatetruecolor( $main_img_obj_w, $main_img_obj_h );
# walk through main image
for( $y = 0; $y < $main_img_obj_h; $y++ ) {
for( $x = 0; $x < $main_img_obj_w; $x++ ) {
$return_color = NULL;
# determine the correct pixel location within our watermark
$watermark_x = $x - $main_img_obj_min_x;
$watermark_y = $y - $main_img_obj_min_y;
# fetch color information for both of our images
$main_rgb = imagecolorsforindex( $main_img_obj, imagecolorat( $main_img_obj, $x, $y ) );
# if our watermark has a non-transparent value at this pixel intersection
# and we're still within the bounds of the watermark image
if ( $watermark_x >= 0 && $watermark_x < $watermark_img_obj_w &&
$watermark_y >= 0 && $watermark_y < $watermark_img_obj_h ) {
$watermark_rbg = imagecolorsforindex( $watermark_img_obj, imagecolorat( $watermark_img_obj, $watermark_x, $watermark_y ) );
# using image alpha, and user specified alpha, calculate average
$watermark_alpha = round( ( ( 127 - $watermark_rbg['alpha'] ) / 127 ), 2 );
$watermark_alpha = $watermark_alpha * $alpha_level;
# calculate the color 'average' between the two - taking into account the specified alpha level
$avg_red = $this->_get_ave_color( $main_rgb['red'], $watermark_rbg['red'], $watermark_alpha );
$avg_green = $this->_get_ave_color( $main_rgb['green'], $watermark_rbg['green'], $watermark_alpha );
$avg_blue = $this->_get_ave_color( $main_rgb['blue'], $watermark_rbg['blue'], $watermark_alpha );
# calculate a color index value using the average RGB values we've determined
$return_color = $this->_get_image_color( $return_img, $avg_red, $avg_green, $avg_blue );
# if we're not dealing with an average color here, then let's just copy over the main color
} else {
$return_color = imagecolorat( $main_img_obj, $x, $y );
} # END if watermark
# draw the appropriate color onto the return image
imagesetpixel( $return_img, $x, $y, $return_color );
} # END for each X pixel
} # END for each Y pixel
# return the resulting, watermarked image for display
return $return_img;
} # END create_watermark()
# average two colors given an alpha
function _get_ave_color( $color_a, $color_b, $alpha_level ) {
return round( ( ( $color_a * ( 1 - $alpha_level ) ) + ( $color_b * $alpha_level ) ) );
} # END _get_ave_color()
# return closest pallette-color match for RGB values
function _get_image_color($im, $r, $g, $b) {
$c=imagecolorexact($im, $r, $g, $b);
if ($c!=-1) return $c;
$c=imagecolorallocate($im, $r, $g, $b);
if ($c!=-1) return $c;
return imagecolorclosest($im, $r, $g, $b);
} # EBD _get_image_color()
} # END watermark API
?>
and this is how to use it
$watermark = new Watermark();
$actual_image = imagecreatefromjpeg("images/$image_file");
$watermark_image = imagecreatefrompng("images/water_mark.png");
//create water marked image with 66% transparency
$return_img_obj = $watermark->create_watermark( $actual_image, $watermark_image, 66 );
//now save the updated image
imagejpeg($return_img_obj,"images/$image_file1");
//clear the memory
imagedestroy($actual_image);
imagedestroy($watermark_image);
imagedestroy($return_img_obj);
without affecting the source image.
Doing this without affecting the actual image is possible only by adding a HTML layer containing a transparent image. That is pretty useless as a means of protection though, because everyone with a tiny bit of technical knowledge can fetch the original image in seconds.
If you don't want to affect the source image, then I'd recommend putting a transparent image in an absolutely positioned div over the image in your HTML. This means you don't have to process an image on each page load (because you want to keep the original intact), and you don't have to mess about with storing an extra image.
Using the GD image library: http://php.net/manual/en/book.image.php
This way I would create a web watermark version of the image and also store the source image.
Unless you mean to add a watermark on the fly in which case I'm not sure you can that easily.
From the first sight, I think this code will not affect the source file if u didn't provide a destination file name to the function.
Related
I am trying to put an png overlay over an underlying png file.
The script works just fine, but instead of giving me the overlay colored as it should be, it is outputting it in gray color.
But only the overlay image is gray (bg-color of the overlay, which is basically a border for the underlying image: RGB 20,114,158). And it's 24-bit from PS.
The transparency part (white) works just fine.
<?php
$im = imagecreatefrompng($sourceFile);
$overlay = imagecreatefrompng($overlayFile);
$white = imagecolorallocate($overlay, 255, 255, 255);
imagecolortransparent($overlay, $white);
imagecopymerge($im, $overlay, 0, 0, 0, 0, 173, 173,100);
header('Content-Type: image/png');
imagepng($im);
?>
Any help is much appreciated!
Cheers
Chris
You should just using imagecopy() (you use 100 for the last argument ($pct) of imagecopymerge()).
pct
The two images will be merged according to pct which can range from 0 to 100.
When pct = 0, no action is taken, when 100 this function behaves identically to
imagecopy() for pallete images, except for ignoring alpha components, while it
implements alpha transparency for true colour images.
And don't forget to enable imagealphablending() on both images.
Can you try this (not my code):
<?php
/**
* PNG ALPHA CHANNEL SUPPORT for imagecopymerge();
* This is a function like imagecopymerge but it handle alpha channel well!!!
**/
// A fix to get a function like imagecopymerge WITH ALPHA SUPPORT
// Main script by aiden dot mail at freemail dot hu
// Transformed to imagecopymerge_alpha() by rodrigo dot polo at gmail dot com
function imagecopymerge_alpha($dst_im, $src_im, $dst_x, $dst_y, $src_x, $src_y, $src_w, $src_h, $pct){
if(!isset($pct)){
return false;
}
$pct /= 100;
// Get image width and height
$w = imagesx( $src_im );
$h = imagesy( $src_im );
// Turn alpha blending off
imagealphablending( $src_im, false );
// Find the most opaque pixel in the image (the one with the smallest alpha value)
$minalpha = 127;
for( $x = 0; $x < $w; $x++ )
for( $y = 0; $y < $h; $y++ ){
$alpha = ( imagecolorat( $src_im, $x, $y ) >> 24 ) & 0xFF;
if( $alpha < $minalpha ){
$minalpha = $alpha;
}
}
//loop through image pixels and modify alpha for each
for( $x = 0; $x < $w; $x++ ){
for( $y = 0; $y < $h; $y++ ){
//get current alpha value (represents the TANSPARENCY!)
$colorxy = imagecolorat( $src_im, $x, $y );
$alpha = ( $colorxy >> 24 ) & 0xFF;
//calculate new alpha
if( $minalpha !== 127 ){
$alpha = 127 + 127 * $pct * ( $alpha - 127 ) / ( 127 - $minalpha );
} else {
$alpha += 127 * $pct;
}
//get the color index with new alpha
$alphacolorxy = imagecolorallocatealpha( $src_im, ( $colorxy >> 16 ) & 0xFF, ( $colorxy >> 8 ) & 0xFF, $colorxy & 0xFF, $alpha );
//set pixel with the new color + opacity
if( !imagesetpixel( $src_im, $x, $y, $alphacolorxy ) ){
return false;
}
}
}
// The image copy
imagecopy($dst_im, $src_im, $dst_x, $dst_y, $src_x, $src_y, $src_w, $src_h);
}
// USAGE EXAMPLE:
$img_a = imagecreatefrompng('image1.png');
$img_b = imagecreatefrompng('wm2.png');
// SAME COMMANDS:
imagecopymerge_alpha($img_a, $img_b, 10, 10, 0, 0, imagesx($img_b), imagesy($img_b),50);
// OUTPUT IMAGE:
header("Content-Type: image/png");
imagesavealpha($img_a, true);
imagepng($img_a, NULL);
?>
Src: http://www.php.net/manual/en/function.imagecopymerge.php#88456
I am trying to layer a partially transparent PNG on top of another opaque PNG.
There are many example of how to do this across this site and the net, however with every version I try I seem to not be able to maintain the foreground image's transparency.
Currently the code looks like this:
$image = imagecreatefrompng($_GET['fg']);
$frame = imagecreatefrompng($_GET['bg']);
imagealphablending($frame,true);
imagecopymerge($image, $frame, 0, 0, 0, 0, 0, 100, 100);
# Save the image to a file
$output_file = 'preview-' . time() . '.png';
imagepng( $image, $_SERVER['DOCUMENT_ROOT'] . '/share/' . $output_file );
Which produces an image made up of the foreground image with the transparent parts as white (or black).
Also I have tried this as seen in the image thumbnail generator, TimThumb, which produces the same output:
$canvas= imagecreatefrompng($_GET['bg']);
$overlay_gd_image = imagecreatefrompng( $_GET['fg'] );
$overlay_width = imagesx( $overlay_gd_image );
$overlay_height = imagesy( $overlay_gd_image );
imagealphablending($canvas, true );
imagecopy( $canvas, $overlay_gd_image, 0, 0, 0, 0, $overlay_width, $overlay_height);
imagealphablending($canvas, false );
imagesavealpha($canvas , true);
imagepng($canvas, 'new.png');
I am running out of things to try and would be grateful if anyone could shed light on the problem.
The native imagecopymerge doesn't really work so well when it comes to transparent images. If you want to merge two PNG's together and not have the alpha channel get messed up, this function found on the manual page works like a charm for me and actually preserves transparency. I have been merging PNGs nonstop with this function and have not had a problem so I think it could solve yours.
(Posted by "rodrigo dot polo at gmail dot com", so all credits to him/her.)
<?php
/**
* PNG ALPHA CHANNEL SUPPORT for imagecopymerge();
* This is a function like imagecopymerge but it handle alpha channel well!!!
**/
// A fix to get a function like imagecopymerge WITH ALPHA SUPPORT
// Main script by aiden dot mail at freemail dot hu
// Transformed to imagecopymerge_alpha() by rodrigo dot polo at gmail dot com
function imagecopymerge_alpha($dst_im, $src_im, $dst_x, $dst_y, $src_x, $src_y, $src_w, $src_h, $pct){
if(!isset($pct)){
return false;
}
$pct /= 100;
// Get image width and height
$w = imagesx( $src_im );
$h = imagesy( $src_im );
// Turn alpha blending off
imagealphablending( $src_im, false );
// Find the most opaque pixel in the image (the one with the smallest alpha value)
$minalpha = 127;
for( $x = 0; $x < $w; $x++ )
for( $y = 0; $y < $h; $y++ ){
$alpha = ( imagecolorat( $src_im, $x, $y ) >> 24 ) & 0xFF;
if( $alpha < $minalpha ){
$minalpha = $alpha;
}
}
//loop through image pixels and modify alpha for each
for( $x = 0; $x < $w; $x++ ){
for( $y = 0; $y < $h; $y++ ){
//get current alpha value (represents the TANSPARENCY!)
$colorxy = imagecolorat( $src_im, $x, $y );
$alpha = ( $colorxy >> 24 ) & 0xFF;
//calculate new alpha
if( $minalpha !== 127 ){
$alpha = 127 + 127 * $pct * ( $alpha - 127 ) / ( 127 - $minalpha );
} else {
$alpha += 127 * $pct;
}
//get the color index with new alpha
$alphacolorxy = imagecolorallocatealpha( $src_im, ( $colorxy >> 16 ) & 0xFF, ( $colorxy >> 8 ) & 0xFF, $colorxy & 0xFF, $alpha );
//set pixel with the new color + opacity
if( !imagesetpixel( $src_im, $x, $y, $alphacolorxy ) ){
return false;
}
}
}
// The image copy
imagecopy($dst_im, $src_im, $dst_x, $dst_y, $src_x, $src_y, $src_w, $src_h);
}
// USAGE EXAMPLE:
$img_a = imagecreatefrompng('image1.png');
$img_b = imagecreatefrompng('wm2.png');
// SAME COMMANDS:
imagecopymerge_alpha($img_a, $img_b, 10, 10, 0, 0, imagesx($img_b), imagesy($img_b),50);
// OUTPUT IMAGE:
header("Content-Type: image/png");
imagesavealpha($img_a, true);
imagepng($img_a, NULL);
?>
If you use the example, you'll see that $img_a would be below $img_b and instead of having a weird black box, $img_b's transparency would be preserved.
I had exactly the same issue. The solution for me was to use imagecopyresampled instead of imagecopymerge. This will preserve transparency for both images.
be aware of the slightly different parameters to pass
I'm trying to create thumbnail and resize image at the same time, so to be more clear here is the image that i'm trying to crop:
And i would like to cut out that red area.
Now my problem is that i'm resizing my image with html before croping so when i submit data to php i get incorrect values, like y = 100 when realy it could be y = 200 so i need to find a way to calculate my values.
I am using imagecopyresampled, maybe there is something better then this command?
Also my closest soliution was this:
imagecopyresampled(
$thumb, //Destination image link resource.
$src, //Source image link resource.
0, //x-coordinate of destination point.
0, //y-coordinate of destination point.
0, //x-coordinate of source point.
0, //y-coordinate of source point.
120, //Destination width.
160, //Destination height.
$image_width/2, //Source width.
$image_height/2 //Source height.
);
In this case it would cut out left corner but size would be not the same as my red box.
So i guess i need to get source width and source height right and everything else should fit perfectly, anyways i hope i make any sense here :)
EDIT Sorry i forgot to mention, $image_width and $image_height is the original image size
EDIT 2 To be more clear this is what i get when i resize with this code
$dimensions = getimagesize('testas.jpg');
$img = imagecreatetruecolor(120, 160);
$src = imagecreatefromjpeg('testas.jpg');
imagecopyresampled($img, $src, 0, 0, 0, 0, 120, 160, $dimensions[0]/2, $dimensions[1]/2);
imagejpeg($img, 'test.jpg');
Resized image size is correct, but as you can it doesn't look right.
I use something like this to scale images:
public static function scaleProportional($img_w,$img_h,$max=50)
{
$w = 0;
$h = 0;
$img_w > $img_h ? $w = $img_w / $img_h : $w = 1;
$img_h > $img_w ? $h = $img_h / $img_w : $h = 1;
$ws = $w > $h ? $ws = ($w / $w) * $max : $ws = (1 / $h) * $max;
$hs = $h > $w ? $hs = ($h / $h) * $max : $hs = (1 / $w) * $max;
return array(
'width'=>$ws,
'height'=>$hs
);
}
usage:
$getScale = Common::scaleProportional($prevWidth,$prevHeight,$scaleArray[$i][1]);
$targ_w = $getScale['width'];
$targ_h = $getScale['height'];
$jpeg_quality = 100;
$src = $prevdest;
$img_r = imagecreatefromjpeg($src);
$dst_r = ImageCreateTrueColor( $targ_w, $targ_h );
//imagecopyresampled(dest_img,src_img,dst_x,dst_y,src_x,src_y,dst_w,dst_h,src_w,src_h);
imagecopyresampled($dst_r,$img_r,0,0,0,0,$targ_w,$targ_h,$prevWidth,$prevHeight);
imagejpeg($dst_r, 'assets/images/'.$scaleArray[$i][0].'/'.$filename, $jpeg_quality);
$complete[] = $scaleArray[$i][0];
When you say 'resizing with HTML', do you mean specifying the size using the width and height attributes of the img element? If so, this won't affect the dimensions of the file on the server, and you can still get those using getimagesize.
Something like this will return the source width and height of the image:
function get_source_size($the_file_path)
{
$imagesize = getimagesize($the_file_path);
return array('width' => $imagesize[0], 'height' => $imagesize[1]);
}
So after some time i was able to do it with my friend help, this is the script i used, maybe some one will need it in the future :)
private function crop($user, $post){
//get original image size
$dimensions = getimagesize($post['image_src']);
//get crop box dimensions
$width = $post['w'] * ($dimensions[0] / $post['img_width']);
$height = $post['h'] * ($dimensions[1] / $post['img_height']);
//get crop box offset
$y = $post['y'] * ($dimensions[1] / $post['img_height']);
$x = $post['x'] * ($dimensions[0] / $post['img_width']);
//create image 120x160
$img = imagecreatetruecolor(120, 160);
$src = imagecreatefromjpeg($post['image_src']);
imagecopyresampled($img, $src, 0, 0, $x, $y, 120, 160, $width, $height);
//and save the image
return imagejpeg($img, 'uploads/avatars/'.$user->id.'/small/'.$post['image_name'].".jpg" , 100);
}
I'm using jQuery's imgAreaSelect plugin in order to crop an image and save the thumbnail to use in cases where, for example, the ratio changes. Unfortunelly the results are far from what I would expect, and I can't get it right. The image gets resized as a whole instead of being cropped.
Here's the test example :
<?php
/***
*
* $_GET returned values
*
* x1 = 0
* x2 = 400
* y1 = 66
* y2 = 258
* w = 400
* h = 192
* folder = widethumb
* filename = IMG_4591.jpg
* scale = 48
*
* Original image properties
*
* width = 600px
* height = 900px
*
***/
define('DOCROOT', realpath(dirname(__FILE__)).DIRECTORY_SEPARATOR);
extract($_GET);
$fn = $filename;
$filename = DOCROOT.$filename;
list($width, $height) = getimagesize($filename);
$src = imagecreatefromjpeg($filename);
$dst = imagecreatetruecolor($w, $h);
imagecopyresampled($dst, $src, 0, 0, (int) $x1, (int) $y1, (int) $w, (int) $h, $width, $height);
header('Content-Type: image/jpeg');
imagejpeg($dst);
What am I mising here?
Cheers!
From PHP Documentation:
bool imagecopyresampled ( resource $dst_image , resource $src_image , int $dst_x , int $dst_y , int $src_x , int $src_y , int $dst_w , int $dst_h , int $src_w , int $src_h )
imagecopyresampled() copies a rectangular portion of one image to another image, smoothly interpolating pixel values so that, in particular, reducing the size of an image still retains a great deal of clarity.
In other words, imagecopyresampled() will take an rectangular area from src_image of width src_w and height src_h at position (src_x,src_y) and place it in a rectangular area of dst_image of width dst_w and height dst_h at position (dst_x,dst_y).
So to get the result you are looking for, you need to avoid scaling. for that use:
imagecopy($dst, $src, 0, 0, $x1, $y1, $w, $h);
// this can also be done but is less efficient (over 10 times slower)
imagecopyresampled($dst, $src, 0, 0, (int) $x1, (int) $y1, $w, $h, $w, $h);
Here we are are taking the same sized rectangle from source as we are putting it into destination image.
I have just tested it and it works just fine.
Update:
I have just tried again on my test server and it is working fine. I'm using following code:
$filename = "test.jpg";
extract($_GET);
$src = imagecreatefromjpeg($filename);
$dst = imagecreatetruecolor($w, $h);
imagecopy($dst, $src, 0, 0, $x1, $y1, $w, $h);
// this is over 10 times slower, as we are only cropping we should use imagecopy
//imagecopyresampled($dst, $src, 0, 0, $x1, $y1, $w, $h, $w, $h);
header('Content-Type: image/jpeg');
imagejpeg($dst);
And I'm calling it like this:
http://localserver/test/gd_crop.php?x1=906&y1=267&w=501&h=355
Performance Update
As we are not resizing we can simply use imagecopy. Performance of 3 functions as i have measured is given below.
imagecopyresampled 69ms
imagecopyresized 5.5ms
imagecopy 4.5ms
So there is an order of 10 speed difference between resampled and the two other functions.
I have finally come up with following line in place of imagecopyresampled function, try it, I have also updated the above code listing:
imagecopy($dst, $src, 0, 0, $x1, $y1, $w, $h);
Use the WideImage library instead.
This is my own cropping function:
function createThumbnail($file, $cropX, $cropY, $cropWidth, $cropHeight, $desiredWidth, $desiredHeight, $shrink = false)
{
if(file_exists(MPS_ROOT_PATH . "$file") && $cropWidth && $cropHeight)
{
$source_path = MPS_ROOT_PATH . $file;
list( $source_width, $source_height, $source_type ) = getimagesize( $source_path );
switch ( $source_type )
{
case IMAGETYPE_GIF:
$source_gdim = imagecreatefromgif( $source_path );
break;
case IMAGETYPE_JPEG:
$source_gdim = imagecreatefromjpeg( $source_path );
break;
case IMAGETYPE_PNG:
$source_gdim = imagecreatefrompng( $source_path );
break;
default:
return false;
}
if(!$desiredWidth)
{
// Desired width not set, computing new width based on original
// image's aspect ratio...
$desiredWidth = $cropWidth * ($desiredHeight / $cropHeight);
}
if(!$desiredHeight)
{
// Desired height not set, computing new height based on original
// image's aspect ratio
$desiredHeight = $cropHeight * ($desiredWidth / $cropWidth);
}
if(!$desiredWidth || !$desiredHeight)
{
// Desired height or width not set.
// Halting image processing and returning file
return $file;
}
$source_aspect_ratio = $cropWidth / $cropHeight;
$desired_aspect_ratio = $desiredWidth / $desiredHeight;
if($shrink)
{
// Shrink to fit flag set. Inverting computations to make image fit
// within the desired dimensions...
if($source_aspect_ratio > $desired_aspect_ratio)
{
// Source image is wider than desired aspect ratio,
// setting thumbnail width to the desired width and the height
// will be computed based on the original image's aspect ratio
$temp_width = $desiredWidth;
$temp_height = (int) ($desiredWidth / $source_aspect_ratio);
}
else
{
// Source image is taller than desired aspect ratio,
// setting thumbnail height to the desired height and the width
// will be computed based on the original image's aspect ratio
$temp_height = $desiredHeight;
$temp_width = (int) ($desiredHeight * $source_aspect_ratio);
}
}
// shrink to fit not set
else
{
if($source_aspect_ratio > $desired_aspect_ratio)
{
// Source image is wider than desired aspect ratio,
// setting thumbnail height to the desired height to fill the
// desired aspect ratio and the width will be computed based on
// the original image's aspect ratio
$temp_height = $desiredHeight;
$temp_width = (int) ($desiredHeight * $source_aspect_ratio);
}
else
{
// Source image is taller than desired aspect ratio,
// setting thumbnail width to the desired width to fill the
// desired aspect ratio and the width will be computed based on
// the original image's aspect ratio");
$temp_width = $desiredWidth;
$temp_height = (int) ($desiredWidth / $source_aspect_ratio);
}
}
$temp_gdim = imagecreatetruecolor($temp_width, $temp_height);
// Copying a $cropWidth x $cropHeight image from the source
// file at ($cropX, $cropY) and resampling it to fit the temporary
// $temp_width x $temp_height thumbnail at (0, 0)
imagecopyresampled(
$temp_gdim,
$source_gdim,
0, 0,
$cropX, $cropY,
$temp_width, $temp_height,
$cropWidth, $cropHeight
);
$x0 = ($desiredWidth - $temp_width) / 2;
$y0 = ($desiredHeight - $temp_height) / 2;
// Positioning the temporary $temp_width x $temp_height thumbnail in
// the center of the final $desiredWidth x $desiredHeight thumbnail...
// Creating final thumbnail canvas at $desiredWidth x $desiredHeight
$desired_gdim = imagecreatetruecolor($desiredWidth, $desiredHeight);
$white = imagecolorallocate($desired_gdim, 255, 255, 255);
imagefill($desired_gdim, 0, 0, $white);
// Filling final thumbnail canvas with white
// Copying a $temp_width x $temp_height image from the temporary
// thumbnail at (0, 0) and placing it in the final
// thumbnail at ($x0, $y0)
imagecopy(
$desired_gdim,
$temp_gdim,
$x0, $y0,
0, 0,
$temp_width, $temp_height
);
$pathInfo = pathinfo($file);
$thumbFile = "images/thumbs/thumb_" . basename($pathInfo["filename"]) . ".jpg";
if(imagejpeg($desired_gdim, MPS_ROOT_PATH . $thumbFile, 80))
{
return $thumbFile;
}
else
{
return 1;
}
}
else
{
echo "Image File Does not exist or Invalid crop parameters!";
return false;
}
}
Why don't you look into using imagemagik; it's great for image manipulation and cropping is just a simple case of using cropImage($width, $height, $x, $y);
Here's a function that you can pass the destination dimension to and will scale and crop from the center, maintain aspect ratio, and will scale up. This is easy to implement with the picture element for responsive design. If you change your destination dimensions, just delete the outputted files and this will recreate the images in their absence.
<?php
function scaleCrop($src, $dest, $destW, $destH, $anchor){
if(!file_exists($dest) && is_file($src) && is_readable($src)){
$srcSize = getimagesize($src);
$srcW = $srcSize[0];
$srcH = $srcSize[1];
$srcRatio = $srcW / $srcH;
$destRatio = $destW / $destH;
$img = (imagecreatefromjpeg($src));
$imgNew = imagecreatetruecolor($destW, $destH);
if ($srcRatio < $destRatio){
$scale = $srcW / $destW;
}
elseif($srcRatio >= $destRatio){
$scale = $srcH / $destH;
}
$srcX = ($srcW - ($destW * $scale)) / 2;
if($anchor = 'middle'){
$srcY = ($srcH - ($destH * $scale)) / 2;
}
elseif($anchor = 'top'){
$srcY = 0;
}
elseif($anchor = 'bottom'){
$srcY = $srcH - ($destH * $scale);
}
if($srcX < 0){$srcX = 0;};
if($srcY < 0){$srcY = 0;};
imagecopyresampled($imgNew, $img, 0, 0, $srcX, $srcY, $destW, $destH, $destW * $scale, $destH * $scale);
imagejpeg($imgNew, $dest, 70);
imagedestroy($img);
imagedestroy($imgNew);
}
return $dest;
}
?>
<img src="<?php echo scaleCrop('srcfolder/srcfile.jpg', 'destfolder/destfile.jpg', 320, 240, 'top'); ?>">
Here is my current code:
$image = 'img.jpg';
$source = imagecreatefromjpeg($image);
list($origWidth, $origHeight) = getimagesize($image);
$imgH = 75;
$imgW = $origWidth / $origHeight * $imgH;
$thumb = imagecreatetruecolor($imgW, $imgH);
imagecopyresampled($thumb, $source, 0, 0, 0, 0, $imgW, $imgH, $origWidth, $origHeight);
This allows me to output an image with a fixed height of 75 pixels. What I would like to do is have a constant image size of 99x75 pixels. Portrait images that don't fit into this will be cropped from the center (so the center of the original remains the center of the thumbnail - if that makes sense).
How can I do this?
Well, it's pure math. You want to achieve a 99x75 size, and you want to only cut from the width. So first, you resize to fit the height. That's what you did, but did it to fit a height of 75. Switch it to 99. Then you, check for the width to be <= 75. If it's not then you do this:
if( $imgW > 75 )
{
$diff = $imgw - 75; // this is what's extra
$srcX = ceil( $diff / 2 ); // this is where your img starts from
$imgW = 75;
}
imagecopyresampled($thumb, $source, 0, 0, $srcX, 0, $imgW, $imgH, $origWidth, $origHeight); // notice that src X changed accordingly.
So, if the width after the first "resize" is 100 and you wanted 75, you compute the diff = 25, split it by 2 and ceil it => 13, then you tell the GD function to start copying the image from 13, instead of 0, and still keep 75 height. This means it will copy from width 13 to witdh 88 => the center.
Hope this is what you wanted.
Regards,
Gabriel
define( 'THUMB_WIDTH', 99 );
define( 'THUMB_HEIGHT', 75 );
$image = imagecreatefromjpeg('img.jpg');
$thumb = imagecreatetruecolor(THUMB_WIDTH, THUMB_HEIGHT);
list($image_width, $image_height) = getimagesize($image);
$x0 = ( $image_width - THUMB_WIDTH ) / 2;
$y0 = ( $image_height - THUMB_HEIGHT ) / 2;
imagecopy(
$thumb, // resource $dst_im
$image, // resource $src_im
0, // int $dst_x
0, // int $dst_y
$x0, // int $src_x
$y0, // int $src_y
THUMB_WIDTH, // int $src_w
THUMB_HEIGHT // int $src_h
);
This code uses imagecopy function to copy 99x75px region from the source image. Source width - 99 / 2 returns the x coordinate from which to start copying, Source height - 75 / 2 returns the y coordinate. If you are interested in generating fixed size thumbnails from arbitrary size images, have a look at this article.
(untested)
define('THUMB_WIDTH', 99);
define('THUMB_HEIGHT', 75);
$image = 'img.jpg';
$source = imagecreatefromjpeg($image);
$thumb = imagecreatetruecolor(THUMB_WIDTH, THUMB_HEIGHT);
$cutX = imagesx($source) > THUMB_WIDTH;
$cutY = imagesy($source) > THUMB_HEIGHT;
$source_x = $cutX ? imagesx($source) / 2 - (THUMB_WIDTH/2) : 0;
$source_y = $cutY ? imagesx($source) / 2 - (THUMB_HEIGHT/2) : 0;
$source_width = $cutX ? THUMB_WIDTH : imagesx($source);
$source_height = $cutY ? THUMB_HEIGHT : imagesy($source);
imagecopyresampled($thumb, $source, 0, 0, $source_x, $source_y, $source_width, $source_height, THUMB_WIDTH, THUMB_HEIGHT);