Duplicated thumbnail images inside php image sprite

308 views Asked by At

I'm working on linux, xampp and wordpress testing theme with style.css and index.php.

I created php script using GD library that creates image sprite. It can conditionally creates sprite from given folder(glob), or from urls (array). It also scale all thumbnails in the fly to fit a given bounding box(not my function).

My problem is that all thumbnails are duplicated inside next thumbnails. Like: First image is duplicated in 2, 2 in 3, 3 in 4(...). However proper image is always on top of duplicated image.

I think my loop or merging thumbnail have problems, but I'm not sure.

Here is my code (by default creates sprite from array):

<?php

//////// PART 1 - DEFINE GLOBAL VARIABLES ////////

//// SPRITE IMAGES SOURCE ////
// 0 = Create sprite from memory - array()
// 1 = Create sprite from folder - glob()
$sprite_images_source = 0;

//// Use array as sprite images source ////
if($sprite_images_source == 0){
  $images=array(
    //// Example .PNGs ////
    // Orientation: Horizontal, smaller than bounding box
    'https://dummyimage.com/128x72/444/f2f2f2.png&text=128x72.png',
    // Orientation: Horizontal, bigger than bounding box
    'https://dummyimage.com/1280x720/444/f2f2f2.png&text=1280x720.png',
    // Orientation: Vertical, smaller than bounding box
    'https://dummyimage.com/72x128/444/f2f2f2.png&text=72x128.png',
    // Orientation: Vertical, bigger than bounding box
    'https://dummyimage.com/720x1280/444/f2f2f2.png&text=720x1280.png',
    // Square, smaller than bounding box
    'https://dummyimage.com/200x200/444/f2f2f2.png&text=400x400.png',

    //// Example .JPEGs ////
    // Orientation: Horizontal, smaller than bounding box
    'https://dummyimage.com/128x72/666/f2f2f2.jpg&text=128x72.jpg',
    // Orientation: Horizontal, bigger than bounding box
    'https://dummyimage.com/1280x720/666/f2f2f2.jpg&text=1280x720.jpg',
    // Orientation: Vertical, smaller than bounding box
    'https://dummyimage.com/72x128/666/f2f2f2.jpg&text=72x128.jpg',
    // Orientation: Vertical, bigger than bounding box
    'https://dummyimage.com/720x1280/666/f2f2f2.jpg&text=720x1280.jpg',
    // Square
    'https://dummyimage.com/200x200/666/f2f2f2.jpg&text=200x200.jpg',

    //// Example .GIFs ////
    // Orientation: Horizontal, smaller than bounding box
    'https://dummyimage.com/128x72/888/f2f2f2.gif&text=128x72.gif',
    // Orientation: Horizontal, bigger than bounding box
    'https://dummyimage.com/1280x720/888/f2f2f2.gif&text=1280x720.gif',
    // Orientation: Vertical, smaller than bounding box
    'https://dummyimage.com/72x128/888/f2f2f2.gif&text=72x128.gif',
    // Try to have 1/3/5/7 images to see empty space on sprite,
    // and test colorize sprite background method with this

  );

//// Use folder as sprite images source ////
} else if($sprite_images_source == 1){
 // $images = glob('sprite/images/*');
}


//// SINGLE THUMBNAIL = BOUNDING BOX DIMENSIONS ////
$thumbnail_width = 300;
$thumbnail_height = 300;
$thumbnail = imagecreatetruecolor($thumbnail_width, $thumbnail_height);


//// SPRITE DIMENSIONS ////
$sprite_columns = 5;
$sprite_rows = ceil(count($images) / $sprite_columns);
$sprite_width = $thumbnail_width * $sprite_columns;
$sprite_height = $thumbnail_height * $sprite_rows;
$sprite = imagecreatetruecolor($sprite_width, $sprite_height);


//// SPRITE BACKGROUND COLOR ////
$sprite_bg = imagecolortransparent($sprite, imagecolorallocatealpha($sprite, 0,0,0,0));
imagefill($sprite,0,0,$sprite_bg);


//////// PART 2 - GENERATE SPRITE ////////

//// Assign each source from array to single image
foreach ($images as $i => $image) {
  $images[$i] = array(
    'src' => $image,
    'title' => 'Product ' . ($i + 1),
    'price' => '$' . ($i * 100)
  );
}


//// SINGLE THUMBNAIL MANIPULATION ////
// Start Generate Thumbnail from first file in array/folder
$i = 0;

for ($y = 0; $y < $sprite_height; $y += $thumbnail_height) {
  for ($x = 0; $x < $sprite_width; $x += $thumbnail_width) {
    // What is this for ???
    if ($i >= count($images)) {
      break 2;
    }

    // Assosiate correct image for thumbnail from array
    $image = $images[$i];
    $src = imagecreatefromstring(file_get_contents($image['src']));

    // Scale Image to Bounding Box
    scale_image($src, $thumbnail, 'fit');


    //// PRINT IMAGE INTO SINGLE THUMBNAIL ////
    imagecopy($sprite, $thumbnail, $x, $y, 0, 0, $thumbnail_width, $thumbnail_height);
    imagedestroy($src);
    $i++;
  }
  // END | for ($y = 0; $y < $sprite_height; $y += $thumbnail_height)
}
// END | for ($y = 0; $y < $sprite_height; $y += $thumbnail_height)


//////// PART 3 - OUTPUT SPRITE ////////

// Output Sprite to Browser as PNG
header('Content-Type: image/png');
imagepng($sprite);

// Clean up, and free memory
imagedestroy($thumbnail);
imagedestroy($sprite);


// FUNCTION - SCALE IMAGE
function scale_image($src_image, $dst_image, $op = 'fit') {
  $src_width = imagesx($src_image);
  $src_height = imagesy($src_image);

  $dst_width = imagesx($dst_image);
  $dst_height = imagesy($dst_image);

  // Try to match destination image by width
  $new_width = $dst_width;
  $new_height = round($new_width*($src_height/$src_width));
  $new_x = 0;
  $new_y = round(($dst_height-$new_height)/2);

  // FILL and FIT mode are mutually exclusive
  if ($op =='fill')
    $next = $new_height < $dst_height;
  else
    $next = $new_height > $dst_height;

  // If match by width failed and destination image does not fit, try by height
  if ($next) {
    $new_height = $dst_height;
    $new_width = round($new_height*($src_width/$src_height));
    $new_x = round(($dst_width - $new_width)/2);
    $new_y = 0;
  }

  // Copy image on right place
  imagecopyresampled($dst_image, $src_image , $new_x, $new_y, 0, 0, $new_width, $new_height, $src_width, $src_height);
}
2

There are 2 answers

3
Vishal Kumar Sahu On

Gabrielle, my english is poorer than you. Let me help you to let you help yourself...

Actually the problem is with your $thumbnail handling which is being kept inside scale_image function in $dst_image, that is why it is repeating...

I tried writing (imagepng($thumbnail,'images/image_xyzzz_i.png');) $thumbnail and destroying it. The overlapping images were created. While I tried destroying $dst_image inside scale_image function, it destroyed $thumbnail too. Get rid of this relation.

UPDATE....

You can see it clearly that sprite is only affected by $thumbnail .

Result For Thumbnail at different stages

UPDATE - 2

Here is your modified code... Just two copy and pastes...

<?php

//////// PART 1 - DEFINE GLOBAL VARIABLES ////////

//// SPRITE IMAGES SOURCE ////
// 0 = Create sprite from memory - array()
// 1 = Create sprite from folder - glob()
$sprite_images_source = 0;

//// Use array as sprite images source ////
if($sprite_images_source == 0){
  $images=array(
    //// Example .PNGs ////
    // Orientation: Horizontal, smaller than bounding box
    'https://dummyimage.com/128x72/444/f2f2f2.png&text=128x72.png',
    // Orientation: Horizontal, bigger than bounding box
    'https://dummyimage.com/1280x720/444/f2f2f2.png&text=1280x720.png',
    // Orientation: Vertical, smaller than bounding box
    'https://dummyimage.com/72x128/444/f2f2f2.png&text=72x128.png',
    // Orientation: Vertical, bigger than bounding box
    'https://dummyimage.com/720x1280/444/f2f2f2.png&text=720x1280.png',
    // Square, smaller than bounding box
    'https://dummyimage.com/200x200/444/f2f2f2.png&text=400x400.png',

    //// Example .JPEGs ////
    // Orientation: Horizontal, smaller than bounding box
    'https://dummyimage.com/128x72/666/f2f2f2.jpg&text=128x72.jpg',
    // Orientation: Horizontal, bigger than bounding box
    'https://dummyimage.com/1280x720/666/f2f2f2.jpg&text=1280x720.jpg',
    // Orientation: Vertical, smaller than bounding box
    'https://dummyimage.com/72x128/666/f2f2f2.jpg&text=72x128.jpg',
    // Orientation: Vertical, bigger than bounding box
    'https://dummyimage.com/720x1280/666/f2f2f2.jpg&text=720x1280.jpg',
    // Square
    'https://dummyimage.com/200x200/666/f2f2f2.jpg&text=200x200.jpg',

    //// Example .GIFs ////
    // Orientation: Horizontal, smaller than bounding box
    'https://dummyimage.com/128x72/888/f2f2f2.gif&text=128x72.gif',
    // Orientation: Horizontal, bigger than bounding box
    'https://dummyimage.com/1280x720/888/f2f2f2.gif&text=1280x720.gif',
    // Orientation: Vertical, smaller than bounding box
    'https://dummyimage.com/72x128/888/f2f2f2.gif&text=72x128.gif',
    // Try to have 1/3/5/7 images to see empty space on sprite,
    // and test colorize sprite background method with this

  );

//// Use folder as sprite images source ////
} else if($sprite_images_source == 1){
 // $images = glob('sprite/images/*');
}


//// SINGLE THUMBNAIL = BOUNDING BOX DIMENSIONS ////
$thumbnail_width = 300;
$thumbnail_height = 300;
################# CUT LINE 1 FROM HERE ########################


//// SPRITE DIMENSIONS ////
$sprite_columns = 5;
$sprite_rows = ceil(count($images) / $sprite_columns);
$sprite_width = $thumbnail_width * $sprite_columns;
$sprite_height = $thumbnail_height * $sprite_rows;
$sprite = imagecreatetruecolor($sprite_width, $sprite_height);


//// SPRITE BACKGROUND COLOR ////
$sprite_bg = imagecolortransparent($sprite, imagecolorallocatealpha($sprite, 0,0,0,0));
imagefill($sprite,0,0,$sprite_bg);


//////// PART 2 - GENERATE SPRITE ////////

//// Assign each source from array to single image
foreach ($images as $i => $image) {
  $images[$i] = array(
    'src' => $image,
    'title' => 'Product ' . ($i + 1),
    'price' => '$' . ($i * 100)
  );
}


//// SINGLE THUMBNAIL MANIPULATION ////
// Start Generate Thumbnail from first file in array/folder
$i = 0;

for ($y = 0; $y < $sprite_height; $y += $thumbnail_height) {
  for ($x = 0; $x < $sprite_width; $x += $thumbnail_width) {
    // What is this for ???
    if ($i >= count($images)) {
      break 2;
    }


############################# PASTED LINE 1 HERE ######################
$thumbnail = imagecreatetruecolor($thumbnail_width, $thumbnail_height);
#######################################################################

    // Assosiate correct image for thumbnail from array
    $image = $images[$i];
    $src = imagecreatefromstring(file_get_contents($image['src']));

    // Scale Image to Bounding Box
    scale_image($src, $thumbnail, 'fit');


    //// PRINT IMAGE INTO SINGLE THUMBNAIL ////
    imagecopy($sprite, $thumbnail, $x, $y, 0, 0, $thumbnail_width, $thumbnail_height);
    imagedestroy($src);
    $i++;

######################## PASTED LINE 2 HERE ###########################
imagedestroy($thumbnail);
#######################################################################

  }
  // END | for ($y = 0; $y < $sprite_height; $y += $thumbnail_height)
}
// END | for ($y = 0; $y < $sprite_height; $y += $thumbnail_height)


//////// PART 3 - OUTPUT SPRITE ////////

// Output Sprite to Browser as PNG
header('Content-Type: image/png');
imagepng($sprite);

// Clean up, and free memory
######################## CUT LINE 2 HERE ###########################
imagedestroy($sprite);


// FUNCTION - SCALE IMAGE
function scale_image($src_image, $dst_image, $op = 'fit') {
  $src_width = imagesx($src_image);
  $src_height = imagesy($src_image);

  $dst_width = imagesx($dst_image);
  $dst_height = imagesy($dst_image);

  // Try to match destination image by width
  $new_width = $dst_width;
  $new_height = round($new_width*($src_height/$src_width));
  $new_x = 0;
  $new_y = round(($dst_height-$new_height)/2);

  // FILL and FIT mode are mutually exclusive
  if ($op =='fill')
    $next = $new_height < $dst_height;
  else
    $next = $new_height > $dst_height;

  // If match by width failed and destination image does not fit, try by height
  if ($next) {
    $new_height = $dst_height;
    $new_width = round($new_height*($src_width/$src_height));
    $new_x = round(($dst_width - $new_width)/2);
    $new_y = 0;
  }

  // Copy image on right place
  imagecopyresampled($dst_image, $src_image , $new_x, $new_y, 0, 0, $new_width, $new_height, $src_width, $src_height);
}
0
Vishal Kumar Sahu On

Move this line of code

$thumbnail = imagecreatetruecolor($thumbnail_width, $thumbnail_height);

After these lines and

    for ($y = 0; $y < $sprite_height; $y += $thumbnail_height) {
      for ($x = 0; $x < $sprite_width; $x += $thumbnail_width) {
        // What is this for ???
        if ($i >= count($images)) {
          break 2;
        }
################## MOVE THAT LINE HERE ##################

and do not forget to use

imagedestroy($thumbnail);

before loop ends.

Hope this helps to remove the overlapping images.

UPDATE Your code is working and the problem was repeat of thumbnail handle. Here is resultant snap compared with that of my previous answer.

Here is the success result compared to my previous answer...[1]