Advanced Examples

Advanced image manipulation examples using BoxLang's image module.

Real-world examples demonstrating practical image manipulation techniques.

Table of Contents

Watermarking Images

Text Watermark

function addTextWatermark(sourcePath, text, outputPath) {
    img = ImageNew(sourcePath);

    // Configure watermark appearance
    img.setDrawingColor("white")
       .setDrawingStroke({
           width: 2,
           color: "black"
       })
       .setDrawingTransparency(70)  // 70% transparent
       .setAntialiasing(true);

    // Position in bottom-right corner
    textWidth = 200;  // Approximate text width
    x = img.getWidth() - textWidth - 20;
    y = img.getHeight() - 30;

    // Draw watermark
    img.drawText(text, x, y, {
        font: "Arial",
        size: 24,
        style: "bold"
    });

    img.write(outputPath);

    return outputPath;
}

// Usage
addTextWatermark(
    "photo.jpg",
    "© 2024 MyCompany",
    "watermarked.jpg"
);

Image Watermark

function addLogoWatermark(sourcePath, logoPath, position, opacity) {
    img = ImageNew(sourcePath);
    logo = ImageNew(logoPath);

    // Resize logo to 15% of image width
    targetWidth = img.getWidth() * 0.15;
    logo.scaleToFit(targetWidth, targetWidth);

    // Calculate position
    margin = 20;
    x = 0;
    y = 0;

    switch (position) {
        case "topLeft":
            x = margin;
            y = margin;
            break;
        case "topRight":
            x = img.getWidth() - logo.getWidth() - margin;
            y = margin;
            break;
        case "bottomLeft":
            x = margin;
            y = img.getHeight() - logo.getHeight() - margin;
            break;
        case "bottomRight":
            x = img.getWidth() - logo.getWidth() - margin;
            y = img.getHeight() - logo.getHeight() - margin;
            break;
        case "center":
            x = (img.getWidth() - logo.getWidth()) / 2;
            y = (img.getHeight() - logo.getHeight()) / 2;
            break;
    }

    // Apply watermark with opacity
    img.paste(logo, x, y, opacity);

    return img;
}

// Usage
watermarked = addLogoWatermark(
    "photo.jpg",
    "logo.png",
    "bottomRight",
    50  // 50% opacity
);

watermarked.write("watermarked.jpg");

Tiled Watermark

function addTiledWatermark(sourcePath, text, outputPath) {
    img = ImageNew(sourcePath);

    img.setDrawingColor("white")
       .setDrawingTransparency(85)  // Very transparent
       .setAntialiasing(true);

    // Rotate drawing axis for diagonal watermarks
    img.rotateDrawingAxis(45);

    // Tile watermark across image
    spacing = 200;
    for (x = 0; x < img.getWidth() + 500; x += spacing) {
        for (y = -500; y < img.getHeight() + 500; y += spacing) {
            img.drawText(text, x, y, {
                font: "Arial",
                size: 20,
                style: "bold"
            });
        }
    }

    img.write(outputPath);
    return outputPath;
}

// Usage
addTiledWatermark("photo.jpg", "CONFIDENTIAL", "watermarked.jpg");

Thumbnail Generation

Fixed-Size Thumbnails

function createThumbnail(sourcePath, size, outputPath) {
    img = ImageNew(sourcePath);

    // Resize to fit within size x size
    img.scaleToFit(size, size, "highQuality");

    // Optional: add border
    img.addBorder(2, "gray", "constant");

    img.write(outputPath);
    return outputPath;
}

// Generate 150x150 thumbnail
createThumbnail("photo.jpg", 150, "thumb_150.jpg");

Square Thumbnails with Crop

function createSquareThumbnail(sourcePath, size, outputPath) {
    img = ImageNew(sourcePath);

    // Calculate crop to center square
    dimension = min(img.getWidth(), img.getHeight());
    x = (img.getWidth() - dimension) / 2;
    y = (img.getHeight() - dimension) / 2;

    img.crop(x, y, dimension, dimension)
       .resize(size, size, "highQuality");

    img.write(outputPath);
    return outputPath;
}

// Create 200x200 square thumbnail
createSquareThumbnail("photo.jpg", 200, "thumb_square.jpg");

Multiple Thumbnail Sizes

function generateThumbnailSet(sourcePath, sizes) {
    img = ImageNew(sourcePath);
    results = {};

    for (size in sizes) {
        // Create copy for each size
        thumb = img.copy();
        thumb.scaleToFit(size, size, "highQuality");

        // Generate filename
        dir = getDirectoryFromPath(sourcePath);
        filename = getFileFromPath(sourcePath);
        name = listFirst(filename, ".");
        ext = listLast(filename, ".");

        outputPath = "#dir##name#_#size#.#ext#";
        thumb.write(outputPath);

        results["thumb_#size#"] = outputPath;
    }

    return results;
}

// Generate multiple sizes
thumbnails = generateThumbnailSet("photo.jpg", [100, 200, 400, 800]);
writeDump(thumbnails);

Image Compositing

Photo Collage

function createCollage(images, cols, spacing, outputPath) {
    // Calculate dimensions
    thumbSize = 200;
    rows = ceiling(arrayLen(images) / cols);

    canvasWidth = (cols * thumbSize) + ((cols + 1) * spacing);
    canvasHeight = (rows * thumbSize) + ((rows + 1) * spacing);

    // Create canvas
    canvas = ImageNew(canvasWidth, canvasHeight, "rgb", "white");

    // Place images
    currentRow = 0;
    currentCol = 0;

    for (imagePath in images) {
        img = ImageNew(imagePath);
        img.scaleToFit(thumbSize, thumbSize);

        x = spacing + (currentCol * (thumbSize + spacing));
        y = spacing + (currentRow * (thumbSize + spacing));

        canvas.paste(img, x, y);

        currentCol++;
        if (currentCol >= cols) {
            currentCol = 0;
            currentRow++;
        }
    }

    canvas.write(outputPath);
    return outputPath;
}

// Create 3x3 collage
images = [
    "photo1.jpg", "photo2.jpg", "photo3.jpg",
    "photo4.jpg", "photo5.jpg", "photo6.jpg",
    "photo7.jpg", "photo8.jpg", "photo9.jpg"
];

createCollage(images, 3, 10, "collage.jpg");

Before/After Comparison

function createBeforeAfter(beforePath, afterPath, outputPath) {
    before = ImageNew(beforePath);
    after = ImageNew(afterPath);

    // Ensure same height
    height = min(before.getHeight(), after.getHeight());
    before.scaleToFit(9999, height);
    after.scaleToFit(9999, height);

    // Create combined canvas
    totalWidth = before.getWidth() + after.getWidth() + 4;
    canvas = ImageNew(totalWidth, height, "rgb", "white");

    // Paste images side-by-side
    canvas.paste(before, 0, 0);
    canvas.paste(after, before.getWidth() + 4, 0);

    // Add divider line
    canvas.setDrawingColor("black")
          .setDrawingStroke({ width: 4 });

    x = before.getWidth() + 2;
    canvas.drawLine(x, 0, x, height);

    // Add labels
    canvas.setDrawingColor("white")
          .setDrawingTransparency(30);

    canvas.drawText("BEFORE", 20, height - 30, {
        font: "Arial",
        size: 24,
        style: "bold"
    });

    canvas.drawText("AFTER", before.getWidth() + 24, height - 30, {
        font: "Arial",
        size: 24,
        style: "bold"
    });

    canvas.write(outputPath);
    return outputPath;
}

// Usage
createBeforeAfter("original.jpg", "edited.jpg", "comparison.jpg");

Picture Frame Effect

function addFrame(sourcePath, frameWidth, frameColor, outputPath) {
    img = ImageNew(sourcePath);

    // Create larger canvas for frame
    canvasWidth = img.getWidth() + (frameWidth * 2);
    canvasHeight = img.getHeight() + (frameWidth * 2);

    canvas = ImageNew(canvasWidth, canvasHeight, "rgb", frameColor);

    // Paste image centered
    canvas.paste(img, frameWidth, frameWidth);

    // Add inner shadow effect
    canvas.setDrawingColor("black")
          .setDrawingTransparency(50)
          .setDrawingStroke({ width: 2 });

    x = frameWidth;
    y = frameWidth;
    w = img.getWidth();
    h = img.getHeight();

    canvas.drawRect(x, y, w, h);

    canvas.write(outputPath);
    return outputPath;
}

// Add 20px black frame
addFrame("photo.jpg", 20, "black", "framed.jpg");

Dynamic Graphics

Certificate Generator

function generateCertificate(name, course, date, outputPath) {
    // Create canvas
    img = ImageNew(1200, 800, "rgb", "white");

    // Add decorative border
    img.addBorder(20, "gold", "constant");

    // Draw ornamental corners
    img.setDrawingColor("#FFD700")  // Gold
       .setDrawingStroke({ width: 5 });

    // Top-left corner
    img.drawLine(40, 40, 200, 40)
       .drawLine(40, 40, 40, 200);

    // Top-right corner
    img.drawLine(1000, 40, 1160, 40)
       .drawLine(1160, 40, 1160, 200);

    // Bottom-left corner
    img.drawLine(40, 760, 200, 760)
       .drawLine(40, 600, 40, 760);

    // Bottom-right corner
    img.drawLine(1000, 760, 1160, 760)
       .drawLine(1160, 600, 1160, 760);

    // Add text
    img.setDrawingColor("black")
       .setAntialiasing(true);

    // Title
    img.drawText("Certificate of Completion", 300, 150, {
        font: "Serif",
        size: 48,
        style: "bold"
    });

    // Presented to
    img.drawText("This certificate is presented to", 350, 250, {
        font: "Serif",
        size: 24
    });

    // Name (larger)
    img.setDrawingColor("#0066CC");
    img.drawText(name, 400, 350, {
        font: "Serif",
        size: 56,
        style: "bold"
    });

    // Course
    img.setDrawingColor("black");
    img.drawText("For successfully completing", 370, 450, {
        font: "Serif",
        size: 24
    });

    img.drawText(course, 400, 520, {
        font: "Serif",
        size: 32,
        style: "italic"
    });

    // Date
    img.drawText("Date: #date#", 500, 650, {
        font: "Serif",
        size: 20
    });

    img.write(outputPath);
    return outputPath;
}

// Generate certificate
generateCertificate(
    "John Doe",
    "Advanced BoxLang Development",
    "December 20, 2024",
    "certificate.png"
);

Social Media Graphics

function createSocialPost(title, subtitle, backgroundPath, outputPath) {
    // Load background
    img = ImageNew(backgroundPath);

    // Resize to social media dimensions (1200x630 for sharing)
    img.resize(1200, 630);

    // Add semi-transparent overlay
    overlay = ImageNew(1200, 630, "argb", "transparent");
    overlay.setDrawingColor("black")
           .setDrawingTransparency(40);
    overlay.drawRect(0, 0, 1200, 630, true);

    img.paste(overlay, 0, 0);

    // Add text
    img.setDrawingColor("white")
       .setAntialiasing(true);

    // Title
    img.drawText(title, 100, 250, {
        font: "Arial",
        size: 72,
        style: "bold"
    });

    // Subtitle
    img.drawText(subtitle, 100, 350, {
        font: "Arial",
        size: 36
    });

    img.write(outputPath);
    return outputPath;
}

// Create post
createSocialPost(
    "New Feature Release",
    "BoxLang Image Module 1.0",
    "background.jpg",
    "social-post.jpg"
);

Chart Overlay

function addChartAnnotations(chartPath, annotations, outputPath) {
    img = ImageNew(chartPath);

    img.setAntialiasing(true)
       .setDrawingStroke({ width: 2 });

    for (annotation in annotations) {
        // Draw arrow
        img.setDrawingColor(annotation.color);
        img.drawLine(
            annotation.fromX,
            annotation.fromY,
            annotation.toX,
            annotation.toY
        );

        // Draw arrowhead
        angle = atan2(
            annotation.toY - annotation.fromY,
            annotation.toX - annotation.fromX
        );

        arrowSize = 10;
        x1 = annotation.toX - arrowSize * cos(angle - 0.5);
        y1 = annotation.toY - arrowSize * sin(angle - 0.5);
        x2 = annotation.toX - arrowSize * cos(angle + 0.5);
        y2 = annotation.toY - arrowSize * sin(angle + 0.5);

        img.drawLine(annotation.toX, annotation.toY, x1, y1)
           .drawLine(annotation.toX, annotation.toY, x2, y2);

        // Add label
        img.drawText(annotation.label, annotation.labelX, annotation.labelY, {
            font: "Arial",
            size: 14,
            style: "bold"
        });
    }

    img.write(outputPath);
    return outputPath;
}

// Usage
annotations = [
    {
        color: "red",
        fromX: 100,
        fromY: 50,
        toX: 200,
        toY: 150,
        label: "Peak",
        labelX: 50,
        labelY: 40
    }
];

addChartAnnotations("chart.png", annotations, "annotated-chart.png");

Photo Processing Pipelines

Instagram-Style Filter

function applyVintageFilter(sourcePath, outputPath) {
    img = ImageNew(sourcePath);

    // Create sepia-toned version
    img.grayScale();

    // Add warmth by overlaying amber color
    overlay = ImageNew(img.getWidth(), img.getHeight(), "argb", "transparent");
    overlay.setDrawingColor("#FFA500")  // Orange/amber
           .setDrawingTransparency(60);
    overlay.drawRect(0, 0, img.getWidth(), img.getHeight(), true);

    img.paste(overlay, 0, 0, 30);

    // Add vignette effect
    vignette = ImageNew(img.getWidth(), img.getHeight(), "argb", "transparent");
    vignette.setDrawingColor("black");

    // Darken edges
    borderSize = img.getWidth() * 0.2;
    for (i = 0; i < borderSize; i++) {
        transparency = 80 - (i / borderSize * 80);
        vignette.setDrawingTransparency(transparency);
        vignette.drawRect(i, i,
            img.getWidth() - (i * 2),
            img.getHeight() - (i * 2),
            false
        );
    }

    img.paste(vignette, 0, 0);

    // Slight blur for dreamy effect
    img.blur(1);

    img.write(outputPath);
    return outputPath;
}

// Apply vintage filter
applyVintageFilter("modern-photo.jpg", "vintage-photo.jpg");

HDR Effect

function applyHDREffect(sourcePath, outputPath) {
    img = ImageNew(sourcePath);
    original = img.copy();

    // Sharpen for detail enhancement
    img.sharpen(1.5);

    // Blend with original at 50%
    img.paste(original, 0, 0, 50);

    // Enhance again
    img.sharpen(0.8);

    img.write(outputPath);
    return outputPath;
}

Photo Restoration Pipeline

function restorePhoto(sourcePath, outputPath) {
    img = ImageNew(sourcePath);

    // 1. Resize if too large (for performance)
    maxDimension = 2000;
    if (img.getWidth() > maxDimension || img.getHeight() > maxDimension) {
        img.scaleToFit(maxDimension, maxDimension);
    }

    // 2. Sharpen slightly to restore detail
    img.sharpen(0.5);

    // 3. Light blur to reduce noise/scratches
    img.blur(0.5);

    // 4. Sharpen again
    img.sharpen(0.3);

    img.write(outputPath);
    return outputPath;
}

Batch Processing

Batch Resize

function batchResize(sourceDir, targetDir, maxWidth, maxHeight) {
    files = directoryList(sourceDir, false, "path");
    results = { processed: 0, skipped: 0, errors: [] };

    for (file in files) {
        if (!IsImageFile(file)) {
            results.skipped++;
            continue;
        }

        try {
            img = ImageNew(file);
            img.scaleToFit(maxWidth, maxHeight, "highQuality");

            filename = getFileFromPath(file);
            outputPath = "#targetDir#/#filename#";

            img.write(outputPath);
            results.processed++;

        } catch (any e) {
            arrayAppend(results.errors, {
                file: file,
                error: e.message
            });
        }
    }

    return results;
}

// Resize all images to max 800x600
stats = batchResize("uploads/", "resized/", 800, 600);
writeDump(stats);

Batch Watermark

function batchWatermark(sourceDir, targetDir, logoPath, position) {
    logo = ImageNew(logoPath);
    files = directoryList(sourceDir, false, "path");
    processed = 0;

    for (file in files) {
        if (!IsImageFile(file)) continue;

        img = ImageNew(file);

        // Resize logo to 10% of image width
        targetWidth = img.getWidth() * 0.1;
        logoResized = logo.copy();
        logoResized.scaleToFit(targetWidth, targetWidth);

        // Calculate position
        margin = 20;
        x = img.getWidth() - logoResized.getWidth() - margin;
        y = img.getHeight() - logoResized.getHeight() - margin;

        // Apply watermark
        img.paste(logoResized, x, y, 50);

        // Save
        filename = getFileFromPath(file);
        img.write("#targetDir#/#filename#");

        processed++;
    }

    return processed;
}

// Watermark all images
count = batchWatermark("photos/", "watermarked/", "logo.png", "bottomRight");
writeln("Processed #count# images");

Image Optimization

Smart Compression

function optimizeForWeb(sourcePath, outputPath, quality) {
    img = ImageNew(sourcePath);

    // Limit dimensions
    maxDimension = 1920;
    if (img.getWidth() > maxDimension || img.getHeight() > maxDimension) {
        img.scaleToFit(maxDimension, maxDimension, "highQuality");
    }

    // Convert to RGB if needed (remove alpha channel)
    if (img.getInfo().colorModel.hasAlpha) {
        rgb = ImageNew(img.getWidth(), img.getHeight(), "rgb", "white");
        rgb.paste(img, 0, 0);
        img = rgb;
    }

    // Write as JPEG with specified quality
    img.write(outputPath, quality);

    // Return file sizes for comparison
    return {
        original: getFileInfo(sourcePath).size,
        optimized: getFileInfo(outputPath).size,
        savings: getFileInfo(sourcePath).size - getFileInfo(outputPath).size
    };
}

// Optimize with 85% quality
stats = optimizeForWeb("photo.png", "photo-optimized.jpg", 0.85);
writeln("Saved #stats.savings# bytes");

Progressive Optimization

function createResponsiveSet(sourcePath, outputDir) {
    img = ImageNew(sourcePath);
    sizes = [
        { name: "thumbnail", width: 150 },
        { name: "small", width: 480 },
        { name: "medium", width: 800 },
        { name: "large", width: 1200 },
        { name: "xlarge", width: 1920 }
    ];

    results = {};
    filename = listFirst(getFileFromPath(sourcePath), ".");

    for (size in sizes) {
        resized = img.copy();
        resized.scaleToFit(size.width, 9999, "highQuality");

        outputPath = "#outputDir#/#filename#-#size.name#.jpg";
        resized.write(outputPath, 0.85);

        results[size.name] = {
            path: outputPath,
            width: resized.getWidth(),
            height: resized.getHeight(),
            size: getFileInfo(outputPath).size
        };
    }

    return results;
}

// Create responsive image set
set = createResponsiveSet("photo.jpg", "responsive/");
writeDump(set);

Next Steps

Last updated

Was this helpful?