Tag: image
Image Resizing Functions (… again?!)
by z3n on Mar.27, 2010, under Coding, Tips & Hints
Problem:
Oh yeah i posted this before, but now that i finally got wordpress updates i can use a decent syntax highlighter.
The main function img_resizer, is able to resize gif, png, wbmp, bmp and jpgs with proportional or cropping resize, it’s also got a function to eventually FIX the format if the filename extension is not really the same of the format, like a jpg named as file.bmp. BMP function been taken off php man pages, i will not post author’s full email to avoid spam.
Solution:
function dwordize($str) {
$a = ord($str[0]);
$b = ord($str[1]);
$c = ord($str[2]);
return $c*256*256 + $b*256 + $a;
}
function byte3($n) {
return chr($n & 255) . chr(($n >> 8) & 255) . chr(($n >> 16) & 255);
}
function dword($n) {
return pack("V", $n);
}
function word($n) {
return pack("v", $n);
}
function imagebmp(&$img, $filename = false) {
$wid = imagesx($img);
$hei = imagesy($img);
$wid_pad = str_pad('', $wid % 4, "\0");
$size = 54 + ($wid + $wid_pad) * $hei;
//prepare & save header
$header['identifier'] = 'BM';
$header['file_size'] = dword($size);
$header['reserved'] = dword(0);
$header['bitmap_data'] = dword(54);
$header['header_size'] = dword(40);
$header['width'] = dword($wid);
$header['height'] = dword($hei);
$header['planes'] = word(1);
$header['bits_per_pixel'] = word(24);
$header['compression'] = dword(0);
$header['data_size'] = dword(0);
$header['h_resolution'] = dword(0);
$header['v_resolution'] = dword(0);
$header['colors'] = dword(0);
$header['important_colors'] = dword(0);
if ($filename) {
$f = fopen($filename, "wb");
foreach ($header AS $h) {
fwrite($f, $h);
}
// save pixels
for ($y=$hei-1; $y>=0; $y--) {
for ($x=0; $x<$wid; $x++) {
$rgb = imagecolorat($img, $x, $y);
fwrite($f, byte3($rgb));
}
fwrite($f, $wid_pad);
}
fclose($f);
} else {
foreach ($header AS $h)
{
echo $h;
}
//save pixels
for ($y=$hei-1; $y>=0; $y--) {
for ($x=0; $x<$wid; $x++) {
$rgb = imagecolorat($img, $x, $y);
echo byte3($rgb);
}
echo $wid_pad;
}
}
}
function _ckdir($fn) {
if (strpos($fn,"/") !== false) {
$p=substr(substr($fn,0,strrpos($fn,"/")),0,250);
if (!is_dir($p)) {
mkdir($p,755,true);
}
}
}
function imagecreatefrombmp($p_sFile) { // by alexander at http://www.php.net/manual/en/function.imagecreatefromwbmp.php
// Load the image into a string
$file = fopen($p_sFile,"rb");
$read=fread($file,10);
while(!feof($file)&&($read<>""))
$read.=fread($file,1024);
$temp=unpack("H*",$read);
$hex=$temp[1];
$header=substr($hex,0,108);
// Process the header
// Structure: http://www.fastgraph.com/help/bmp_header_format.html
if (substr($header,0,4) == "424d") {
// Cut it in parts of 2 bytes
$header_parts=str_split($header,2);
// Get the width4 bytes
$width=hexdec($header_parts[19].$header_parts[18]);
// Get the height4 bytes
$height=hexdec($header_parts[23].$header_parts[22]);
// Unset the header params
unset($header_parts);
}
// Define starting X and Y
$x=0;
$y=1;
// Create newimage
$image=imagecreatetruecolor($width,$height);
// Grab the body from the image
$body=substr($hex,108);
// Calculate if padding at the end-line is needed
// Divided by two to keep overview.
// 1 byte = 2 HEX-chars
$body_size=(strlen($body)/2);
$header_size=($width*$height);
// Use end-line padding? Only when needed
$usePadding=($body_size>($header_size*3)+4);
// Using a for-loop with index-calculation instaid of str_split to avoid large memory consumption
// Calculate the next DWORD-position in the body
for ($i=0;$i < $body_size;$i+=3) {
// Calculate line-ending and padding
if ($x >= $width) {
// If padding needed, ignore image-padding
// Shift i to the ending of the current 32-bit-block
if ($usePadding)
$i+=$width%4;
// Reset horizontal position
$x=0;
// Raise the height-position (bottom-up)
$y++;
// Reached the image-height? Break the for-loop
if ($y > $height)
break;
}
// Calculation of the RGB-pixel (defined as BGR in image-data)
// Define $i_pos as absolute position in the body
$i_pos=$i*2;
$r=hexdec($body[$i_pos+4].$body[$i_pos+5]);
$g=hexdec($body[$i_pos+2].$body[$i_pos+3]);
$b=hexdec($body[$i_pos].$body[$i_pos+1]);
// Calculate and draw the pixel
$color=imagecolorallocate($image,$r,$g,$b);
imagesetpixel($image,$x,$height-$y,$color);
// Raise the horizontal position
$x++;
}
// Unset the body / free the memory
unset($body);
// Return image-object
return $image;
}
function img_force($src,$quality,$w,$h,$saveas,$nocrop,$force) {
foreach (array("jpg","gif","png") as $x) { // will skip bmp formats
if ($x != $force) {
if (img_resizer($src,$quality,$w,$h,$saveas,$nocrop,$x)) {
return 1;
break;
}
}
}
return 0;
}
function img_resizer($src,$quality,$w,$h,$saveas,$nocrop=0,$force=0) { /* v2.72 with auto crop, no crop, automatic file type detection when avalible (requires exif library) */
if (!is_file($src)) { _o("Source is not a file.");return 0; }
if (!is_readable($src)) { _o("Can't read: ".$src);return 0; }
if ((file_exists($saveas)) && (!is_writeable($saveas))) { _o("Can't write to: ".$saveas);return 0; }
$r=1;
if (function_exists('exif_imagetype')) { // automatic filetype detection
$e=exif_imagetype($src);
if ($e == IMAGETYPE_JPEG) {
if (!$OldImage=@ImageCreateFromJpeg($src)) { $r=0; }
} elseif ($e == IMAGETYPE_GIF) {
if (!$OldImage=@ImageCreateFromGif($src)) { $r=0; }
} elseif ($e == IMAGETYPE_BMP) { // custom
if (!$OldImage=@ImageCreateFrombmp($src)) { $r=0; }
} elseif ($e == IMAGETYPE_WBMP) {
if (!$OldImage=@ImageCreateFromwbmp($src)) { $r=0; }
} elseif ($e == IMAGETYPE_PNG) {
if (!$OldImage=@ImageCreateFromPng($src)) { $r=0; }
} else {
_o("Not a Valid Image! (".$e.") -- ".$src);$r=0;
}
} else { // filename based filetype detection, might be subject to incorrect file extensions, resulting on a error, which when enabled will fall into a try and error `force` mode
$e=($force == "0") ? strtolower(substr($src,strrpos($src,".")+1)) : $force;
if (($e == "jpg") || ($e == "jpeg")) {
if (!$OldImage=@ImageCreateFromJpeg($src)) { $r=0; }
} elseif ($e == "gif") {
if (!$OldImage=@ImageCreateFromGif($src)) { $r=0; }
} elseif ($e == "bmp") { // this is NOT wbmp
if (!$OldImage=@ImageCreateFrombmp($src)) { $r=0; }
} elseif ($e == "png") {
if (!$OldImage=@ImageCreateFromPng($src)) { $r=0; }
} else {
_o("Not a Valid Image! (".$e.") -- ".$src);$r=0;
}
}
if ($r) {
list($width,$height)=getimagesize($src);
// check if ratios match
$_ratio=array($width/$height,$w/$h);
if ($_ratio[0] != $_ratio[1]) { // ratio don't match
if ($nocrop) { // since we can't crop we will need to do image on a different height/width
$hx = (100 / ($width / $w)) * .01;
$hx = @round ($height * $hx);
$wx = (100 / ($height / $h)) * .01;
$wx = @round ($width * $wx);
if ($hx < $h) {
$h = (100 / ($width / $w)) * .01;
$h = @round ($height * $h);
} else {
$w = (100 / ($height / $h)) * .01;
$w = @round ($width * $w);
}
} else { // crop image
// find the right scale to use
$_scale=min((float)($width/$w),(float)($height/$h));
// coords to crop
$cropX=(float)($width-($_scale*$w));
$cropY=(float)($height-($_scale*$h));
// cropped image size
$cropW=(float)($width-$cropX);
$cropH=(float)($height-$cropY);
$crop=ImageCreateTrueColor($cropW,$cropH);
ImageCopy($crop,$OldImage,0,0,(int)($cropX/2),(int)($cropY/2),$cropW,$cropH); // crop the middle part of the image to fit the thumbnail's proportions
}
}
// do the thumbnail
$NewThumb=ImageCreateTrueColor($w,$h);
if (isset($crop)) { // been cropped
ImageCopyResampled($NewThumb,$crop,0,0,0,0,$w,$h,$cropW,$cropH);
ImageDestroy($crop);
} else { // ratio match, regular resize
ImageCopyResampled($NewThumb,$OldImage,0,0,0,0,$w,$h,$width,$height);
}
_ckdir($saveas);
ImageJpeg($NewThumb,$saveas,$quality);
ImageDestroy($NewThumb);
ImageDestroy($OldImage);
} elseif (($force == "0") && (!function_exists('exif_imagetype'))) {
$r=img_force($src,$quality,$w,$h,$saveas,$nocrop,$e);
}
return $r;
}
See how nice it looks with the syntax highligher? :P
Updates:
100407 – Added imagebmp function to save as bmp;
Alternate method for background images
by z3n on May.20, 2009, under Tips & Hints
Problem:
When you need to build up a page with lots of little images , like the borders, gradients, different backgrounds , slideshows etc. All into the same page.
You probably will have lots of images on the same page, specially if you cut them to save much bytes as you can, however, you might fall into a different issue:
Too many images will make the load slow as well, since browser will open only 2 connections at same time with the server (every connection takes a while to actually start downloading something since it needs to go thuru all the hops and reach the server etc etc), meaning that all that nice optmization you did worth nothing since you got lots of images.
No good!
Solution:
I’ve seen this only one time at fleXcroll script, and many times on old games textures.
The technique used on both is the same, although might not ring a bell for you it’s pretty simple to use, a little complicated to add on css, but will do the work.

picmap png file zoomed
This is a zoomed version of a picmap (I don’t really know a formal name for this that’s how i will call it) png I did, you can see it got transparency and stuff.
The different colors and green lines are just to highlight the different images i merged here, they will be used all in background at the css, meaning that i can have the position easily set.
As you can see on the bottom there’s 2 huge blocks, this is for the horizontal repeat, since i can’t define a fixed area on the image for the browser to pick as pattern for repeat-x (for example) I need to do this. You may think that it would be a waste, since usually, you can do a 1px width image for this type of thing, however, when you merge pictures toguether you’re not only saving the connection delay time, but for some image formats you have a header on the file or a color index that, when merged, became smaller than the separated files.
In the original 2,65kb png, I managed to merge 17 different pictures, that separated were 4,79kb, and yet you can see that there still some space left to add more things if i wanted to.
The css for the top circle (which is actually 4 corners) would look like this:
.bB,.bC,.bD,.bE{height:9px;width:9px;font-size:1px;}
.bB{background:url(img/b.png) 0px 0px;}
.bC{background:url(img/b.png) -9px 0px;}
.bD{background:url(img/b.png) -9px -9px;}
.bE{background:url(img/b.png) 0px -9px;}
Note that all the positions are negative.
Depending on the usage of your picmap you might want to have repeat-y’s for example, so you need to rethink the layout in order to take maximum of it.
For me, i only have repeat-x backgrounds, so I broke it in different formats, gif, png and jpg, doing that I could take the best of each.
A Decent PHP Resizer with auto cropping
by z3n on Apr.27, 2009, under Coding, Tips & Hints
Problem:
Resize an image to any size without having black areas, even if the resized image ratio is no match with the original image.
Solution:
When the resized image ratio is no match we will crop the proportional middle area of the original then resize it using the right ratio.
More Information:
PHP Manual page for ImageCopyResampled.
* ratio = width / height