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.
Related
I want to create a thumbnail image without black/white bars and have it keep aspect ratio
The thumbnail size should be 320x200 (px).
I actually wrote a function to create a thumbnail for a given resolution but I don't know how to keep the aspect ratio of the image
function imageResize($imageResourceId, $width, $height)
{
$targetWidth = 320;
$targetHeight = 200;
$targetLayer = imagecreatetruecolor($targetWidth, $targetHeight);
imagecopyresampled($targetLayer, $imageResourceId, 0, 0, 0, 0, $targetWidth, $targetHeight, $width, $height);
return $targetLayer;
}
But I can't figure out a way to crop them and have them accommodated as I want. Thanks in advance!
To do this you can use imagecopyresampled function like this:
function imageResize($imageResourceId, $width, $height)
{
$targetWidth = 320;
$targetHeight = 200;
$aspectRatio = $width / $height;
$targetRatio = $targetWidth / $targetHeight;
if ($aspectRatio > $targetRatio) {
$newHeight = $targetHeight;
$newWidth = $targetHeight * $aspectRatio;
} else {
$newWidth = $targetWidth;
$newHeight = $targetWidth / $aspectRatio;
}
$targetLayer = imagecreatetruecolor($newWidth, $newHeight);
imagecopyresampled($targetLayer, $imageResourceId, 0, 0, 0, 0, $newWidth, $newHeight, $width, $height);
return $targetLayer;
}
Using this, the new Width and Height are calculated based on the aspect ratio of the original image.
More samples on: https://www.php.net/manual/en/function.imagecopyresampled.php
I want to create a thumbnail for an image so that it's a square with no black bars/white bars and it fills the whole square while maintaining proportion. Kind of like CSS background-size: cover.
Like this:
Even if the image is smaller than the tuhmbnail size (which is arbitrary) it should still create the thumbnail.
The thumbnail size should be 400x400 (px).
I actually wrote a function to create a thumbnail with the white bars, here it is:
function createThumbnail($orig, $sizes){
$width = $sizes[0];
$height = $sizes[1];
$targetSize = 340;
$targetWidth = ($width > $height) ? $targetSize : round(($width * $targetSize) / $height);
$targetHeight = ($width > $height) ? round(($height * $targetSize) / $width) : $targetSize;
$targetLayer = imagecreatetruecolor($targetSize, $targetSize);
$color = imagecolorallocate($targetLayer, 255, 255, 255);
imagefill($targetLayer, 0, 0, $color);
$targetX = ($width > $height) ? 0 : ($targetSize - $targetWidth) / 2;
$targetY = ($width > $height) ? ($targetSize - $targetHeight) / 2 : 0;
imagecopyresampled($targetLayer, $orig, $targetX, $targetY, 0, 0, $targetWidth, $targetHeight, $width, $height);
return $targetLayer;
}
But I can't figure out a way to crop them and have them accomodated as I want. Thanks in advance!
Well after some back and forth I actually came up with a solution, probably not the best or most efficient, I have yet to test it for all cases but it seems to work for now:
function createThumbnail($orig, $sizes){
$width = $sizes[0];
$height = $sizes[1];
$targetSize = 400;
$srcX = 0;
$srcY = 0;
$src = $width;
if ($width > $height){
$ratio = $targetSize / $height;
$srcX = (($ratio * $width) - $targetSize) / (2 * $ratio);
$src = $height;
}else if ($height > $width){
$ratio = $targetSize / $width;
$srcY = (($ratio * $height) - $targetSize) / (2 * $ratio);
}
$targetLayer = imagecreatetruecolor($targetSize, $targetSize);
$color = imagecolorallocate($targetLayer, 255, 255, 255);
imagecopyresampled($targetLayer, $orig, 0, 0, $srcX, $srcY, $targetSize, $targetSize, $src, $src);
return $targetLayer;
}
If someone has a better solution or knows how to improve this one please let me know!
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)
Ok so I'm trying to resize an image using php. I do not have access to install plugins on the server I use at this time.
$originalimage is the actual original image that I'm going to resize.
$width is another parameter to define $original_width. The same can be said for $height and $original_height.
$original_width = imagesx($originalimage);
$original_height = imagesy($originalimage);
$max_width = $thumbwidth;
$max_height = $thumbheight;
$width = $original_width;
$height = $original_height;
Using the pre-setup above I start to work on this one here. This works but no way to set a max height. For example I pass a max width as $thumbwidth and max height as $thumbheight and this will work as desired till I then try to go ahead and use an image that's higher than it is wide. (Portrait image.) It does not completely fail however it does fail to enforce a max height, rendering an image that can potentially be very high.
if ($width > $height) {
$newwidth = $thumbwidth;
$divisor = $width / $thumbwidth;
$newheight = floor( $height / $divisor);
} else {
$newheight = $thumbheight;
$divisor = $height / $thumbheight;
$newwidth = floor( $width / $divisor );
}
$image = imagecreatetruecolor( $newwidth, $newheight );
imagecopyresampled( $image, $originalimage, 0, 0, 0, 0, $newwidth, $newheight, $original_width, $original_height );
After trying to understand this and failing after a few hours I came up with the code below which I had gotten from php.net. As you can see there was a reason I set two sets of variables equal to each other in the pre-setup part of the code. Mostly because I can not comprehend calling $max_width as $thumbwidth in the second code segment.
This below works as well until you pass in a parameter though that is larger than the width or height of $originalimage.
# taller
if ($height > $max_height) {
$width = ($max_height / $height) * $width;
$height = $max_height;
}
# wider
if ($width > $max_width) {
$height = ($max_width / $width) * $height;
$width = $max_width;
}
$image = imagecreatetruecolor( $width, $height );
imagecopyresampled( $image, $originalimage, 0, 0, 0, 0, $width, $height, $original_width, $original_height );
I'm sorry I can't find a way to do this on my own. As for this being a duplicate question, Most similar questions end up with "[Insert plugin name here] is better use that instead." I am asking specifically for an answer that does not use other plugins or javascript. (Besides GD which is pre-installed on my server.)
Before I end this question I will say that I am using imagejpeg($image); so the use of HTML or CSS is completely forbidden.
Here's a class I whipped up for a program I worked on. maybe it will help you?
<?php
class ImageHelper
{
/**
* #static
* #param $source string Path for source image
* #param $destination string Path for destination image to be placed
* #param $targetWidth int Width of the new image (in pixels)
* #param $targetHeight int Height of the new image (in pixels)
* #param $strict bool
*/
public static function createImage($source, $destination, $targetWidth, $targetHeight, $strict = false){
$dir = dirname($destination);
if(!is_dir($dir)){
mkdir($dir, 0770, true);
}
$fileContents = file_get_contents($source);
$image = imagecreatefromstring($fileContents);
$thumbnail = ImageHelper::resizeImage($image, $targetWidth, $targetHeight, $strict);
imagejpeg($thumbnail, $destination, 100);
imagedestroy($thumbnail);
imagedestroy($image);
}
/**
* Resize an image to the specified dimensions
* #param string $original Path to the original image
* #param int $targetWidth Width of the new image (in pixels)
* #param int $targetHeight Height of the new image (in pixels)
* #param bool $strict True to crop the picture to the specified dimensions, false for best fit
* #return bool|resource Returns the new image resource or false if the image was not resized.
*/
public static function resizeImage($original, $targetWidth, $targetHeight, $strict = false)
{
$originalWidth = imagesx($original);
$originalHeight = imagesy($original);
$widthRatio = $targetWidth / $originalWidth;
$heightRatio = $targetHeight / $originalHeight;
if(($widthRatio > 1 || $heightRatio > 1) && !$strict){
// don't scale up an image if either targets are greater than the original sizes and we aren't using a strict parameter
$dstHeight = $originalHeight;
$dstWidth = $originalWidth;
$srcHeight = $originalHeight;
$srcWidth = $originalWidth;
$srcX = 0;
$srcY = 0;
}elseif ($widthRatio > $heightRatio) {
// width is the constraining factor
if ($strict) {
$dstHeight = $targetHeight;
$dstWidth = $targetWidth;
$srcHeight = $originalHeight;
$srcWidth = $heightRatio * $targetWidth;
$srcX = floor(($originalWidth - $srcWidth) / 2);
$srcY = 0;
} else {
$dstHeight = ($originalHeight * $targetWidth) / $originalWidth;
$dstWidth = $targetWidth;
$srcHeight = $originalHeight;
$srcWidth = $originalWidth;
$srcX = 0;
$srcY = 0;
}
} else {
// height is the constraining factor
if ($strict) {
$dstHeight = $targetHeight;
$dstWidth = $targetWidth;
$srcHeight = $widthRatio * $targetHeight;
$srcWidth = $originalWidth;
$srcY = floor(($originalHeight - $srcHeight) / 2);
$srcX = 0;
} else {
$dstHeight = $targetHeight;
$dstWidth = ($originalWidth * $targetHeight) / $originalHeight;
$srcHeight = $originalHeight;
$srcWidth = $originalWidth;
$srcX = 0;
$srcY = 0;
}
}
$new = imagecreatetruecolor($dstWidth, $dstHeight);
if ($new === false) {
return false;
}
imagecopyresampled($new, $original, 0, 0, $srcX, $srcY, $dstWidth, $dstHeight, $srcWidth, $srcHeight);
return $new;
}
}
You can try this function as shown below.
<?php
function makeThumbnail($sourcefile,$max_width, $max_height, $endfile, $type){
// Takes the sourcefile (path/to/image.jpg) and makes a thumbnail from it
// and places it at endfile (path/to/thumb.jpg).
// Load image and get image size.
//
switch($type){
case'image/png':
$img = imagecreatefrompng($sourcefile);
break;
case'image/jpeg':
$img = imagecreatefromjpeg($sourcefile);
break;
case'image/gif':
$img = imagecreatefromgif($sourcefile);
break;
default :
return 'Un supported format';
}
$width = imagesx( $img );
$height = imagesy( $img );
if ($width > $height) {
if($width < $max_width)
$newwidth = $width;
else
$newwidth = $max_width;
$divisor = $width / $newwidth;
$newheight = floor( $height / $divisor);
}
else {
if($height < $max_height)
$newheight = $height;
else
$newheight = $max_height;
$divisor = $height / $newheight;
$newwidth = floor( $width / $divisor );
}
// Create a new temporary image.
$tmpimg = imagecreatetruecolor( $newwidth, $newheight );
imagealphablending($tmpimg, false);
imagesavealpha($tmpimg, true);
// Copy and resize old image into new image.
imagecopyresampled( $tmpimg, $img, 0, 0, 0, 0, $newwidth, $newheight, $width, $height);
// Save thumbnail into a file.
//compressing the file
switch($type){
case'image/png':
imagepng($tmpimg, $endfile, 0);
break;
case'image/jpeg':
imagejpeg($tmpimg, $endfile, 100);
break;
case'image/gif':
imagegif($tmpimg, $endfile, 0);
break;
}
// release the memory
imagedestroy($tmpimg);
imagedestroy($img);
}
?>
The function has five parameters.
> $sourcefile - Specicifies the temporary location of your image file
> $max_width - Specifies the possible maximum width
> $max_height - Specifies the possible maximum width
> $endfile - Specifies the directory to save the image
> $type - Specifies the image file type
Download demo code here
I've had a very similar problem building the thumbs for a gallery page. I tried Daniel Nyamasyo solution above but just could not get past the "$img = imagecreatefromjpeg($sourcefile);" line without getting "Warning: imagecreatefromjpeg failed to open stream: HTTP request failed! HTTP/1.1 400 Bad Request" no matter what $sourcefile I fed it.
I came up with this dirty method.
<?php
// Some variables
$thumb_width = 162; // The maximum values you want
$thumb_height = 122;
$thumb_pointer = 'thumbs'; // Put your output folder here which must exist
$img = imagecreatefromjpeg( $image_name);
$width = imagesx( $img );
$height = imagesy( $img );
if ($width>=$height)
{
// Now calculate thumbnail size
$new_width = $thumb_width;
$new_height = floor( $height * ($thumb_width / $width));
// The 'dirty' bit I found was needed for square or near square images
while ($new_height > $thumb_height)
{
$new_width = floor($new_width * 0.99);
$new_height = floor($new_height * 0.99);
}
}
else
{
$new_height = $thumb_height;
$new_width = floor($width * ($thumb_height / $height));
}
// Create a new temporary image
$tmp_img = imagecreatetruecolor( $new_width, $new_height );
// Copy and resize old image into new image
imagecopyresized( $tmp_img, $img, 0, 0, 0, 0, $new_width, $new_height, $width, $height );
// Save the thumbnail into a file
imagejpeg( $tmp_img, $thumb_pointer.'/'.$image_name);
?>
I have an upload form where you select photos. Upon upload I resize the image if necessary.
It seems any photo that I upload where the HEIGHT > WIDTH stretches the image. If I upload an image where WIDTH > HEIGHT it works fine. I've been racking my brain trying to figure this out. I'm pretty sure I know which line is the issue and I've pointed it out in a comment.
Can anyone see what is wrong with my math? Thanks!
<?php
$maxWidth = 900;
$maxHeight = 675;
$count = 0;
foreach ($_FILES['photos']['name'] as $filename)
{
$uniqueId = uniqid();
$target = "../resources/images/projects/" . strtolower($uniqueId . "_" . $filename);
$file = $_FILES['photos']['tmp_name'][$count];
list($originalWidth, $originalHeight) = getimagesize($file);
// if the image is larger than maxWidth or maxHeight
if ($originalWidth > $maxWidth || $originalHeight > $maxHeight)
{
$ratio = $originalWidth / $originalHeight;
// I think this is the problem line
(($maxWidth / $maxHeight) > $ratio) ? $maxWidth = $maxWidth * $ratio : $maxHeight = $maxWidth / $ratio;
// resample and save
$image_p = imagecreatetruecolor($maxWidth, $maxHeight);
$image = imagecreatefromjpeg($file);
imagecopyresampled($image_p, $image, 0, 0, 0, 0, $maxWidth, $maxHeight, $originalWidth, $originalHeight);
$image = imagejpeg($image_p, $target, 75);
}
else
{
// just save the image
move_uploaded_file($file,$target);
}
$count += 1;
}
?>
When scaling, you need to modify both the width and the height of the target.
Try:
if ($originalWidth > $maxWidth || $originalHeight > $maxHeight)
{
if ($originalWidth / $maxWidth > $originalHeight / $maxHeight) {
// width is the limiting factor
$width = $maxWidth;
$height = floor($width * $originalHeight / $originalWidth);
} else { // height is the limiting factor
$height = $maxHeight;
$width = floor($height * $originalWidth / $originalHeight);
}
$image_p = imagecreatetruecolor($width, $height);
$image = imagecreatefromjpeg($file);
imagecopyresampled($image_p, $image, 0, 0, 0, 0, $width, $height, $originalWidth, $originalHeight);
$image = imagejpeg($image_p, $target, 75);
}