ImageLib — Image Control Library
Display bitmap images in Plan9Basic applications with full control over scaling, positioning, and interactivity. Load images from local files or directly from the web via HTTP/HTTPS. Supports PNG (with transparency), JPEG, BMP, and GIF formats. Features include six wrap/scaling modes, rotation, opacity, mouse wheel zoom, and a complete mouse event system. 78 functions.
| Category | Count | Description |
|---|---|---|
| Error Handling | 4 | image_error, errormsg$, strerror$, clearerror |
| Creation & Destruction | 4 | image# (3 overloads), image_free |
| Loading & Saving | 4 | image_load (2 variants), image_save (2 variants) |
| Bitmap Properties | 5 | bitmapwidth, bitmapheight, isempty, clear# (2 overloads) |
| Wrap Mode | 2 | wrapmode (get/set) |
| Position & Size | 14 | x, y, width, height (get/set), bounds#, size#, move# |
| Alignment & Margins | 12 | align (get/set), margin#, margins#, marginleft/top/right/bottom (get/set) |
| Visibility & State | 8 | visible, enabled, opacity, hittest (get/set) |
| Tag & Rotation | 4 | tag (get/set), rotation (get/set) |
| Parent & Z-Order | 4 | parent# (get/set), bringtofront#, sendtoback#, invalidate# |
| Events | 17 | 8 event types × set/get + clearcallbacks# |
Cross-Platform Support
| Platform | Status | Notes |
|---|---|---|
| Windows | ✅ Full Support | Win32/Win64 |
| Linux | ✅ Full Support | GTK-based |
| Android | ✅ Full Support | Mobile-optimized |
Supported Image Formats
| Format | Extension | Notes |
|---|---|---|
| PNG | .png | Recommended for transparency support |
| JPEG | .jpg / .jpeg | Best for photographs |
| BMP | .bmp | Uncompressed bitmap |
| GIF | .gif | Simple animations not supported (shows first frame) |
Error Handling
| Function | Signature | Description |
|---|---|---|
image_error() | image_error@ | Last error code (0 = no error) |
image_errormsg$() | image_errormsg$@ | Last error message as string |
image_strerror$(code) | image_strerror$@n | Description for a given error code |
image_clearerror() | image_clearerror@ | Clear the error state |
Numeric Values Reference
Wrap Mode image_wrapmode#
| Value | Mode | Description |
|---|---|---|
| 0 | Original | Display at original size, top-left aligned |
| 1 | Fit | Scale to fit while keeping aspect ratio (default) |
| 2 | Stretch | Stretch to fill control (may distort) |
| 3 | Tile | Repeat image to fill control |
| 4 | Center | Center without resizing |
| 5 | Place | Fit if larger, center if smaller |
Control Alignment image_align#
| Value | Description |
|---|---|
| 0 | None (absolute positioning) |
| 1 | Top |
| 2 | Left |
| 3 | Right |
| 4 | Bottom |
| 9 | Client (fill parent) |
| 11 | Center |
Creation & Destruction
| Function | Signature | Description |
|---|---|---|
image#(parent#) | image#@# | Create image control with default size |
image#(parent#, w, h) | image#@#nn | Create with size (positioned at 0, 0) |
image#(parent#, x, y, w, h) | image#@#nnnn | Create with position and size |
image_free(img#) | image_free@# | Destroy image control and release resources |
let img# = image#(frm#, 50, 50, 400, 300) ' Or just specify size let img# = image#(frm#, 400, 300) ' Cleanup image_free(img#)
Loading & Saving
| Function | Signature | Description |
|---|---|---|
image_load(img#, path$) | image_load@#$ | Load from file or URL; returns 1 on success, 0 on failure |
image_load#(img#, path$) | image_load#@#$ | Load from file or URL; returns image pointer |
image_save(img#, filepath$) | image_save@#$ | Save to file; returns 1 on success, 0 on failure |
image_save#(img#, filepath$) | image_save#@#$ | Save to file; returns image pointer |
' Load from local file image_load#(img#, "photo.png") ' Load from web URL image_load#(img#, "https://picsum.photos/400/300") ' Check if load succeeded if image_load(img#, "photo.png") = 1 then println "Loaded OK" else println "Load failed: " + image_errormsg$() endif ' Save to file image_save#(img#, "output.png")
ⓘ Note: Image loading supports both local file paths and full HTTP/HTTPS URLs. Web images are downloaded automatically. Use
image_load (returns 1/0) when you need to check success, or image_load# (returns pointer) for chaining.Bitmap Properties
| Function | Signature | Description |
|---|---|---|
image_bitmapwidth(img#) | image_bitmapwidth@# | Get the actual loaded image width in pixels |
image_bitmapheight(img#) | image_bitmapheight@# | Get the actual loaded image height in pixels |
image_isempty(img#) | image_isempty@# | Returns 1 if no image is loaded, 0 if loaded |
image_clear#(img#) | image_clear#@# | Clear the image (transparent) |
image_clear#(img#, color$) | image_clear#@#$ | Clear with a fill color |
' Check before accessing if image_isempty(img#) = 0 then println "Image: " + str$(image_bitmapwidth(img#)) + "x" + str$(image_bitmapheight(img#)) endif ' Clear to transparent image_clear#(img#) ' Clear to a color image_clear#(img#, "#336699")
⚠ Warning:
image_bitmapwidth / image_bitmapheight return the actual pixel size of the loaded image, which is different from image_width / image_height which return the control size on the form.Wrap Mode
| Function | Signature | Description |
|---|---|---|
image_wrapmode(img#) | image_wrapmode@# | Get current wrap mode (0–5) |
image_wrapmode#(img#, mode) | image_wrapmode#@#n | Set wrap mode |
' Fit preserves aspect ratio (best for photos) image_wrapmode#(img#, 1) ' Stretch fills the control (may distort) image_wrapmode#(img#, 2) ' Tile repeats the image (patterns) image_wrapmode#(img#, 3) ' Place: fit-if-larger, center-if-smaller image_wrapmode#(img#, 5)
ⓘ Note: Use Fit (1) for photos, Stretch (2) for backgrounds, Tile (3) for patterns, and Place (5) when you want small images centered but large ones scaled down.
Position & Size
| Function | Signature | Description |
|---|---|---|
image_x(img#) | image_x@# | Get X position |
image_x#(img#, x) | image_x#@#n | Set X position |
image_y(img#) | image_y@# | Get Y position |
image_y#(img#, y) | image_y#@#n | Set Y position |
image_width(img#) | image_width@# | Get control width |
image_width#(img#, w) | image_width#@#n | Set control width |
image_height(img#) | image_height@# | Get control height |
image_height#(img#, h) | image_height#@#n | Set control height |
image_bounds#(img#, x, y, w, h) | image_bounds#@#nnnn | Set position and size in one call |
image_size#(img#, w, h) | image_size#@#nn | Set size only |
image_move#(img#, x, y) | image_move#@#nn | Set position only |
Alignment & Margins
| Function | Signature | Description |
|---|---|---|
image_align(img#) | image_align@# | Get control alignment mode |
image_align#(img#, n) | image_align#@#n | Set alignment (0=none, 1=top, 2=left, 3=right, 4=bottom, 9=client, 11=center) |
image_margin#(img#, n) | image_margin#@#n | Set uniform margin on all four sides |
image_margins#(img#, l, t, r, b) | image_margins#@#nnnn | Set individual margins (left, top, right, bottom) |
image_marginleft(img#) | image_marginleft@# | Get left margin |
image_marginleft#(img#, n) | image_marginleft#@#n | Set left margin |
image_margintop(img#) | image_margintop@# | Get top margin |
image_margintop#(img#, n) | image_margintop#@#n | Set top margin |
image_marginright(img#) | image_marginright@# | Get right margin |
image_marginright#(img#, n) | image_marginright#@#n | Set right margin |
image_marginbottom(img#) | image_marginbottom@# | Get bottom margin |
image_marginbottom#(img#, n) | image_marginbottom#@#n | Set bottom margin |
' Full-screen background image image_align#(img#, 9) ' Client = fill image_margin#(img#, 0)
Visibility & State
| Function | Signature | Description |
|---|---|---|
image_visible(img#) | image_visible@# | Get visibility (0/1) |
image_visible#(img#, n) | image_visible#@#n | Set visibility |
image_enabled(img#) | image_enabled@# | Get enabled state (0/1) |
image_enabled#(img#, n) | image_enabled#@#n | Set enabled state |
image_opacity(img#) | image_opacity@# | Get opacity (0.0–1.0) |
image_opacity#(img#, value) | image_opacity#@#n | Set opacity (0.0=transparent, 1.0=opaque) |
image_hittest(img#) | image_hittest@# | Get hit-test state (0/1) |
image_hittest#(img#, n) | image_hittest#@#n | Enable/disable mouse hit testing |
' Semi-transparent overlay image_opacity#(imgOverlay#, 0.5) ' Disable mouse interaction (click-through) image_hittest#(imgBackground#, 0)
ⓘ Note: Set
image_hittest#(img#, 0) to make an image “click-through” — mouse events will pass through to controls behind it. Useful for decorative overlays.Tag & Rotation
| Function | Signature | Description |
|---|---|---|
image_tag(img#) | image_tag@# | Get user-defined integer tag |
image_tag#(img#, n) | image_tag#@#n | Set user-defined integer tag |
image_rotation(img#) | image_rotation@# | Get rotation angle in degrees |
image_rotation#(img#, angle) | image_rotation#@#n | Set rotation angle (0–360 degrees) |
' Rotate 45 degrees image_rotation#(img#, 45) ' Use tags to identify thumbnails image_tag#(img1#, 1) image_tag#(img2#, 2) image_tag#(img3#, 3)
Parent & Z-Order
| Function | Signature | Description |
|---|---|---|
image_parent#(img#) | image_parent#@# | Get parent control pointer |
image_parent#(img#, parent#) | image_parent#@## | Move image to a different parent |
image_bringtofront#(img#) | image_bringtofront#@# | Bring to front of Z-order |
image_sendtoback#(img#) | image_sendtoback#@# | Send to back of Z-order |
image_invalidate#(img#) | image_invalidate#@# | Force the image to redraw |
' Layer images: background behind foreground image_sendtoback#(imgBackground#) image_bringtofront#(imgForeground#) ' Force redraw after external changes image_invalidate#(img#)
Events
Each event has a setter (image_onXXX#(img#, func$)) and a getter (image_onXXX$(img#)). Use image_clearcallbacks#(img#) to disconnect all callbacks at once.
Click Events
| Event Setter | Getter | Callback Signature |
|---|---|---|
image_onclick#(img#, func$) | image_onclick$(img#) | function name(sender#) |
image_ondblclick#(img#, func$) | image_ondblclick$(img#) | function name(sender#) |
Mouse Events
| Event Setter | Getter | Callback Signature |
|---|---|---|
image_onmousedown#(img#, func$) | image_onmousedown$(img#) | function name(sender#, button, x, y, shift$) |
image_onmouseup#(img#, func$) | image_onmouseup$(img#) | function name(sender#, button, x, y, shift$) |
image_onmousemove#(img#, func$) | image_onmousemove$(img#) | function name(sender#, x, y, shift$) |
image_onmouseenter#(img#, func$) | image_onmouseenter$(img#) | function name(sender#) |
image_onmouseleave#(img#, func$) | image_onmouseleave$(img#) | function name(sender#) |
image_onmousewheel#(img#, func$) | image_onmousewheel$(img#) | function name(sender#, delta, shift$) |
ⓘ Note: OnMouseWheel provides a
delta value: positive for scroll up, negative for scroll down. Perfect for implementing zoom functionality.Other Events
| Event Setter | Getter | Callback Signature |
|---|---|---|
image_onresize#(img#, func$) | image_onresize$(img#) | function name(sender#) |
image_clearcallbacks#(img#) | — | Disconnect all event callbacks |
Free Web Image Sources
Lorem Picsum (https://picsum.photos) provides free stock photos for testing:
| URL Pattern | Description |
|---|---|
https://picsum.photos/400/300 | Random image 400×300 |
https://picsum.photos/id/10/400/300 | Specific image by ID |
https://picsum.photos/seed/hello/400/300 | Consistent image from seed text |
https://picsum.photos/400/300?grayscale | Grayscale image |
https://picsum.photos/400/300?blur=5 | Blurred image (1–10) |
' Random image each time image_load#(img#, "https://picsum.photos/400/300") ' Same image every time (use seed) image_load#(img#, "https://picsum.photos/seed/myapp/400/300") ' Specific image by ID image_load#(img#, "https://picsum.photos/id/42/400/300")
ⓘ Note: Use the
seed parameter to get the same image consistently across runs. Without it, each request returns a random image.Complete Examples
Web Image Gallery
function OnThumbClick(sender#) local tag, url$ tag = image_tag(sender#) if tag = 1 then url$ = "https://picsum.photos/seed/nature/660/290" elseif tag = 2 then url$ = "https://picsum.photos/seed/city/660/290" elseif tag = 3 then url$ = "https://picsum.photos/seed/ocean/660/290" endif image_load#(imgMain#, url$) endfunction let frm# = form#("Gallery", 700, 450) form_position#(frm#, 4) ' Thumbnails let img1# = image#(frm#, 20, 20, 150, 100) let img2# = image#(frm#, 190, 20, 150, 100) let img3# = image#(frm#, 360, 20, 150, 100) image_wrapmode#(img1#, 1) image_wrapmode#(img2#, 1) image_wrapmode#(img3#, 1) image_load#(img1#, "https://picsum.photos/seed/nature/150/100") image_load#(img2#, "https://picsum.photos/seed/city/150/100") image_load#(img3#, "https://picsum.photos/seed/ocean/150/100") ' Main display let imgMain# = image#(frm#, 20, 140, 660, 290) image_wrapmode#(imgMain#, 1) image_tag#(img1#, 1) image_tag#(img2#, 2) image_tag#(img3#, 3) image_onclick#(img1#, "OnThumbClick") image_onclick#(img2#, "OnThumbClick") image_onclick#(img3#, "OnThumbClick") form_show(frm#) while form_visible(frm#) = 1 processmessages() end while
Wrap Mode Selector
function SetOriginal(sender#) image_wrapmode#(img#, 0) label_text#(lblMode#, "Mode: Original") endfunction function SetFit(sender#) image_wrapmode#(img#, 1) label_text#(lblMode#, "Mode: Fit") endfunction function SetStretch(sender#) image_wrapmode#(img#, 2) label_text#(lblMode#, "Mode: Stretch") endfunction function SetTile(sender#) image_wrapmode#(img#, 3) label_text#(lblMode#, "Mode: Tile") endfunction function SetCenter(sender#) image_wrapmode#(img#, 4) label_text#(lblMode#, "Mode: Center") endfunction let frm# = form#("Wrap Modes", 600, 500) form_position#(frm#, 4) let img# = image#(frm#, 10, 50, 580, 400) image_load#(img#, "https://picsum.photos/seed/demo/400/300") image_wrapmode#(img#, 1) let lblMode# = label#(frm#, "Mode: Fit", 10, 460) let btnOriginal# = button#(frm#, "Original", 10, 10, 80, 30) let btnFit# = button#(frm#, "Fit", 100, 10, 80, 30) let btnStretch# = button#(frm#, "Stretch", 190, 10, 80, 30) let btnTile# = button#(frm#, "Tile", 280, 10, 80, 30) let btnCenter# = button#(frm#, "Center", 370, 10, 80, 30) button_onclick#(btnOriginal#, "SetOriginal") button_onclick#(btnFit#, "SetFit") button_onclick#(btnStretch#, "SetStretch") button_onclick#(btnTile#, "SetTile") button_onclick#(btnCenter#, "SetCenter") form_show(frm#) while form_visible(frm#) = 1 processmessages() end while
Zoom with Mouse Wheel
let zoomLevel = 100 function OnZoom(sender#, delta, shift$) local w, h, origW, origH origW = image_bitmapwidth(sender#) origH = image_bitmapheight(sender#) if delta > 0 then zoomLevel = zoomLevel + 10 if zoomLevel > 400 then zoomLevel = 400 else zoomLevel = zoomLevel - 10 if zoomLevel < 10 then zoomLevel = 10 endif w = origW * zoomLevel / 100 h = origH * zoomLevel / 100 image_size#(sender#, w, h) label_text#(lblZoom#, "Zoom: " + str$(zoomLevel) + "%") endfunction let frm# = form#("Zoom", 800, 600) form_position#(frm#, 4) let img# = image#(frm#, 0, 40, 800, 560) image_wrapmode#(img#, 0) image_load#(img#, "https://picsum.photos/seed/zoom/600/400") let lblZoom# = label#(frm#, "Zoom: 100%", 10, 10) image_onmousewheel#(img#, "OnZoom") form_show(frm#) while form_visible(frm#) = 1 processmessages() end while
Image Rotation
function RotateLeft(sender#) local angle angle = image_rotation(img#) - 15 if angle < 0 then angle = angle + 360 image_rotation#(img#, angle) label_text#(lblAngle#, "Angle: " + str$(angle)) endfunction function RotateRight(sender#) local angle angle = image_rotation(img#) + 15 if angle >= 360 then angle = angle - 360 image_rotation#(img#, angle) label_text#(lblAngle#, "Angle: " + str$(angle)) endfunction let frm# = form#("Rotate", 500, 500) form_position#(frm#, 4) let img# = image#(frm#, 100, 50, 300, 300) image_load#(img#, "https://picsum.photos/seed/rotate/300/300") image_wrapmode#(img#, 1) let lblAngle# = label#(frm#, "Angle: 0", 200, 370) let btnLeft# = button#(frm#, "< Left", 100, 410, 120, 40) let btnRight# = button#(frm#, "Right >", 280, 410, 120, 40) button_onclick#(btnLeft#, "RotateLeft") button_onclick#(btnRight#, "RotateRight") form_show(frm#) while form_visible(frm#) = 1 processmessages() end while
Opacity Layering
let opacity = 1.0 function ToggleFade(sender#) local pct if opacity > 0.5 then opacity = 0.0 else opacity = 1.0 endif image_opacity#(imgFront#, opacity) pct = opacity * 100 label_text#(lblOpacity#, "Opacity: " + str$(pct) + "%") endfunction let frm# = form#("Opacity", 600, 500) form_position#(frm#, 4) let imgBack# = image#(frm#, 50, 50, 500, 350) image_load#(imgBack#, "https://picsum.photos/seed/back/500/350") image_wrapmode#(imgBack#, 2) let imgFront# = image#(frm#, 50, 50, 500, 350) image_load#(imgFront#, "https://picsum.photos/seed/front/500/350") image_wrapmode#(imgFront#, 2) let lblOpacity# = label#(frm#, "Opacity: 100%", 250, 420) let btnFade# = button#(frm#, "Toggle", 250, 450, 100, 35) button_onclick#(btnFade#, "ToggleFade") form_show(frm#) while form_visible(frm#) = 1 processmessages() end while
Best Practices
| Practice | Why |
|---|---|
| Use Fit mode (1) for photos | Preserves aspect ratio without distortion |
| Use Stretch mode (2) for backgrounds | Fills the entire control area |
| Use Tile mode (3) for patterns | Repeats the image seamlessly |
Check image_isempty(img#) after loading | Detects load failures before accessing bitmap properties |
| Use PNG for transparency | PNG images correctly display transparent areas |
| Distinguish control vs bitmap size | image_width = control size; image_bitmapwidth = actual image pixels |
Use seed for consistent web images | https://picsum.photos/seed/myapp/400/300 always returns the same image |
| Match requested size to display size | Request web images at the size you’ll display them to avoid unnecessary bandwidth |
Set image_hittest#(img#, 0) for decorations | Makes the image click-through so mouse events reach controls behind it |
Quick Reference
| Function | Signature | Description |
|---|---|---|
image_error / errormsg$ / strerror$ / clearerror | various | Error handling (4) |
image#(parent#[, w, h] | [, x, y, w, h]) | various | Create (3 overloads) |
image_free(img#) | image_free@# | Destroy |
image_load / image_load# / image_save / image_save# | various | Loading & saving (4) |
image_bitmapwidth / bitmapheight / isempty / clear# | various | Bitmap properties (5) |
image_wrapmode (get/set) | various | Wrap mode (2) |
image_x/y/width/height (get/set) / bounds# / size# / move# | various | Position & size (14) |
image_align / margin# / margins# / margin[left/top/right/bottom] | various | Alignment & margins (12) |
image_visible / enabled / opacity / hittest | various | Visibility & state (8) |
image_tag / rotation | various | Tag & rotation (4) |
image_parent# / bringtofront# / sendtoback# / invalidate# | various | Parent & Z-order (4) |
image_onclick/ondblclick/onmousedown/up/move/enter/leave/onmousewheel/onresize | various | Events set+get (17) |
image_clearcallbacks# | image_clearcallbacks#@# | Disconnect all events |
78 functions. Part of the Plan9Basic GUI library system.