BoxLang 🚀 A New JVM Dynamic Language Learn More...
|:------------------------------------------------------: |
| ⚡︎ B o x L a n g ⚡︎
| Dynamic : Modular : Productive
|:------------------------------------------------------: |
Copyright Since 2023 by Ortus Solutions, Corp
www.boxlang.io | www.ortussolutions.com
The BoxLang Image module provides comprehensive image manipulation functionality with a fluent, chainable API. Read, create, transform, filter, and save images with ease. This module brings CFML-compatible image functions to BoxLang while adding modern enhancements and conveniences.
Key Features:
BoxLang Image brings a fluent, modern API to image manipulation. Unlike traditional tag-based or function-based approaches, BoxLang Image emphasizes method chaining for readable, maintainable code:
// ✨ The Fluent Way (Recommended)
imageRead("photo.jpg")
.scaleToFit(800, 600)
.blur(2)
.sharpen(1)
.grayScale()
.write(); // Saves back to original file
// 📦 Traditional BIF Approach
img = imageRead("photo.jpg");
imageResize(img, 800, 600);
imageBlur(img, 2);
imageSharpen(img, 1);
imageGrayScale(img);
imageWrite(img, "photo.jpg");
// 🏷️ Component Approach
<bx:image action="read" source="photo.jpg" name="img" />
<bx:image action="resize" source="#img#" width="800" height="600" />
<bx:image action="write" source="#img#" destination="photo.jpg" />
The fluent API provides:
Install via CommandBox:
# Install the module
install bx-image
# Or add to box.json
box install bx-image --save
// Read and manipulate an image
img = imageRead("photo.jpg");
img.scaleToFit(800, 600)
.blur(2)
.sharpen(1)
.write("photo-optimized.jpg");
// Create a new image with drawing
canvas = imageNew("", 400, 300, "rgb", "white");
canvas.setDrawingColor("blue")
.drawRect(50, 50, 300, 200, true)
.setDrawingColor("red")
.drawText("Hello BoxLang!", 150, 150)
.write("greeting.png");
// Chain operations
imageRead("logo.png")
.crop(10, 10, 200, 200)
.grayScale()
.rotate(45)
.write("logo-transformed.png");
The BoxImage class provides a fluent interface where
most methods return this for chaining:
img = imageRead("path/to/file.jpg") // Load from file
img = imageRead("https://example.com/img") // Load from URL
img = imageReadBase64(base64String) // Load from Base64
img = imageNew("", 800, 600, "rgb", "white") // Create blank canvas
img.write("output.png") // Write to specified file
img.write() // Write back to original source file
base64 = imageWriteBase64(img) // Export as Base64
blob = imageGetBlob(img) // Export as binary
Note: The parameterless write() method
saves the image back to its original source path. This is useful when
you want to modify an image in place. For images created from scratch
(not loaded from a file), you must provide a path.
img.resize(width, height) // Exact dimensions
img.resize(width, height, interpolation) // With interpolation method
img.scaleToFit(size) // Fit to width, maintain aspect ratio
img.scaleToFit(width, height) // Fit within rectangular bounds
img.scaleToFit(width, height, interpolation) // With custom interpolation
img.crop(x, y, width, height) // Extract region
img.rotate(angle) // Rotate degrees
img.flip("horizontal") // Flip horizontal
img.flip("vertical") // Flip vertical
img.flip("diagonal") // Flip along main diagonal (transpose)
img.flip("antidiagonal") // Flip along anti-diagonal
img.flip("90") // Rotate 90° clockwise
img.flip("180") // Rotate 180°
img.flip("270") // Rotate 270° clockwise (90° CCW)
img.shear(shearX, shearY) // Shear transform
img.rotateDrawingAxis(angle) // Rotate drawing axis
img.translateDrawingAxis(x, y) // Translate drawing axis
img.shearDrawingAxis(shearX, shearY) // Shear drawing axis
img.blur(radius) // Apply Gaussian blur
img.sharpen(gain) // Sharpen image
img.grayScale() // Convert to grayscale
img.negative() // Invert colors
img.addBorder(thickness, color) // Add colored border
img.setDrawingColor("red") // Set foreground color
img.setDrawingColor("#FF0000") // Use hex colors
img.setBackgroundColor("white") // Set background
img.setAntiAliasing(true) // Enable anti-aliasing
img.setDrawingTransparency(50) // Set transparency (0-100)
img.setDrawingStroke({ // Set stroke properties
width: 2.0, // Stroke width in pixels
endCaps: "round", // "butt", "round", or "square"
lineJoins: "miter", // "miter", "round", or "bevel"
miterLimit: 10.0, // Miter limit for mitered joins
dashArray: [10, 5], // Dash pattern (on, off, on, off...)
dashPhase: 0 // Offset to start dash pattern
})
img.drawRect(x, y, width, height, filled) // Rectangle
img.drawRoundRect(x, y, w, h, aw, ah, fill) // Rounded rectangle
img.drawBeveledRect(x, y, w, h, raised, fill)// Beveled rectangle
img.drawOval(x, y, width, height, filled) // Oval/circle
img.drawArc(x, y, w, h, start, arc, filled) // Arc segment
img.drawLine(x1, y1, x2, y2) // Straight line
img.drawLines(pointArray, isPolygon, filled) // Multiple lines/polygon
img.drawPoint(x, y) // Single pixel
img.drawCubicCurve(x1, y1, cx1, cy1, ...) // Bezier curve
img.drawQuadraticCurve(x1, y1, cx, cy, ...) // Quadratic curve
img.clearRect(x, y, width, height) // Clear region
img.drawText(text, x, y) // Draw text at position
img.drawText(text, x, y, attributes) // With font attributes
// attributes: { font, size, style, alpha, underline, strikethrough }
img.overlay(topImage) // Overlay another image
img.paste(source, x, y) // Paste at position
img.copy(x, y, width, height) // Copy region to new image
width = img.getWidth() // Get width in pixels
height = img.getHeight() // Get height in pixels
info = imageInfo(img) // Full image info struct
exif = imageGetExifMetadata(img) // EXIF metadata
tag = imageGetExifTag(img, tagName) // Specific EXIF tag
iptc = imageGetIPTCMetadata(img) // IPTC metadata
tag = imageGetIPTCTag(img, tagName) // Specific IPTC tag
buffered = imageGetBufferedImage(img) // Java BufferedImage
// From file
img = imageRead("path/to/image.jpg");
// From URL
img = imageRead("https://example.com/image.png");
// From Base64
img = imageReadBase64(base64String);
// New blank canvas
img = imageNew("", 800, 600, "rgb", "white");
Most functions work both ways:
// As BIF (Built-In Function)
imageBlur(img, 5);
imageCrop(img, 10, 10, 200, 200);
// As member function (chainable!)
img.blur(5)
.crop(10, 10, 200, 200)
.write();
This module contributes the following BIFs:
ImageGreyScale()
for you britsimagePaste()
Most of these BIFs are also implemented as member functions on the
BoxImage type, so imageGrayScale( myImage )
can also be written as myImage.grayScale().
This module provides the
<bx:image>
component for tag-based image manipulation.
The <bx:image> component supports the following actions:
// Read an image
<bx:image action="read" source="photo.jpg" name="myImage" />
// Resize
<bx:image action="resize" source="#myImage#" width="800" height="600" />
// Rotate
<bx:image action="rotate" source="#myImage#" angle="45" destination="rotated.jpg" />
// Add border
<bx:image action="border" source="#myImage#" color="black" thickness="5" />
// Write to file
<bx:image action="write" source="#myImage#" destination="output.jpg" />
// Get image info
<bx:image action="info" source="#myImage#" structName="imageInfo" />
// Write to browser
<bx:image action="writeToBrowser" source="#myImage#" />
Supported Actions:
read - Load an image from file or URLwrite - Save image to filewriteToBrowser - Stream image to HTTP responseresize - Change image dimensionsrotate - Rotate image by angleborder - Add border around imageinfo - Get image metadataconvert - Convert image formatCommon Attributes:
source - Path to image file, URL, or BoxImage variablename - Variable name to store the imagedestination - Output file path for write operationswidth, height - Dimensions for resizeangle - Rotation angle in degreescolor - Color name or hex codethickness - Border thickness in pixelsoverwrite - Boolean, allow overwriting existing files
(default: false)isBase64 - Boolean, indicates if source is Base64-encoded💡 Tip: For complex image manipulation workflows, consider using the fluent API instead of components for better readability and maintainability.
The module properly manages file handles when reading images. After
loading an image with imageRead() or
imageNew(), the underlying file stream is automatically
closed, allowing you to safely delete or move the source file:
// This works correctly - file can be deleted after reading
img = imageRead("photo.jpg");
img.resize(800, 600).write("photo-resized.jpg");
fileDelete("photo.jpg"); // ✅ Works - no file lock
This is especially important on Windows, where file locks can prevent file operations.
When writing images, parent directories are automatically created if they don't exist:
// Creates 'output/thumbs/' directory if needed
img.write("output/thumbs/photo.jpg");
Blur, crop, and grayscale a png image before saving it back to disk:
var updatedLogo = ImageRead( "src/test/resources/logo.png" )
.blur( 5 )
.crop( x = 50, y = 50, width = 150, height = 100 )
.grayScale();
imageWrite( updatedLogo, "src/test/resources/logoNew.png" );
BoxLang is a professional open-source project and it is completely funded by the community and Ortus Solutions, Corp. Ortus Patreons get many benefits like a cfcasts account, a FORGEBOX Pro account and so much more. If you are interested in becoming a sponsor, please visit our patronage page: https://patreon.com/ortussolutions
"I am the way, and the truth, and the life; no one comes to the Father, but by me (JESUS)" Jn 14:1-12
All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
$
box install bx-image