I'm processing images when the user uploads a pic but my problem is high rez pics. How do you detect when the user uploads one? I'm using the GD library for PHP. Setting the quality to 90 with the imagejpeg() method doesn't do anything to it but scales the dimension and then sets the ppi to 72. I want to be able to preserve the dimension and drop the ppi to 72 at the same time. Any开发者_StackOverflow中文版 advice would be greatly appreciated.
There is no such thing as PPI as far as you need to be concerned. Also, DPI doesn't exist in digital. There are only pixels, and the dimensions (which are just a measurement of pixels in either direction).
What you are really trying to do is downsample an image, reducing the overall dimensions of an image. You will probably want to do it proportionally, which is to say you want to keep the same ratio of width to height so that the image doesn't appear stretched after resampling it. Also worth noting, resizing and resampling differ in that resizing doesn't pay much attention to the content, resulting in very visually-poor resized images. You probably want resampling.
The PHP documentation has some great examples on handling uploaded files as well as how to resize images using the GDImage library. I suggest you check them out. Other relevant methods you might want to know about:
- getimagesize() will let you check the dimensions of an image without opening it (useful to check if it needs to be resized without loading it up).
- imagesx() and imagesy() grab dimensions of a GD Image resource.
PPI, DPI...
First, let us clarify the terminology. Both PPI (pixels per inch) and DPI (dot per inch) are ratios that specify conversion of pixels to physical units (inch in this case). In the digital world - computers, images, ... DPI is mistakenly used where PPI should be used instead. DPI in fact only exist in a printing world. But for us now, DPI = PPI. >> More info
The resolution information (sometimes refered to as DPI, but it is PPI) is stored in the headers (image meta information). JPG and PNG do support this; but GIF doesn't support DPI - it is not present in the GIF header.
Change PPI in PHP
So, you are probably asking how to set PPI (DPI) in the image header? In PHP, you can do it using Imagick library (of course not for GIFs):
$image = new Imagick('img.jpg'); // default 72 dpi image
$image->setImageResolution(500, 500);
$image->writeImage("img-500dpi.jpg"); // this image will have 500 dpi
If you download these images and try to print them e.g. in IrfanView, it will actually use the dpi information to convert pixels to target physical unit. Both images will be printed in different size.
Image PPI won't work on web
Bad news is that this won't change anything when displaying the image on a web page. The anchor unit for the display is always a pixel in CSS. So img.jpg
and the img-500dpi.jpg
will have exactly the same size in the browser. Even if you open the images directly. Even if you use physical unit like cm
:
img { width: 8cm; height: 6cm; }
both images will be displayed in the same size; physical units are converted to pixels regardless of the image resolution using fixed ratio. And surprisingly even if you try to print the raw images (not the page) in Firefox, they both will be printed at the same size. Cannot comment on other browsers. Strange enough - this works as expected in Irfanview.
PPI and retina images
Now with Iphones etc. retina (i.e. high resolution) images are becoming trendy. Here, a lot is spoken about DPI (PPI in fact), but this is all related only to the target device and the CSS media queries. There is nothing that would actually recognize the PPI of your image; you have to specify the actual dimensions of the high-res retina image in pixels. This is an example for 66x66 icon (from here):
@media (-webkit-min-device-pixel-ratio: 2),
(min-resolution: 192dpi) {
.box {
background:url('images/icon66x66.png') no-repeat top left;
background-size: 33px 33px;
}
}
So you can actually "downscale" the high-res images by setting lower dimensions for them in the CSS. But I would only recommend to do this for retina images and within correct media query.
So, you have to resample in PHP
So in fact, if you want to make uploaded image appear smaller "on the Web", the best way is to resample it. Resampling means not to change the header only, but to change the actual pixel matrix of the image. Here is the code I use in PHP, which uses the GD library:
$t = imagecreatefromjpeg($old_img_path);
$s = imagecreatetruecolor($new_width, $new_height);
$x = imagesx($t);
$y = imagesy($t);
imagecopyresampled($s, $t, 0, 0, 0, 0, $new_width, $new_height, $x, $y);
imagejpeg($s, $new_img_path);
chmod($new_img_path, 0644);
Be aware that this requires quite a lot of memory, which might be limited by your hosting provider.
If you're dealing with hi-res images a lot I'd go down the ImageMagick path as it is fastert + gives a lot more information about the images + lets you write images back at 300 DPI (or other resolutions) if you want.
Here's what I do with Jcrop and ImageMagick (but at 72 DPI)
$picture = new Imagick($src);
$picture->cropImage( $_POST['w'], $_POST['h'], $_POST['x'], $_POST['y']);
$picture->resizeImage(690, 500, Imagick::FILTER_LANCZOS,1, true);
$picture->writeImage($cropped);
$picture->clear();
$picture->destroy();
Using phpthumb (http://phpthumb.gxdlabs.com) is a good, elegant and easy solution.
I have a working code example using it uploaded to GitHub. It can use both GD & Imagemagick, it's up to you.
https://github.com/lopezator/thumbNailGenerator
bool Imagick::setResolution ( float $x_resolution , float $y_resolution )
If you're reducing ppi, the dimensions will change to reflect the reduction - fewer pixels per inch mean there will be less inches to your picture.
精彩评论