Matteo Corona Matteo Corona - 7 months ago 16
PHP Question

math formula behind code

Does anyone know the mathematical formula that relates the following strings of code ?

// aspect ratio <
$src_pos = array(0, (($new_size[1] - $thumb_height) * ($src_size[1] /$new_size[1])) / 2 );
// aspect ratio >
$src_pos = array((($new_size[0] - $thumb_width) * ($src_size[0] / $new_size[0])) / 2, 0);


They are inside a wider script that creates thumbs from uploaded images:

//variables
$src_size = getimagesize($_FILES["file"]["name"]);
$thumb_width = 250;
$thumb_height = 200;
$src_aspect = round(($src_size[0] / $src_size[1]), 1);
$thumb_aspect = round(($thumb_width / $thumb_height), 1);

if ($src_aspect < $thumb_aspect){
//higher
$new_size = array($thumb_width,($thumb_width / $src_size[0]) * $src_size[1]);
$src_pos = array(0, (($new_size[1] - $thumb_height) * ($src_size[1] /$new_size[1])) / 2 );
}else if($src_aspect > $thumb_aspect){
//wider
$new_size = array(($thumb_width / $src_size[1]) * $src_size[0], $thumb_height);
$src_pos = array((($new_size[0] - $thumb_width) * ($src_size[0] / $new_size[0])) / 2, 0);
}else{
//same shape
$new_size = array($thumb_width, $thumb_height);
$src_pos = array(0, 0);
}

if ($new_size[0] < 1) $new_size[0] = 1;
if ($new_size[1] < 1) $new_size[1] = 1;


//creation of thumb
$thumb = imagecreatetruecolor($thumb_width, $thumb_height);
imagecopyresampled($thumb, $src, 0, 0, $src_pos[0], $src_pos[1], $new_size[0], $new_size[1], $src_size[0], $src_size[1]);


I am studing this script but I cant understand the logic behind the two lines of code I wrote at the beginning of this question, so I'd like to know which mathematical formula they are related to.

Answer

you need to look at each aspect ratio if part separately you mixed them together which is a bit confusing from start (added the comments to your question).

I see it like this:

// load image
$src_size = getimagesize($_FILES["file"]["name"]);
// static fixed resolution for the thumb
$thumb_width = 250; 
$thumb_height = 200;
// aspects (if the x or y size is bigger for image and thumb
$src_aspect = round(($src_size[0] / $src_size[1]), 1);
$thumb_aspect = round(($thumb_width / $thumb_height), 1);

// rescale height because the result will not exceeding thumb height in this case
if ($src_aspect < $thumb_aspect){
    $new_size = array
     (
     $thumb_width,                                 // thumb width stays as is
     ($thumb_width / $src_size[0]) * $src_size[1]  // thumb height is rescaled by image aspect
     );
    // this just compute the distance to move the thumb after rescaling so it is still centered
    $src_pos = array(0, (($new_size[1] - $thumb_height) * ($src_size[1] /$new_size[1])) / 2 );
}
// rescale width because the result will not exceeding thumb width in this case
else if($src_aspect > $thumb_aspect){
    $new_size = array
     (
     ($thumb_width / $src_size[1]) * $src_size[0],  // thumb width is rescaled by image aspect
     $thumb_height                                 // thumb height stays as is
     );
    // this just compute the distance to move the thumb after rescaling so it is still centered
    $src_pos = array((($new_size[0] - $thumb_width) * ($src_size[0] / $new_size[0])) / 2, 0);
}else{
    //same shape
    $new_size = array($thumb_width, $thumb_height);
    $src_pos = array(0, 0);
}

if ($new_size[0] < 1) $new_size[0] = 1;
if ($new_size[1] < 1) $new_size[1] = 1;


//creation of thumb
$thumb = imagecreatetruecolor($thumb_width, $thumb_height);
imagecopyresampled($thumb, $src, 0, 0, $src_pos[0], $src_pos[1], $new_size[0], $new_size[1], $src_size[0], $src_size[1]);

I hope the comments are enough for you ... but to be sure let us examine:

  • ( $thumb_width / $src_size[0]) * $src_size[1]

I would use this instead (so just integer math can be used)

  • ( $thumb_width * $src_size[1] ) / $src_size[0]

So $thumb_width is the thumb nail target maximal resolution and $src_size[1] / $src_size[0] is image aspect ratio constant less then 1.0. When you look at the whole line more closely it is simple linear interpolation without offset (starting point is at (0,0)) so the result will be smaller then thumbnail resolution (will fit inside) and still be matching original image aspect ratio.

Mathematical formula:

  • lets have 2 points (x0,y0) and (x1,y1) representing endpoints of a line.
  • and some arbitrary point (x,y) inside/on the line

So if we know one coordinate of a point on line we can compute the other by exploiting triangle similarities like this:

  • x=x0+(y-y0)*(x1-x0)/(y1-y0)
  • y=y0+(x-x0)*(y1-y0)/(x1-x0)

This is called linear interpolation. As in your case (x0,y0)=(0,0) then the equation became:

  • x=y*x1/y1
  • y=x*y1/x1

Which is what your code represents... while x,y is new_size and x1,y1 is src_size

Now the position offset

for example you computed it like this:

  • ($new_size[0] - $thumb_width) * ($src_size[0] / $new_size[0])) / 2 so the terms are:
  • ($new_size[0] - $thumb_width) is empty space between new and original thumbnail resolution
  • ($new_size[0] - $thumb_width)/2 is how much you need to shift resized thumbnail to place it in the middle of original thumbnail resolution
  • ($src_size[0] / $new_size[0]) is just scale converting this offset from thumbnail coordinates to image coordinate system

When you put all together you got position which is a bit outside the image (so the missing data is filled with background color) So when copied data from image to thumbnail from this position you got the rescaled thumbnail image centered with empty space around the rescaled axis... (unless I am missing something)