Chris Brown
Chris Brown

Reputation: 4635

PHP GD - Merge multiple images in tiled layout

I'm working on a class that takes an array of images by src and merges them into a single tiled image, similar to the following image;

Example "tiled" output

The only issue is the images provided to the class aren't of set dimensions like in the image above.

The following state of the class creates a vertically stacked list of the images without gaps (an example shown below), and calculates the required height of the export image automatically (calculated in $total_height).

enter image description here

I imagine gaps are inevitable in the final output one way or another due to the infinite variation in image dimensions, but I'm not sure where to start in incorporating tiling horizontally as well as vertically.

class BoardCreator {

private $_img_type;
private $_img_urls = array();

public function __construct($img_export_type, array $img_urls) {
    $this->_img_type = $img_export_type;    // File format for exported image
    $this->_img_urls = $img_urls;           // Array of image URLs
}


public function GenerateBoard() {

    /*
     * Arrays to hydrate with loaded image properties & resources
     */
    $images = array();  // Image resources
    $width = array();   // Image widths
    $height = array();  // Image heights

    $total_height = 0;  // Total height required for the board

    /*
     * Load in each image, and store its width & height
     */
    for ($i=0; $i < count($this->_img_urls); $i++) {

        switch (exif_imagetype($this->_img_urls[$i])) {
            case IMAGETYPE_JPEG :
                $images[$i] = imagecreatefromjpeg($this->_img_urls[$i]);
                break;

            case IMAGETYPE_PNG :
                $images[$i] = imagecreatefrompng($this->_img_urls[$i]);
                break;

            case IMAGETYPE_GIF :
                $images[$i] = imagecreatefromgif($this->_img_urls[$i]);
                break;

            // default w/ error required
        }

        // Store the image's dimensions
        list($width[$i], $height[$i])  = getimagesize($this->_img_urls[$i]);

        // Add this image's height to the required canvas height
        $total_height = $total_height + $height[$i];
    }

    /*
     * Create a new "canvas" image with specified dimensions
     */

    $canvas_image = imagecreatetruecolor($width[0], $total_height);

    /*
     * Copy each image into the "canvas" image generated above
     */

    $current_x = 0;
    $current_y = 0;

    for ($i=0; $i < count($images); $i++) {
        imagecopy(
            $canvas_image,  // destination image
            $images[$i],    // source image
            0,              // x co-ordinate of destination
            $current_y,     // y co-ordinate of destination
            0,              // x co-ordinate of source
            0,              // y co-ordinate of source
            $width[$i],     // source img width
            $height[$i]     // source img height
        );

        $current_y = $current_y + $height[$i];
    }

    /*
     * Save the resulting image in the format specified at initiation
     */

    switch ($this->_img_type) {
        case "jpg" :
            $images[$i] = imagejpeg($canvas_image, "../board_exports/test.jpg");
            break;

        case "png" :
            $images[$i] = imagepng($canvas_image, "../board_exports/test.png");
            break;

        case "gif" :
            $images[$i] = imagegif($canvas_image, "../board_exports/test.gif");
            break;

        default :
            // Create an error to handle here
            die("Error in BoardCreator.php (Method GenerateBoard() )");
            break;
    }

    /*
     * Release the created image from memory
     */
    imagedestroy($canvas_image);

    /*
     * Loop through and release each loaded image
     */
    for ($i=0; $i < count($this->_img_urls); $i++) {
        imagedestroy($images[$i]);
    }

}

Upvotes: 0

Views: 2070

Answers (1)

kraysak
kraysak

Reputation: 1756

i made this code to help you.

1.- to fix "the infinite variation in image dimensions" i make thumbnails of images with this function:

function generate_image_thumbnail($source_image_path, $thumbnail_image_path,$THUMBNAIL_IMAGE_MAX_WIDTH,$THUMBNAIL_IMAGE_MAX_HEIGHT)
{
        $condicion = GetImageSize($source_image_path); // image format?
        if($condicion[2] == 1) //gif
        $original = imagecreatefromgif("$source_image_path");
        if($condicion[2] == 2) //jpg
        $original = imagecreatefromjpeg("$source_image_path");
        if($condicion[2] == 3) // png
        $original = imagecreatefrompng("$source_image_path");

        $thumb = imagecreatetruecolor($THUMBNAIL_IMAGE_MAX_WIDTH,$THUMBNAIL_IMAGE_MAX_HEIGHT); 

        $ancho = imagesx($original);
        $alto = imagesy($original);
        imagecopyresampled($thumb,$original,0,0,0,0,$THUMBNAIL_IMAGE_MAX_WIDTH,$THUMBNAIL_IMAGE_MAX_HEIGHT,$ancho,$alto);
        
        imagejpeg($thumb,$thumbnail_image_path,90);
    return true;
}

2.- create an image to paste the thumbnails

$size_image=460;

$img_disp = imagecreatetruecolor($size_image,$size_image);
$backcolor = imagecolorallocate($img_disp,0,0,0);
imagefill($img_disp,0,0,$backcolor);

3.- start to paste the thumbnails

//$THUMBNAIL_IMAGE=150;
 $images_by_side = round($size_image/$THUMBNAIL_IMAGE); // round(460/150)=3  3 images by side
        $separator = $size_image%$THUMBNAIL_IMAGE;     //150*3=450... so 10px in total of space
        $space_btwen_images=$separator/($images_by_side+1);  //10px / 3 of total images + 1 =2,5
        $total_image = pow($images_by_side , 2 );  //total images to paste (images by side)^2.. 3^2=9
    
//some math calculations to make more nice the output image

        $dst_x=$space_btwen_images;
        $cont_imgs=0;
        for($x=0;$x<$total_image;$x++) {
        
                if($cont_imgs == $images_by_side){      
                $dst_x=$dst_x+$THUMBNAIL_IMAGE+$space_btwen_images;
                $cont_imgs=0;
                }
                $dst_y=$cont_imgs*$THUMBNAIL_IMAGE+($space_btwen_images * ($cont_imgs+1));
                $cont_imgs++;   
                
                $thumb_image=$img_tmb_dir.$arr_img[$x];  //image to paste
                    $condicion = GetImageSize($thumb_image); // image format?
    
                    if($condicion[2] == 1) //  gif
                    $image_to_copy = imagecreatefromgif("$thumb_image");
                    if($condicion[2] == 2) //  jpg
                    $image_to_copy = imagecreatefromjpeg("$thumb_image");
                    if($condicion[2] == 3) // png
                    $image_to_copy = imagecreatefrompng("$thumb_image");
                    
                    echo "dst_x=".$dst_x.";  dst_y=".$dst_y.";<br>";
                    //output to check the destinations of the images to paste
            /*
            dst_x=2.5; dst_y=2.5;
            dst_x=2.5; dst_y=155;
            dst_x=2.5; dst_y=307.5;
            dst_x=155; dst_y=2.5;
            dst_x=155; dst_y=155;
            dst_x=155; dst_y=307.5;
            dst_x=307.5; dst_y=2.5;
            dst_x=307.5; dst_y=155;
            dst_x=307.5; dst_y=307.5;
            */

                    imagecopy($img_disp, $image_to_copy, $dst_x, $dst_y, 0, 0, $THUMBNAIL_IMAGE, $THUMBNAIL_IMAGE);
    
        }
        imagejpeg($img_disp, "test3.jpg",90);
        imageDestroy($img_disp);
        echo '<img src="test3.jpg"/>';

4.-

  1. with my images (150 x 150) and $size_image=460; will return

    image1

  2. and $size_image=610 will return

image2

Upvotes: 2

Related Questions