Solved

Use php to get a photo in the right proportions

Posted on 2011-09-04
14
332 Views
Last Modified: 2012-05-12
I have a folder full of .jpg files of all kinds of random dimensions and sizes.  I have used php for manipulating images but it has been a while.

I wish to print them all to 8"x12" paper and have nothing cropped or stretched from the original.

What I am currently doing is manually adding black bars to meet the correct dimensions.

Since I'm printing to 8"x12" the ratio is 1/1.5 or 0.667

So a photo coming in at 3000x4000 will finalize at 3000x4500 with black on top & bottom of 3000x250

A picture coming in at 2500x10000 will finalize at 6666x10000 with black bars on right & left of 2083x10000

Hopefully I'm being clear.  The incoming photo will be of varying sizes, both landscape & portrait.  They will all print to 8"x12" or 12"x8" with no stretching or cropping.
0
Comment
Question by:hrolsons
  • 7
  • 4
  • 3
14 Comments
 
LVL 13

Expert Comment

by:F Igor
ID: 36482437
Thy this function . It needs the PHP/gd2 functions enabled.

function imageResize($filename,$newfile){

	$imgsrc=@imagecreatefromjpeg ($filename);
	if (!$imgsrc) return false;
	list($width, $height, $type, $atr) = getimagesize($filename);
	// ratio selection
	if ($width<$height){
		$ratio=8/12;
	}else{
		$ratio=12/8;
	}
	// best size selection
	if ($height<=round($width/$ratio)){
		$width_n=($width);
		$height_n=round($width/$ratio);
	}else{
		$height_n=($height);
		$width_n=round($height*$ratio);
	}
	
	/* New image */
	$imgdst  = imagecreatetruecolor ($width_n, $height_n); 
	// White BGColor  (255,255,255)
	$bgc = imagecolorallocate ($imgdst, 255, 255, 255);
	imagefilledrectangle ($imgdst, 0, 0, $width_n, $height_n, $bgc);		

	// add simetric borders
	$xx=($width_n-$width)/2;
	$yy=($height_n-$height)/2;

	//best function to resize
	if (function_exists("imagecopyresampled"))
		imagecopyresampled($imgdst,$imgsrc,$xx,$yy,0,0,$width_n,$height_n,$width,$height);
	//alternative function

		else
		imagecopyresized($imgdst,$imgsrc,$xx,$yy,0,0,$width_n,$height_n,$width,$height);
	//create the new (jpeg) image in the $newfile path
	imagejpeg($imgdst,$newfile);
	return true;
}

Open in new window

0
 
LVL 109

Expert Comment

by:Ray Paseur
ID: 36502343
I think we need a little clarification here, and it would be really useful if you could post your test images and show us the code you have tried to use to complete this task.

The term will finalize is not clear to me, and it is not a term of art in imaging.  Please clarify.

When you write, "no stretching or cropping" I understand that to mean that you would want to preserve the aspect ratio of the images.  Is that what you mean?
http://en.wikipedia.org/wiki/Aspect_ratio_%28image%29

What image density (DPI) do you intend to use for printing?  On my fine art photo-quality Epson printers I usually use at least 150DPI and never find any value in using more than 300DPI.  Parenthetically, I rarely find 8x12" paper, but that is probably not really relevant to your objectives.

The image dimensions in pixels for a 12x8 landscape image would be 1,800 x 1,200 at 150DPI and 3,600 x 2,400 at 300DPI.  Image dimensions are always written with the width (x-axis) first.  

Do you care about the size and position of the "black bars?"  Do you want the image centered in a black field?  Or do you want the image resized  to occupy the largest possible area of the paper, understanding that resizing images to enlarge them may produce visually unacceptable results.  And resizing images to reduce them may result in irrevocable loss of detail as image information is discarded in the process

Do you want to render the images to the browser output stream or save them into a library?  

Do you care about compression and image quality?  If so, please tell us what your objectives are - better images or smaller file sizes?

The general design I would use goes something like this: 1. create an image resource of appropriate dimensions with black.  2. use ImageCopyResampled() to put the raw image into the final image.  There is not really much more to it, just a few ratios, etc.

Have you thought about doing this with Photoshop "actions?"
0
 

Author Comment

by:hrolsons
ID: 36513245
I'm getting this error:

"Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 3204 bytes) in..."

On this line:

$imgdst  = imagecreatetruecolor ($width_n, $height_n);

Where $width_n=3204 and $height_n=4806
0
What is SQL Server and how does it work?

The purpose of this paper is to provide you background on SQL Server. It’s your self-study guide for learning fundamentals. It includes both the history of SQL and its technical basics. Concepts and definitions will form the solid foundation of your future DBA expertise.

 

Author Comment

by:hrolsons
ID: 36513283
Here are the original image, and how I'd like it to end up:

 Original
 Edited
0
 
LVL 109

Accepted Solution

by:
Ray Paseur earned 250 total points
ID: 36514067
The start image you posted here is 465x721 pixels at 300 DPI.  This is an image 1.550" wide and 2.403" high.  I have saved it on my server here:
http://www.laprbass.com/RAY_temp_hrolsons.jpg

I saved a black image of 481x721 pixels (same dimensions as the finish image you posted here) on my server.  See it here:
http://www.laprbass.com/RAY_temp_hrolsons_black.png

The finish image is 481x721 pixels at 300DPI.  Same height as the start image, and 1.603" wide.  It has two strips of black on each side, 8 pixels wide.

The email message with the memory utilization said something like this:
WITH IMAGES int(4,190,992)
POST IMAGES    int(680,544)
<?php // RAY_temp_hrolsons.php
error_reporting(E_ALL);

// LOCATION OF THE IMAGES (COULD COME IN FROM $_GET URL STRING)
$original = 'http://www.LAPRBass.com/RAY_temp_hrolsons.jpg';
$border   = 'http://www.LAPRBass.com/RAY_temp_hrolsons_black.png';

// READ THE BLACK IMAGE BACKGROUND
$bg = ImageCreateFromPNG($border);

// READ THE IMAGE
$im = ImageCreateFromJPEG($original);

// COMPUTE THE OFFSET FOR THE SIDE BORDERS
$bg_x = imagesx($bg);
$im_x = imagesx($im);
$im_y = imagesy($im);
$offs = (int)($bg_x - $im_x) / 2;

// COPY THE IMAGE TO THE BACKGROUND
ImageCopy
( $bg    // DESTINATION IMAGE
, $im    // SOURCE IMAGE
, $offs  // DESTINATION X-AXIS IN PIXELS
, 0      // DESINTATION Y-AXIS IN PIXELS
, 0      // SOURCE X-AXIS IN PIXELS
, 0      // SOURCE Y-AXIS IN PIXELS
, $im_x  // SOURCE WIDTH
, $im_y  // SOURCE HEIGHT
)
;

// SHOW THE IMAGE
header('Content-type: image/jpg');
ImageJPEG($bg, NULL, 100);

// SHOW THE MEMORY USE
ob_start();
echo "WITH IMAGES ";
var_dump(memory_get_usage());

// REMOVE THE IMAGE RESOURCES
ImageDestroy($im);
ImageDestroy($bg);

// SHOW THE MEMORY USE
ECHO "POST IMAGES ";
var_dump(memory_get_usage());

// SEND THE MESSAGE
$msg = ob_get_clean();
mail('Ray.Paseur@Gmail.com', 'hrolsons memory stats', $msg);

Open in new window

0
 
LVL 13

Assisted Solution

by:F Igor
F Igor earned 250 total points
ID: 36515005
For larger images you need a lot of memory configured in your PHP configuration to get it working:

If you have access to the php configuration and modify it,
edit php.ini the line with the folowing text:

memory_limit = 128M (or whatever is set up before)


to

memory limit = 256M  (or a higher value like 512M)


If you can´t access this configuration to modify it,
you can add the following line at the start of your PHP code
(It must be done in every page that you need more memory,
if you can't modify the php configuration for a global value)



<?php

ini_set('memory_limit', '256M');

...
..
..

Open in new window


And try different values to meet your needs.

0
 

Author Comment

by:hrolsons
ID: 36515147
Ray,

When I run your code, the correct image pops up, but none of your "echo" statements show up on-screen for some reason.  And, the mail function didn't work.  I just installed phpED on my local machine and I believe php.ini is not configured correctly.

I'm going to try something, based on your code...
0
 

Author Comment

by:hrolsons
ID: 36515174
OK, I tried your code with the "real" image and:

Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 12388 bytes) in C:\Photo Resell\Photo Editor\noname2.php on line 13

And Ray, I know it drives you crazy when people don't include the "real" image in their question, but I thought it was too large to post.  But in this case, here goes:

 Actual "real" image
0
 
LVL 13

Expert Comment

by:F Igor
ID: 36515203
For an image of 3204 x 4806 you need at least
3204*4806*24 = 369562176 bytes (360M)
so you need to set the memory-limit from 512M or more for larger images.

<?php

ini_set('memory_limit', '512M');


?>

Open in new window

0
 

Author Comment

by:hrolsons
ID: 36515211
What is the maximum I can set it to?
0
 
LVL 13

Expert Comment

by:F Igor
ID: 36515290
You can set it up up to all available memory on the server.

If you want no limit set it to -1
(0 will work, i guess)


See the documentation for "memory_limit" php configuration.
http://php.net/manual/en/ini.core.php

0
 
LVL 109

Expert Comment

by:Ray Paseur
ID: 36516269
...none of your "echo" statements show up on-screen for some reason.  
The reason is on line 28: ob_start(); and you can read about that function here.
See http://us2.php.net/manual/en/function.ob-start.php

The reason for using output buffering and the mail() command is that the script writes a JPG image header, so the browser output has to be a JPG image.  Text does not fit into that model, so I capture the text and use email to get it to myself.  This lets me see what is going on in the script.  The browser output of the image lets me see that the script worked correctly.

And, the mail function didn't work.
Yes it did.  I just removed it from the script on my server so I wouldn't get junk mail if someone is testing the script at http://www.laprbass.com/RAY_temp_hrolsons.php

More importantly, the test data you provided to us was nothing like the actual data you're working with.  A file that is 91KB is materially different from a file that is 3,100KB.  Notwithstanding that, you have the solution to your question as well as a script that shows the implementation using the test data you gave us.  And now all you need to do is get your server settings right.  So I'll sign off on this one.  If you have other questions, please consider posting a "follow-on" question.  Best of luck with your project, ~Ray
0
 

Author Comment

by:hrolsons
ID: 36517019
Thank you guys so much.  I have indeed posted a "follow-on" question here:

http://www.experts-exchange.com/Web_Development/Web_Languages-Standards/PHP/Q_27301642.html
0
 

Author Comment

by:hrolsons
ID: 36517058
Darn it, I shouldn't have created the new question because I can see the answer now in "fraigor" post above.

And now when I change the memory limit, fraigor's code is almost working, but the black bar(after I changed to 0,0,0) is only to the side.

What a mess, and now how do I do points, you have all been so helpful, as usual.
0

Featured Post

DevOps Toolchain Recommendations

Read this Gartner Research Note and discover how your IT organization can automate and optimize DevOps processes using a toolchain architecture.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Build an array called $myWeek which will hold the array elements Today, Yesterday and then builds up the rest of the week by the name of the day going back 1 week.   (CODE) (CODE) Then you just need to pass your date to the function. If i…
This article discusses four methods for overlaying images in a container on a web page
Learn how to match and substitute tagged data using PHP regular expressions. Demonstrated on Windows 7, but also applies to other operating systems. Demonstrated technique applies to PHP (all versions) and Firefox, but very similar techniques will w…
This tutorial will teach you the core code needed to finalize the addition of a watermark to your image. The viewer will use a small PHP class to learn and create a watermark.

810 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question