View Raw SPL
/*****************************************************************************
*                                                                            *
*   IMCOMBINE.SPL   Copyright (C) 2026 DSP Development Corporation           *
*                               All Rights Reserved                          *
*                                                                            *
*   Author:      Randy Race                                                  *
*                                                                            *
*   Synopsis:    Combines multiple images into a single image                *
*                                                                            *
*   Revisions:   22 Jul 2026  RRR  Creation                                  *
*                                                                            *
*****************************************************************************/


#if @HELP_IMCOMBINE

    IMCOMBINE

    Purpose: Combine two or more images into a single image.

    Syntax:  IMCOMBINE(img1, img2, ..., imgN, direction, order, bg)

             imgN      - Two or more arrays, the input images.

             direction - Optional. An integer, the combination direction.

                          0: Combine horizontally (side-by-side, default)
                          1: Combine vertically (stacked).

             order     - Optional. An integer, the combination order.
              
                          0: Combine left to right or bottom to top (default).
                          1: Combine right to left or top to bottom.

             bg        - Optional. An integer, a color index for the
                         background color of unequal sized images.
                         Defaults to 15, WHITE.

    Returns: A single combined RGB image.

    Example:
             W1: readimage(gethome + "\data\kasha.jpg");scalesoff
             W2: W1;turbo;setaspect(-1);scalesoff
             W3: W1;paruline;setaspect(-1);scalesoff
             W4: imcombine(W1, W2, W3);scalesoff
             W5: imcombine(W1, W2, W3, 0, 1);scalesoff

             W1 loads a color JPEG image.

             W2 sets the image shading to TURBO.

             W3 sets the image shading to PARULINE.

             W4 horizontally combines the 3 images into a single image.

             W5 also horizontally combines the 3 images into a single image,
             except the images are ordered right to left.

    Example:
             W1: readimage(gethome + "\data\kasha.jpg");scalesoff
             W2: W1;turbo;setaspect(-1);scalesoff
             W3: W1;paruline;setaspect(-1);scalesoff
             W4: imcombine(W1, W2, W3, 1, 0);scalesoff
             W5: imcombine(W1, W2, W3, 1, 1);scalesoff

             W1 loads a color JPEG image.

             W2 sets the image shading to TURBO.

             W3 sets the image shading to PARULINE.

             W4 vertically combines the 3 images into a single image.

             W5 also vertically combines the 3 images into a single image,
             except the images are ordered top to bottom.

    Example:
             W1: readimage(gethome + "\data\kasha.jpg");scales(0)
             W2: readimage(gethome + "\data\kashadog.jpg");scales(0)
             W3: imcombine(w1, w2);scales(0)
             W4: imcombine(w1, w2, 0, 0, black);scales(0)

             W1 and W2 load two images of different sizes.

             W3 combines the images horizontally. The smaller image is
             padded with white pixels.

             W4 is the same as W3, except the smaller image is padded
             with black pixels.

    Remarks:
             IMCOMBINE combines two or more images into a single image.

             For images of different dimensions, the smaller ones are padded
             with the specified background color BG.

             All input images are converted to RGB if necessary.

             IMCOMBINE is particularly useful for creating side-by-side or
             stacked comparisons.

    See Also:
             Image24
             Readimage
             Rgb2hsv
             Rgb2mono
#endif


/* combine 2 or more images horizontally or vertically */
imcombine(argv)
{
        local images, outimages, j, direction = {}, order = {}, bg = {};
        local n, r, c, nr, nc, img, imz, imout;

        images = cell(argc, 1);

        n = 0;

        loop (j = 1..argc)
        {
                if (isarray(getargv(j)))
                {
                        /* convert to image24 */
                        images[++n] = image24(getargv(j));
                }
                else if (isscalar(getargv(j)))
                {
                        /* layout direction */
                        if (isempty(direction))
                        {
                                /* layout direction */
                                direction = getargv(j);
                        }
                        else if (isempty(order))
                        {
                                /* layout order */
                                order = getargv(j);
                        }
                        else if (isempty(bg))
                        {
                                /* background padding color */
                                bg = getargv(j);
                        }
                }
        }

        if (n < 2)
        {
                error(sprintf("%s - at least two input images required", __FUNC__));
        }

        nr = nc = 0;

        if (isempty(direction))
        {
                /* horizontal */
                direction = 0;
        }

        if (isempty(order))
        {
                /* L-R or B-T */
                order = 0;
        }

        if (isempty(bg))
        {
                /* bacground color index */
                bg = WHITE;
        }

        /* convert bg color to BGR colorref for image24 use */
        bg = color2colorref(bg);

        /* sizes */
        loop (j = 1..n)
        {
                (r, c) = size(images[j]);

                nr = max(r, nr);
                nc = max(c, nc);
        }

        outimages = cell(n, 1);

        /* size output images */
        loop (j = 1..n)
        {
                img = refseries(images[j]);
                imz = ones(nr, nc) * bg;

                /* fill from upper left with RGB pal values */
                imz[1..numrows(img), (nc - numcols(img)+1)..nc] = img;

                /* force RGB image */
                rgbimage(imz, 1);

                /* cell */
                outimages[j] = imz;
        }

        imout = {};

        if (direction > 0)
        {
                /* ravel all images for vertical display */
                if (order > 0)
                {
                        /* top to bottom */
                        loop (j = n..-1..1)
                        {
                                imout = ravel(imout, outimages[j]);
                        }
                }
                else
                {
                        /* bottom to top */
                        loop (j = 1..n)
                        {
                                imout = ravel(imout, outimages[j]);
                        }
                }
        }
        else
        {
                /* concat all images for side-by-side display */
                if (order > 0)
                {
                        /* right to left */
                        loop (j = n..-1..1)
                        {
                                imout = concat(imout, outimages[j]);
                        }
                }
                else
                {
                        /* left to right */
                        loop (j = 1..n)
                        {
                                imout = concat(imout, outimages[j]);
                        }
                }
        }

        /* force 24 bit image */
        rgbimage(imout, 1);

        /* units */
        setvunits(imout, getvunits(images[1]));
        sethunits(imout, gethunits(images[1]));
        setzunits(imout, getzunits(images[1]));

        /* force image display */
        setplotstyle(imout, 0);
        setplottype(imout, 5);

        if (outargc == 0)
        {
                /* natural aspect atio */
                setaspect(w0, -1);
        }


        return(imout);
}