Image resize issue using GD - php

I have successfully resized images using GD library. I resize any image to 350 x 250, the problem is tat some pictures don't look good (stretch) when they are resized as i am resizing them to a fixed size. I have a space of 350 x 250 where resize picture needs to be fit, I don't mind if the pic size is smaller than 350 x 250 as long as it does not stretch. How do i solve this problem?
$save = "$directory/" . $file_name; //This is the new file you saving
$file = "$directory/" . $file_name; //This is the original file
list($width, $height) = getimagesize($file) ;
$modwidth = 350;
if ($width > $height) {
$y = 0;
$x = ($width - $height) / 2;
$smallestSide = $height;
} else {
$x = 0;
$y = ($height - $width) / 2;
$smallestSide = $width;
}
$diff = $width / $modwidth;
$modheight = 250;
$tn = imagecreatetruecolor($modwidth, $modheight) ;
$image = imagecreatefromjpeg($file) ;
imagecopyresampled($tn, $image, 0, 0, 0, 0, $modwidth, $modheight, $width, $height);
imagejpeg($tn, $save, 100) ;

Try using this function I've written some time ago:
public function resize($img, $width, $height, $stretch = false)
{
$temp = imagecreatetruecolor($width, $height);
imagealphablending($temp, true);
imagesavealpha($temp, true);
$bg = imagecolorallocatealpha($temp, 0, 0, 0, 127); // Background color
imagefill($temp, 0, 0, $bg);
if ($stretch)
{
imagecopyresampled($temp, img, 0, 0, 0, 0, $width, $height, imagesx($img), imagesy($img));
}
else
{
if (imagesx($img) <= $width && imagesy($img) <= $height)
{
$fwidth = imagesx($img);
$fheight = imagesy($img);
}
else
{
$wscale = $width / imagesx($img);
$hscale = $height / imagesy($img);
$scale = min($wscale, $hscale);
$fwidth = $scale * imagesx($img);
$fheight = $scale * imagesy($img);
}
imagecopyresampled($temp,
$img,
($width - $fwidth) / 2, ($height - $fheight) / 2,
0, 0,
$fwidth, $fheight,
imagesx($img), imagesy($img)
);
}
return $temp;
}
if you say not to stretch the image, it will calculate a new size making it fit your new size.
use it as:
...
$image = imagecreatefromjpeg($file);
$resized = resize($image, 350, 250, false); // false = don't stretch
imagejpeg($resized, $save, 100);
...
now store $resized on the disk using imagepng() for example.

Related

PHP - Unbelievable Slow Image Processing

I have a function that returns base 64 image from URL. For a list of images (around 100 images - all thumbs), it takes almost 30 sec to complete. Is there anything I can do to speed up PHP image processing function (maybe some way to clear memory...) ?
<?php
// Get new dimensions
$url = "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcTnhDbj3HU9Sh4K71lOfJ9uMjESMTnYqLyJ7QLJf12asOj_o05N&s";;
list($width_orig, $height_orig) = getimagesize($url);
$maxWidth = 220;
$maxHeight = 220;
// Set a maximum height and width
$targetWidth = $maxWidth ? $maxWidth : $width_orig;
$targetHeight = $maxHeight ? $maxHeight : $height_orig;
// Resample
$image_p = imagecreatetruecolor($targetWidth, $targetHeight);
$image = imagecreatefromstring(file_get_contents($url));
$white = imagecolorallocate($image_p, 255, 255, 255);
imagefill($image_p, 0, 0, $white);
$dx = ($targetWidth - $width_orig) / 2;
$dy = ($targetHeight - $height_orig) / 2;
imagecopyresampled($image_p, $image, $dx, $dy, 0, 0, $width_orig, $height_orig, $width_orig, $height_orig);
ob_start();
imagepng($image_p);
$data = ob_get_contents();
imagedestroy($image_p);
imagedestroy($image);
ob_end_clean();
if ($image_p !== false) {
echo "data:image/jpg;base64,".base64_encode($data);
};
?>
Thank you!

Resize image to certain size without cropping with PHP

Original Image:
Desired output: (I added black border for the sack of understanding)
I want to resize image to 200/200 without cropping. See the desired output.
I have this code
<?php
// function created by www.thewebhelp.com
if (!function_exists("create_square_image")) {
function create_square_image($original_file, $destination_file = NULL, $square_size = 96) {
if (isset($destination_file) and $destination_file != NULL) {
if (!is_writable($destination_file)) {
echo '<p style="color:#FF0000">Oops, the destination path is not writable. Make that file or its parent folder wirtable.</p>';
}
}
// get width and height of original image
$imagedata = getimagesize($original_file);
$original_width = $imagedata[0];
$original_height = $imagedata[1];
if ($original_width > $original_height) {
$new_height = $square_size;
$new_width = $new_height * ($original_width / $original_height);
}
if ($original_height > $original_width) {
$new_width = $square_size;
$new_height = $new_width * ($original_height / $original_width);
}
if ($original_height == $original_width) {
$new_width = $square_size;
$new_height = $square_size;
}
$new_width = round($new_width);
$new_height = round($new_height);
// load the image
if (substr_count(strtolower($original_file), ".jpg") or substr_count(strtolower($original_file), ".jpeg")) {
$original_image = imagecreatefromjpeg($original_file);
}
if (substr_count(strtolower($original_file), ".gif")) {
$original_image = imagecreatefromgif($original_file);
}
if (substr_count(strtolower($original_file), ".png")) {
$original_image = imagecreatefrompng($original_file);
}
$smaller_image = imagecreatetruecolor($new_width, $new_height);
$square_image = imagecreatetruecolor($square_size, $square_size);
imagecopyresampled($smaller_image, $original_image, 0, 0, 0, 0, $new_width, $new_height, $original_width, $original_height);
if ($new_width > $new_height) {
$difference = $new_width - $new_height;
$half_difference = round($difference / 2);
imagecopyresampled($square_image, $smaller_image, 0 - $half_difference + 1, 0, 0, 0, $square_size + $difference, $square_size, $new_width, $new_height);
}
if ($new_height > $new_width) {
$difference = $new_height - $new_width;
$half_difference = round($difference / 2);
imagecopyresampled($square_image, $smaller_image, 0, 0 - $half_difference + 1, 0, 0, $square_size, $square_size + $difference, $new_width, $new_height);
}
if ($new_height == $new_width) {
imagecopyresampled($square_image, $smaller_image, 0, 0, 0, 0, $square_size, $square_size, $new_width, $new_height);
}
// if no destination file was given then display a png
if (!$destination_file) {
imagepng($square_image, NULL, 9);
}
// save the smaller image FILE if destination file given
if (substr_count(strtolower($destination_file), ".jpg")) {
imagejpeg($square_image, $destination_file, 100);
}
if (substr_count(strtolower($destination_file), ".gif")) {
imagegif($square_image, $destination_file);
}
if (substr_count(strtolower($destination_file), ".png")) {
imagepng($square_image, $destination_file, 9);
}
imagedestroy($original_image);
imagedestroy($smaller_image);
imagedestroy($square_image);
}
}
create_square_image("image.jpg", "sample_thumb.jpg", 200);
?>
<h2>Original image</h2>
<h2><img src="image.jpg" />
</h2>
<h2>The created square thumbnail</h2>
<h2><img src="sample_thumb.jpg" />
</h2>
But my code is outputting like this
How about using a white image that matches your dimensions? I.e you get a white image that is your desired size (200x200) and merge it with your other image.
// First image is the white image that has the dimension you want.
$image1 = imagecreatefrompng('COLOR.png');
// Second image is the image you want to change size of
$image2 = imagecreatefrompng('SOURCE.png');
// Merge the two, so that the white image is below the "Dress"
// image you showed us in your question.
imagecopymerge($image1, $image2, 0, 0, 0, 0, 161, 200, 100);
// Output and free from memory
header('Content-Type: image/png');
echo imagepng($image1);
// Destroy images
imagedestroy($image1);
imagedestroy($image2);
Parameters for the function:
bool imagecopymerge ( resource $dst_im , resource $src_im , int $dst_x
, int $dst_y , int $src_x , int $src_y , int $src_w , int $src_h , int
$pct )
Last parameter is percentage(alpha) so if you don't want a white backround then you just set it to 0, and it will be transparent.
EDIT: Check out the docs so that you get the correct position for the second image here.
EDIT 2: The above code will produce the following image(provided the color image is black):
I have found the solution that works for both situation whether image is wide or tall.
$whereToPut = "source.jpg"; // This is 200/200 blank white image
$size = getimagesize($fn);
$ratio = $size[0] / $size[1]; // width/height
$dst_y = 0;
$dst_x = 0;
if ($ratio > 1) {
$width = 200;
$height = 200 / $ratio;
$dst_y = (200 - $height) / 2;
} else {
$width = 200 * $ratio;
$height = 200;
$dst_x = (200 - $width) / 2;
}
$src = imagecreatefromstring(file_get_contents($fn));
$dst = imagecreatetruecolor($width, $height);
imagecopyresampled($dst, $src, 0, 0, 0, 0, $width, $height, $size[0], $size[1]);
$image1 = imagecreatefromjpeg($whereToPut);
imagecopymerge($image1, $dst, $dst_x, $dst_y, 0, 0, imagesx($dst), imagesy($dst), 100);
imagejpeg($image1, $finalImage);
// $dinalImage is your final created image.

PHP GD Resizing Causes Artifacts

I have a function that I'm using to accept user-uploaded images, proportionally scale it to a have a maximum width/height of 4,000px, and also generate 400px and 800px thumbnails. It needs to be capable of handling transparent PNGs and applying a white background.
My current code does all of this, however, it adds undesirable artifacts not typical of JPEGs. They're vertical striations and look like a very washed out barcode when viewed close up (400% Zoomed Screenshot attached). This even occurs on the original image when uploaded at the size it's being scaled to. It seems to be even more prevalent with transparent PNGs, but happens in white regions of JPEGs as well. JPEGs are being saved with Quality 80.
function resize_image($file, $w, $h, $strict = false, $crop = false, $path = null, $thumbnail = false)
{
// Check for Valid Image + Calculate Ratio
list($width, $height) = getimagesize($file);
if (empty($width) || empty($height))
{
echo json_encode(['result' => 'error', 'error' => 'file_format_invalid']);
http_response_code(405);
exit;
}
$r = $width / $height;
if (!$strict)
{
$w = min($w, $width);
$h = min($h, $height);
}
$wTa = min($w, 400);
$hTa = min($h, 400);
$wTb = min($w, 800);
$hTb = min($h, 800);
// Apply Crop Constraint
if ($crop)
{
if ($width > $height)
{
$width = ceil($width - ($width * abs($r - $w / $h)));
$widthTa = ceil($width - ($width * abs($r - $wTa / $hTa)));
$widthTb = ceil($width - ($width * abs($r - $wTb / $hTb)));
}
else
{
$height = ceil($height - ($height * abs($r - $w / $h)));
$heightTa = ceil($height - ($height * abs($r - $wTa / $hTa)));
$heightTb = ceil($height - ($height * abs($r - $wTa / $hTb)));
}
$newWidth = $w;
$newHeight = $h;
}
else
{
if ($w / $h > $r || $r < 1)
{
$newWidth = $h * $r;
$newWidthTa = $hTa * $r;
$newWidthTb = $hTb * $r;
$newHeight = $h;
$newHeightTa = $hTa;
$newHeightTb = $hTb;
}
else
{
$newHeight = $w / $r;
$newHeightTa = $wTa / $r;
$newHeightTb = $wTb / $r;
$newWidth = $w;
$newWidthTa = $wTa;
$newWidthTb = $wTb;
}
}
// Create, Resample + Return Image
$src = imagecreatefromstring(file_get_contents($file));
$dst = imagecreatetruecolor($newWidth, $newHeight);
$fff = imagecolorallocate($dst, 255, 255, 255);
imagefill($dst, 0, 0, $fff);
imagecopyresampled($dst, $src, 0, 0, 0, 0, $newWidth, $newHeight, $width, $height);
if (!is_null($path))
{
imagejpeg($dst, $path, 80);
if ($thumbnail)
{
$dstThumbA = imagecreatetruecolor($newWidthTa, $newHeightTa);
$dstThumbB = imagecreatetruecolor($newWidthTb, $newHeightTb);
$fffThumbA = imagecolorallocate($dstThumbA, 255, 255, 255);
$fffThumbB = imagecolorallocate($dstThumbB, 255, 255, 255);
imagefill($dstThumbA, 0, 0, $fffThumbA);
imagefill($dstThumbB, 0, 0, $fffThumbB);
imagecopyresampled($dstThumbA, $src, 0, 0, 0, 0, $newWidthTa, $newHeightTa, $width, $height);
imagecopyresampled($dstThumbB, $src, 0, 0, 0, 0, $newWidthTb, $newHeightTb, $width, $height);
imagejpeg($dstThumbA, str_replace('.jpg', '-thumb.jpg', $path), 80);
imagejpeg($dstThumbB, str_replace('.jpg', '-thumb#2x.jpg', $path), 80);
}
}
return $dst;
}
I concluded that the issue is specific to the environment (occurs on PHP 7.1.3 under Ubuntu, but not under PHP 7.0.1 on Windows). Reinstalling php7.1 and php7.1-gd had no effect.
Ultimately I decided to bite the bullet and rewrite with ImageMagick, resulting in a much more concise block of code:
$magickSource = new Imagick();
$magickSource->readImageBlob(file_get_contents($file));
$magickSource = $magickSource->flattenImages();
$magickFull = clone $magickSource;
$magickFull->resizeImage(min($originalWidth, $newWidth), min($originalHeight, $newHeight), Imagick::FILTER_LANCZOS, 1, true);
$magickFull->setImageCompression(Imagick::COMPRESSION_JPEG);
$magickFull->setImageCompressionQuality(75);
$magickFull->stripImage();
$magickFull->writeImage($path);
$magickFull->destroy();
if ($thumbnail)
{
$magickThumb = clone $magickSource;
$magickThumb->resizeImage(min($originalWidth, 400), min($originalHeight, 400), Imagick::FILTER_LANCZOS, 1, true);
$magickThumb->setImageCompression(Imagick::COMPRESSION_JPEG);
$magickThumb->setImageCompressionQuality(75);
$magickThumb->stripImage();
$magickThumb->writeImage(str_replace('.jpg', '-thumb.jpg', $path));
$magickThumb->destroy();
}
The calls to setImageCompression(), setImageCompressionQuality, and stripImage() yielded a 53% reduction in combined filesizes. (Source)

GD Image resize doesn't work PHP

I've got the following piece of code:
$biggest = ($width > $height) ? $width : $height;
$newWidth = 0;
$newHeight = 0;
if($biggest > $divSize){
echo "BIGGEST<br />";
$scale = $divSize/$biggest;
$newWidth = floor($width * $scale);
$newHeight = floor($height * $scale);
} else if($biggest < $divSize){
echo "DIVSIZE<br />";
$scale = $biggest/$divSize;
$newWidth = floor($width * $scale);
$newHeight = floor($height * $scale);
}
echo "SCALE: ".$scale."<br />";
echo "BIGGEST: ".$biggest."<br />";
echo "WIDTH: ".$width."<br />";
echo "HEIGHT: ".$height."<br />";
echo "NEWWIDTH: ".$newWidth."<br />";
echo "NEWHEIGHT: ".$newHeight."<br />";
$sourceImage = imagecreatefromstring(file_get_contents($fileName));
$thumb = imagecreatetruecolor($newWidth, $newHeight);
imagecopyresampled($thumb, $sourceImage, 0, 0, 0, 0, $newWidth, $newHeight, $width, $height);
imagedestroy($sourceImage);
This piece of code works fine for some images but not for all of them.
I've got a div with the dimension of 64 by 64.
For some images they scale perfectly fine but for some images the height of the outputted image is also 64px what should by for example 32px.
I don't have a clue what's causing this problem.
If you need more information, please ask.
Your function is good but sometimes your image should have a static size (this avoid to break design on some web pages).
In such a case, you can use this function. It resizes an image fit inside a defined width / height, and if the image has not the same proportions as the required thumbnail's, unused free space is set transparent.
function resizePreservingAspectRatio($img, $targetWidth, $targetHeight)
{
$srcWidth = imagesx($img);
$srcHeight = imagesy($img);
// Determine new width / height preserving aspect ratio
$srcRatio = $srcWidth / $srcHeight;
$targetRatio = $targetWidth / $targetHeight;
if (($srcWidth <= $targetWidth) && ($srcHeight <= $targetHeight))
{
$imgTargetWidth = $srcWidth;
$imgTargetHeight = $srcHeight;
}
else if ($targetRatio > $srcRatio)
{
$imgTargetWidth = (int) ($targetHeight * $srcRatio);
$imgTargetHeight = $targetHeight;
}
else
{
$imgTargetWidth = $targetWidth;
$imgTargetHeight = (int) ($targetWidth / $srcRatio);
}
// Creating new image with desired size
$targetImg = imagecreatetruecolor($targetWidth, $targetHeight);
// Add transparency if your reduced image does not fit with the new size
$targetTransparent = imagecolorallocate($targetImg, 255, 0, 255);
imagefill($targetImg, 0, 0, $targetTransparent);
imagecolortransparent($targetImg, $targetTransparent);
// Copies image, centered to the new one (if it does not fit to it)
imagecopyresampled(
$targetImg, $img, ($targetWidth - $imgTargetWidth) / 2, // centered
($targetHeight - $imgTargetHeight) / 2, // centered
0, 0, $imgTargetWidth, $imgTargetHeight, $srcWidth, $srcHeight
);
return $targetImg;
}
Usage example :
$gd = imagecreatefromjpeg("images/image5.jpg");
$resized = resizePreservingAspectRatio($gd, 100, 100);
header("Content-type: image/png");
imagepng($resized);
This image :
Becomes :
Never mind.
I figured it out myself.
I simplefied the code for scaling the thumbnail quite a bit:
$biggest = ($width > $height) ? $width : $height;
$newWidth = 0;
$newHeight = 0;
$scale = ($biggest >= $thumbSize) ? $thumbSize/$biggest : $biggest/$thumbSize;
$newWidth = floor($width * $scale);
$newHeight = floor($height * $scale);
$sourceImage = imagecreatefromstring(file_get_contents($fileName));
$thumb = imagecreatetruecolor($newWidth, $newHeight);
imagecopyresampled($thumb, $sourceImage, 0, 0, 0, 0, $newWidth, $newHeight, $width, $height);
imagedestroy($sourceImage);
Maybe someone can use this.

Upload, resize, and crop center of image with PHP

I'm wanting to create a very very basic upload, resize, and crop PHP script.
The functionality to this will be identical (last i checked anyway) to the method Twitter uses to upload avatar pictures.
I want the script to take any size image, resize the shortest side to 116px, then crop off the top and bottom (or left and right side if it's landscape) as to get a square 116px by 116px.
I don't want a bloated PHP script with client side resizing or anything, just a simple PHP resize and crop. How is this done?
The GD Library is a good place to start.
http://www.php.net/manual/en/book.image.php
There a simple to use, open source library called PHP Image Magician. It uses GD but simplifies it's usage to 3 lines.
Example of basis usage:
$magicianObj = new imageLib('racecar.jpg');
$magicianObj -> resizeImage(100, 200, 'crop');
$magicianObj -> saveImage('racecar_small.png');
If you want an example to work from my upload, resize and crop class does all of this plus some other cool stuff - you can use it all if needed or just take the bits out that you like:
http://www.mjdigital.co.uk/blog/php-upload-and-resize-image-class/
I don't think it is too bloated! - you can just do something this (not tested):
if((isset($_FILES['file']['error']))&&($_FILES['file']['error']==0)){ // if a file has been posted then upload it
include('INCLUDE_CLASS_FILE_HERE.php');
$myImage = new _image;
// upload image
$myImage->uploadTo = 'uploads/'; // SET UPLOAD FOLDER HERE
$myImage->returnType = 'array'; // RETURN ARRAY OF IMAGE DETAILS
$img = $myImage->upload($_FILES['file']);
if($img) {
$myImage->newWidth = 116;
$myImage->newHeight = 116;
$i = $myImage->resize(); // resizes to 116px keeping aspect ratio
// get new image height
$imgWidth = $i['width'];
// get new image width
$imgHeight = $i['height'];
if($i) {
// work out where to crop it
$cropX = ($imgWidth>116) ? (($imgWidth-116)/2) : 0;
$cropY = ($imgHeight>116) ? (($imgHeight-116)/2) : 0;
$cropped = $myImage->crop(116,116,$cropX,$cropY);
if($cropped) { echo 'It Worked (I think!)'; print_r($cropped);
} else { echo 'Crop failed'; }
} else { echo 'Resize failed'; }
} else { echo 'Upload failed'; }
I made this simple function which is very easy to use, it allows you to resize, crop and center an image to a specific width and height, it can suppert JPGs, PNGs and GIFs. Feel free to copy and paste it to your code:
function resize_imagejpg($file, $w, $h, $finaldst) {
list($width, $height) = getimagesize($file);
$src = imagecreatefromjpeg($file);
$ir = $width/$height;
$fir = $w/$h;
if($ir >= $fir){
$newheight = $h;
$newwidth = $w * ($width / $height);
}
else {
$newheight = $w / ($width/$height);
$newwidth = $w;
}
$xcor = 0 - ($newwidth - $w) / 2;
$ycor = 0 - ($newheight - $h) / 2;
$dst = imagecreatetruecolor($w, $h);
imagecopyresampled($dst, $src, $xcor, $ycor, 0, 0, $newwidth, $newheight,
$width, $height);
imagejpeg($dst, $finaldst);
imagedestroy($dst);
return $file;
}
function resize_imagegif($file, $w, $h, $finaldst) {
list($width, $height) = getimagesize($file);
$src = imagecreatefromgif($file);
$ir = $width/$height;
$fir = $w/$h;
if($ir >= $fir){
$newheight = $h;
$newwidth = $w * ($width / $height);
}
else {
$newheight = $w / ($width/$height);
$newwidth = $w;
}
$xcor = 0 - ($newwidth - $w) / 2;
$ycor = 0 - ($newheight - $h) / 2;
$dst = imagecreatetruecolor($w, $h);
$background = imagecolorallocatealpha($dst, 0, 0, 0, 127);
imagecolortransparent($dst, $background);
imagealphablending($dst, false);
imagesavealpha($dst, true);
imagecopyresampled($dst, $src, $xcor, $ycor, 0, 0, $newwidth, $newheight,
$width, $height);
imagegif($dst, $finaldst);
imagedestroy($dst);
return $file;
}
function resize_imagepng($file, $w, $h, $finaldst) {
list($width, $height) = getimagesize($file);
$src = imagecreatefrompng($file);
$ir = $width/$height;
$fir = $w/$h;
if($ir >= $fir){
$newheight = $h;
$newwidth = $w * ($width / $height);
}
else {
$newheight = $w / ($width/$height);
$newwidth = $w;
}
$xcor = 0 - ($newwidth - $w) / 2;
$ycor = 0 - ($newheight - $h) / 2;
$dst = imagecreatetruecolor($w, $h);
$background = imagecolorallocate($dst, 0, 0, 0);
imagecolortransparent($dst, $background);
imagealphablending($dst, false);
imagesavealpha($dst, true);
imagecopyresampled($dst, $src, $xcor, $ycor, 0, 0, $newwidth,
$newheight,$width, $height);
imagepng($dst, $finaldst);
imagedestroy($dst);
return $file;
}
function ImageResize($file, $w, $h, $finaldst) {
$getsize = getimagesize($file);
$image_type = $getsize[2];
if( $image_type == IMAGETYPE_JPEG) {
resize_imagejpg($file, $w, $h, $finaldst);
} elseif( $image_type == IMAGETYPE_GIF ) {
resize_imagegif($file, $w, $h, $finaldst);
} elseif( $image_type == IMAGETYPE_PNG ) {
resize_imagepng($file, $w, $h, $finaldst);
}
}
All you have to do to use it is call it like so:
ImageResize(image, width, height, destination);
E.g.
ImageResize("uploads/face.png", 100, 150, "images/user332profilepic.png");

Categories