Bitmap
From Rosetta Code
You are encouraged to solve this task according to the task description, using any language you may know.
Show a basic storage type to handle a simple RGB raster graphics image, and some primitive associated functions.
If possible provide a function to allocate an uninitialised image, given its width and height, and provide 3 additional functions:
- one to fill an image with a plain RGB color,
- one to set a given pixel with a color,
- one to get the color of a pixel.
(If there are specificities about the storage or the allocation, explain those.)
These functions are used as a base for the articles in the category raster graphics operations, and a basic output function to check the results is available in the article write ppm file.
[edit] Ada
The package interface:
package Bitmap_Store is
type Luminance is mod 2**8;
type Pixel is record
R, G, B : Luminance;
end record;
Black : constant Pixel := (others => 0);
White : constant Pixel := (others => 255);
type Image is array (Positive range <>, Positive range <>) of Pixel;
procedure Fill (Picture : in out Image; Color : Pixel);
procedure Print (Picture : Image);
type Point is record
X, Y : Positive;
end record;
end Bitmap_Store;
The implementation of:
with Ada.Text_IO; use Ada.Text_IO;
package body Bitmap_Store is
procedure Fill (Picture : in out Image; Color : Pixel) is
begin
for I in Picture'Range (1) loop
for J in Picture'Range (2) loop
Picture (I, J) := Color;
end loop;
end loop;
end Fill;
procedure Print (Picture : Image) is
begin
for I in Picture'Range (1) loop
for J in Picture'Range (2) loop
if Picture (I, J) = White then
Put (' ');
else
Put ('H');
end if;
end loop;
New_Line;
end loop;
end Print;
end Bitmap_Store;
This can be used like:
use Bitmap_Store; with Bitmap_Store;
...
X : Image (1..64, 1..64);
begin
Fill (X, (255, 255, 255));
X (1, 2) := (R => 255, others => 0);
X (3, 4) := X (1, 2);
[edit] ALGOL 68
Translation of: ada
Note: short and shorten need to be tuned (added or removed) the match the underlying graphic hardware colour depth.
Works with: ALGOL 68 version Standard - no extensions to language used Works with: ALGOL 68G version Any - tested with release mk15-0.8b.fc9.i386
MODE PIXEL = STRUCT(#SHORT# BITS red,green,blue);
MODE POINT = STRUCT(INT x,y);
MODE IMAGE = [0,0]PIXEL; # instance attributes #
MODE CLASSIMAGE = STRUCT ( # class attributes #
PIXEL black, red, green, blue, white,
PROC (REF IMAGE)REF IMAGE init,
PROC (REF IMAGE, PIXEL)VOID fill,
PROC (REF IMAGE)VOID print,
# virtual: #
REF PROC (REF IMAGE, POINT, POINT, PIXEL)VOID line,
REF PROC (REF IMAGE, POINT, INT, PIXEL)VOID circle,
REF PROC (REF IMAGE, POINT, POINT, POINT, POINT, PIXEL, UNION(INT, VOID))VOID cubic bezier
);
CLASSIMAGE class image = (
# black = # (#SHORTEN# 16r00, #SHORTEN# 16r00, #SHORTEN# 16r00),
# red = # (#SHORTEN# 16rff, #SHORTEN# 16r00, #SHORTEN# 16r00),
# green = # (#SHORTEN# 16r00, #SHORTEN# 16rff, #SHORTEN# 16r00),
# blue = # (#SHORTEN# 16r00, #SHORTEN# 16r00, #SHORTEN# 16rff),
# white = # (#SHORTEN# 16rff, #SHORTEN# 16rff, #SHORTEN# 16rff),
# PROC init = # (REF IMAGE self)REF IMAGE:
BEGIN
(fill OF class image)(self, black OF class image);
self
END,
# PROC fill = # (REF IMAGE self, PIXEL color)VOID:
FOR x FROM 1 LWB self TO 1 UPB self DO
FOR y FROM 2 LWB self TO 2 UPB self DO
self[x,y] := color
OD
OD,
# PROC print = # (REF IMAGE self)VOID:
printf(($n(UPB self)(3(16r2d))l$, self)),
# virtual: #
# REF PROC line = # LOC PROC (REF IMAGE, POINT, POINT, PIXEL)VOID,
# REF PROC circle = # LOC PROC (REF IMAGE, POINT, INT, PIXEL)VOID,
# REF PROC cubic bezier = # LOC PROC (REF IMAGE, POINT, POINT, POINT, POINT, PIXEL, UNION(INT, VOID))VOID
);
OP CLASSOF = (IMAGE image)CLASSIMAGE: class image;
OP INIT = (REF IMAGE image)REF IMAGE: (init OF (CLASSOF image))(image);
BOOL test = TRUE;
IF test THEN
###
The test program
###
REF IMAGE x := INIT LOC[1:16, 1:16]PIXEL;
(fill OF class image) (x, white OF class image);
(print OF class image) (x)
FI
Output (A 16x16 white block):
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
[edit] AutoHotkey
Works with: AutoHotkey_L
test:
blue := color(0,0,255) ; rgb
cyan := color(0,255,255)
blue_square := Bitmap(10, 10, blue)
cyanppm := Bitmap(10, 10, cyan)
x := blue_square[4,4] ; get pixel(4,4)
msgbox % "blue: 4,4,R,G,B, RGB: " x.R ", " x.G ", " x.B ", " x.rgb()
blue_square[4,4] := cyan ; set pixel(4,4)
x := blue_square[4,4] ; get pixel(4,4)
blue_square.write("blue.ppm")
return
Bitmap(width = 1, height = 1, background = 0)
{
global black
black := color(0,0,0)
if !background
background := black
static BitmapType
if !BitmapType
BitmapType
:= Object("fill", "Bitmap_Fill"
,"write", "Bitmap_write_ppm3")
img := Object("width", width
,"height", height
, "base" , BitmapType)
img._SetCapacity(height) ; an array of rows
img.fill(background)
Return img
}
Bitmap_Fill(bitmap, color)
{
r := color.r
g := color.g
b := color.b
loop % bitmap.height
{
height := A_Index
loop % bitmap.width
{
width := A_Index
bitmap[height, width] := color(r, g, b)
}
}
return bitmap
}
Bitmap_write_ppm3(bitmap, filename)
{
file := FileOpen(filename, 0x11) ; utf-8, write
file.seek(0,0)
file.write("P3`n"
. bitmap.width . " " . bitmap.height . "`n"
. "255`n")
loop % bitmap.height
{
height := A_Index
loop % bitmap.width
{
width := A_Index
color := bitmap[height, width]
file.Write(color.R . " ")
file.Write(color.G . " ")
file.Write(color.B . " ")
}
file.write("`n")
}
file.close()
return 0
}
Color(r, g, b)
{
static ColorType
if !ColorType
ColorType
:= Object("rgb" , "Color_rgb")
return Object("r" , r, "g", g, "b", b
, "base" , ColorType)
; return Object("r" , r, "g", g, "b", b, "rgb", "Color_rgb")
}
Color_rgb(clr)
{
return clr.R << 16 | clr.G << 8 | clr.B
}
[edit] C
Working excerpt from imglib.h usable as "interface" (some includes are needed for other functions of the same category).
#ifndef _IMGLIB_0
#define _IMGLIB_0
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <string.h>
#include <math.h>
#include <sys/queue.h>
typedef unsigned char color_component;
typedef color_component pixel[3];
typedef struct {
unsigned int width;
unsigned int height;
pixel * buf;
} image_t;
typedef image_t * image;
image alloc_img(unsigned int width, unsigned int height);
void free_img(image);
void fill_img(image img,
color_component r,
color_component g,
color_component b );
void put_pixel_unsafe(
image img,
unsigned int x,
unsigned int y,
color_component r,
color_component g,
color_component b );
void put_pixel_clip(
image img,
unsigned int x,
unsigned int y,
color_component r,
color_component g,
color_component b );
#define GET_PIXEL(IMG, X, Y) (IMG->buf[ ((Y) * IMG->width + (X)) ])
#endif
image alloc_img(unsigned int width, unsigned int height)
{
image img;
img = malloc(sizeof(image_t));
img->buf = malloc(width * height * sizeof(pixel));
img->width = width;
img->height = height;
return img;
}
void free_img(image img)
{
free(img->buf);
free(img);
}
void fill_img(
image img,
color_component r,
color_component g,
color_component b )
{
unsigned int i, n;
n = img->width * img->height;
for (i=0; i < n; ++i)
{
img->buf[i][0] = r;
img->buf[i][1] = g;
img->buf[i][2] = b;
}
}
void put_pixel_unsafe(
image img,
unsigned int x,
unsigned int y,
color_component r,
color_component g,
color_component b )
{
unsigned int ofs;
ofs = (y * img->width) + x;
img->buf[ofs][0] = r;
img->buf[ofs][1] = g;
img->buf[ofs][2] = b;
}
void put_pixel_clip(
image img,
unsigned int x,
unsigned int y,
color_component r,
color_component g,
color_component b )
{
if (x < img->width && y < img->height)
put_pixel_unsafe(img, x, y, r, g, b);
}
[edit] C++
[edit] C#
This implementation uses a multidemensional array to store the Color structure (which stores the RGB values). No exception catching for out-of-bounds errors if they occur, but provides Height and Width properties so a program using it can avoid them.
public class Bitmap
{
public struct Color
{
public byte Red { get; set; }
public byte Blue { get; set; }
public byte Green { get; set; }
}
Color[,] _imagemap;
public int Width { get { return _imagemap.GetLength(0); } }
public int Height { get { return _imagemap.GetLength(1); } }
public Bitmap(int width, int height)
{
_imagemap = new Color[width, height];
}
public void Fill(Color color)
{
for (int y = 0; y < Height; y++)
for (int x = 0; x < Width; x++)
{
_imagemap[x, y] = color;
}
}
public Color GetPixel(int x, int y)
{
return _imagemap[x, y];
}
public void SetPixel(int x, int y, Color color)
{
_imagemap[x, y] = color;
}
}
[edit] Common Lisp
(defpackage #:rgb-pixel-buffer
(:use #:common-lisp)
(:export #:rgb-pixel-component #:rgb-pixel #:rgb-pixel-buffer
#:+red+ #:+green+ #:+blue+ #:+black+ #:+white+
#:make-rgb-pixel #:make-rgb-pixel-buffer #:rgb-pixel-buffer-width
#:rgb-pixel-buffer-height #:rgb-pixel-red #:rgb-pixel-green
#:rgb-pixel-blue #:fill-rgb-pixel-buffer))
(in-package #:rgb-pixel-buffer)
(deftype rgb-pixel-component ()
'(unsigned-byte 8))
(deftype rgb-pixel ()
'(unsigned-byte 24))
(deftype rgb-pixel-buffer (&optional (width '*) (height '*))
`(array rgb-pixel (,width ,height)))
(defconstant +black+ 0)
(defconstant +white+ #xFFFFFF)
(defconstant +red+ #xFF0000)
(defconstant +green+ #x00FF00)
(defconstant +blue+ #x0000FF)
(defun make-rgb-pixel (r g b)
(declare (type rgb-pixel-component r g b))
(logior (ash r 16) (ash g 8) b))
(defun rgb-pixel-red (rgb)
(declare (type rgb-pixel rgb))
(logand (ash rgb -16) #xFF))
(defun rgb-pixel-green (rgb)
(declare (type rgb-pixel rgb))
(logand (ash rgb -8) #xFF))
(defun rgb-pixel-blue (rgb)
(declare (type rgb-pixel rgb))
(logand rgb #xFF))
(defun make-rgb-pixel-buffer (width height &optional (initial-element +black+))
(declare (type (integer 1) width height))
(declare (type rgb-pixel initial-element))
(make-array (list width height)
:element-type 'rgb-pixel
:initial-element initial-element))
(defun rgb-pixel-buffer-width (buffer)
(first (array-dimensions buffer)))
(defun rgb-pixel-buffer-height (buffer)
(second (array-dimensions buffer)))
(defun rgb-pixel (buffer x y)
(declare (type rgb-pixel-buffer buffer))
(declare (type (integer 0) x y))
(aref buffer x y))
(defun (setf rgb-pixel) (value buffer x y)
(declare (type rgb-pixel-buffer buffer))
(declare (type rgb-pixel value))
(declare (type (integer 0) x y))
(setf (aref buffer x y) value))
(defun fill-rgb-pixel-buffer (buffer pixel)
(declare (type rgb-pixel-buffer buffer))
(declare (type rgb-pixel pixel))
(let* ((dimensions (array-dimensions buffer))
(width (first dimensions))
(height (second dimensions)))
(loop
:for y :of-type fixnum :upfrom 0 :below height
:do (loop
:for x :of-type fixnum :upfrom 0 :below width
:do (setf (rgb-pixel buffer x y) pixel)))
buffer))
Example:
(defvar *buffer* (make-rgb-pixel-buffer 10 10))
(fill-rgb-pixel-buffer *buffer* +white+)
(setf (rgb-pixel *buffer* 0 0) +red+)
(setf (rgb-pixel *buffer* 0 9) +red+)
(setf (rgb-pixel *buffer* 9 0) +red+)
(setf (rgb-pixel *buffer* 9 9) +red+)
[edit] D
Definition of rgb-holder struct, and Bitmap template with basic operations.
struct Rgb {
ubyte[3] value;
// some convinient modifiers
void opCall(ubyte r, ubyte g, ubyte b) { value[] = [r, g, b]; }
void opCall(ubyte[3] v) { value[] = v[]; }
void opCall(ubyte v) { value[] = v; }
// simple accessors
ubyte r() { return value[0]; }
ubyte g() { return value[1]; }
ubyte b() { return value[2]; }
// simple luminosities for [[Greyscale image]] problem
ubyte lumCIE() { return cast(ubyte)(0.2126*r + 0.7152*g + 0.0722*b); }
ubyte lumAVG() { return cast(ubyte)(0.3333*r + 0.3333*g + 0.3333*b); }
}
struct Bitmap(T) {
alias Bitmap!(T) _MyT;
int width, height;
T[] data;
static _MyT opCall(int width, int height) {
_MyT res = void;
res.width = width; res.height = height;
res.data = new T[width * height]; // handled by GC
return res;
}
void checkRange(int x, int y) { // auto-magically removed in release code
assert(x >= 0 && y >= 0 && x < width && y < height, "x,y out of range");
}
T opIndex(int x, int y) {
checkRange(x,y);
return data[y * width + x];
}
T opIndexAssign(T v, int x, int y) {
checkRange(x, y);
return data[y * width + x] = v;
}
void fill(T v) {
data[] = v; // array write
}
int opApply(int delegate(ref T) dg) {
int result = 0;
foreach (ref elem; data) {
if ((result = dg(elem)) != 0) break;
}
return result;
}
}
alias Bitmap!(Rgb) RgbImage;
[edit] E
This example includes the write ppm file code, because it is most naturally written as a method on the image object.
def makeFlexList := <elib:tables.makeFlexList>
def format := <import:java.lang.makeString>.format
def CHANNELS := 3
def UByte := 0..255
def makeColor {
to fromFloat(r, g, b) {
return makeColor.fromByte((r * 255).round(),
(g * 255).round(),
(b * 255).round())
}
to fromByte(r :UByte, g :UByte, b :UByte) {
def color {
to __printOn(out) {
out.print(format("%02x%02x%02x", [color.rb(), color.gb(), color.bb()]))
}
to rf() { return r / 255 }
to gf() { return g / 255 }
to bf() { return b / 255 }
to rb() { return r }
to gb() { return g }
to bb() { return b }
}
return color
}
}
/** Convert 0..255 into 0..127 -128..-1 */
def sign(v) {
return v %% 256 - 2*(v & 128)
}
def makeImage(width, height) {
# NOTE: The primary E implementation is in Java and Java's fixed-size integers only
# come in signed varieties. Therefore, there is a little bit of extra arithmetic.
#
# In an ideal E implementation we would specify the type 0..255, but this is not
# currently possible everywhere, or efficient.
def storage := makeFlexList.fromType(<type:java.lang.Byte>, width * height * CHANNELS)
storage.setSize(width * height * CHANNELS)
def X := 0..!width
def Y := 0..!height
def flexImage {
to __printOn(out) {
for y in Y {
out.print("[")
for x in X {
out.print(flexImage[x, y], " ")
}
out.println("]")
}
}
to width() { return width }
to height() { return height }
to fill(color) {
for x in X {
for y in Y {
flexImage[x, y] := color
}
}
}
to get(x :X, y :Y) {
def base := (y * width + x) * CHANNELS
return makeColor.fromByte(storage[base + 0] %% 256,
storage[base + 1] %% 256,
storage[base + 2] %% 256)
}
/** Provided to make [[Flood fill]] slightly less insanely slow. */
to test(x :X, y :Y, c) {
def base := (y * width + x) * CHANNELS
return storage[base + 0] <=> sign(c.rb()) &&
storage[base + 1] <=> sign(c.gb()) &&
storage[base + 2] <=> sign(c.bb())
}
to put(x :X, y :Y, c) {
def base := (y * width + x) * CHANNELS
storage[base + 0] := sign(c.rb())
storage[base + 1] := sign(c.gb())
storage[base + 2] := sign(c.bb())
}
to writePPM(outputStream) {
outputStream.write(`P6$\n$width $height$\n255$\n`.getBytes("US-ASCII"))
outputStream.write(storage.getArray())
}
/** Used for [[Read ppm file]] */
to replace(list :List) {
require(list.size() == width * height * CHANNELS)
storage(0) := list
}
}
return flexImage
}
Examples/tests:
? def i := makeImage(3, 3)
# value: [000000 000000 000000 ]
# [000000 000000 000000 ]
# [000000 000000 000000 ]
#
? i.fill(makeColor.fromFloat(1, 0, 0))
? i
# value: [ff0000 ff0000 ff0000 ]
# [ff0000 ff0000 ff0000 ]
# [ff0000 ff0000 ff0000 ]
#
? i[1, 1] := makeColor.fromFloat(0.5, 0.5, 0.5)
# value: 808080
? i
# value: [ff0000 ff0000 ff0000 ]
# [ff0000 808080 ff0000 ]
# [ff0000 ff0000 ff0000 ]
#
? i[0, 1]
# value: ff0000
? i[1, 1]
# value: 808080
? i.writePPM(<import:java.io.makeFileOutputStream>(<file:~/Desktop/Rosetta.ppm>))
[edit] Factor
The image is a matrix of triples {R,G,B}. The various utilities could be defined in another file, most of them are not used right now, but we need them for drawing so I put every thing here..
USING: arrays fry kernel math.matrices sequences ;
IN: rosettacode.raster.storage
! Various utilities
: meach ( matrix quot -- ) [ each ] curry each ; inline
: meach-index ( matrix quot -- )
[ swap 2array ] prepose
[ curry each-index ] curry each-index ; inline
: mmap ( matrix quot -- matrix' ) [ map ] curry map ; inline
: mmap! ( matrix quot -- matrix' ) [ map! ] curry map! ; inline
: mmap-index ( matrix quot -- matrix' )
[ swap 2array ] prepose
[ curry map-index ] curry map-index ; inline
: matrix-dim ( matrix -- i j ) [ length ] [ first length ] bi ;
: set-Mi,j ( elt {i,j} matrix -- ) [ first2 swap ] dip nth set-nth ;
: Mi,j ( {i,j} matrix -- elt ) [ first2 swap ] dip nth nth ;
! The storage functions
: <raster-image> ( width height -- image )
zero-matrix [ drop { 0 0 0 } ] mmap ;
: fill-image ( {R,G,B} image -- image )
swap '[ drop _ ] mmap! ;
: set-pixel ( {R,G,B} {i,j} image -- ) set-Mi,j ; inline
: get-pixel ( {i,j} image -- pixel ) Mi,j ; inline
[edit] Forth
This creates bitmaps on the heap (they may be deallocated with "FREE"). 32-bit or greater cells are assumed, one pixel per cell. This automatically word-aligns rows, so a separate stride field is not required.
hex
0000ff constant red
00ff00 constant green
ff0000 constant blue
decimal
1 cells constant pixel
: pixels cells ;
: bdim ( bmp -- w h ) 2@ ;
: bheight ( bmp -- h ) @ ;
: bwidth ( bmp -- w ) bdim drop ;
: bdata ( bmp -- addr ) 2 cells + ;
: bitmap ( w h -- bmp )
2dup * pixels bdata allocate throw
dup >r 2! r> ;
: bfill ( pixel bmp -- )
dup bdata swap bdim * pixels
bounds do
dup i !
pixel +loop
drop ;
: bxy ( x y bmp -- addr )
dup >r bwidth * + pixels r> bdata + ;
: b@ ( x y bmp -- pixel ) bxy @ ;
: b! ( pixel x y bmp -- ) bxy ! ;
: bshow ( bmp -- )
hex
dup bdim
0 do cr
dup 0 do
over i j rot b@ if [char] * else bl then emit \ 7 u.r
loop
loop
2drop decimal ;
4 3 bitmap value test
red test bfill
test bshow cr
[edit] Fortran
See Basic bitmap storage/Fortran
[edit] Haskell
We implement the Image type as an STArray so that we can use it in an imperative fashion in the ST monad.
module Bitmap(module Bitmap) where
import Control.Monad
import Control.Monad.ST
import Data.Array.ST
newtype Pixel = Pixel (Int, Int) deriving Eq
instance Ord Pixel where
compare (Pixel (x1, y1)) (Pixel (x2, y2)) =
case compare y1 y2 of
EQ -> compare x1 x2
v -> v
instance Ix Pixel where
{- This instance differs from the one for (Int, Int) in that
the ordering of indices is
(0,0), (1,0), (2,0), (0,1), (1,1), (2,1)
instead of
(0,0), (0,1), (1,0), (1,1), (2,0), (2,1). -}
range (Pixel (xa, ya), Pixel (xz, yz)) =
[Pixel (x, y) | y <- [ya .. yz], x <- [xa .. xz]]
index (Pixel (xa, ya), Pixel (xz, _)) (Pixel (xi, yi)) =
(yi - ya)*(xz - xa + 1) + (xi - xa)
inRange (Pixel (xa, ya), Pixel (xz, yz)) (Pixel (xi, yi)) =
not $ xi < xa || xi > xz || yi < ya || yi > yz
rangeSize (Pixel (xa, ya), Pixel (xz, yz)) =
(xz - xa + 1) * (yz - ya + 1)
instance Show Pixel where
show (Pixel p) = show p
class Ord c => Color c where
luminance :: c -> Int
-- The Int should be in the range [0 .. 255].
black, white :: c
toNetpbm :: [c] -> String
fromNetpbm :: [Int] -> [c]
netpbmMagicNumber, netpbmMaxval :: c -> String
{- The argument to these two functions is ignored; the
parameter is only for typechecking. -}
newtype Color c => Image s c = Image (STArray s Pixel c)
image :: Color c => Int -> Int -> c -> ST s (Image s c)
{- Creates a new image with the given width and height, filled
with the given color. -}
image w h = liftM Image .
newArray (Pixel (0, 0), Pixel (w - 1, h - 1))
listImage :: Color c => Int -> Int -> [c] -> ST s (Image s c)
{- Creates a new image with the given width and height, with
each pixel set to the corresponding element of the given list. -}
listImage w h = liftM Image .
newListArray (Pixel (0, 0), Pixel (w - 1, h - 1))
dimensions :: Color c => Image s c -> ST s (Int, Int)
dimensions (Image i) = do
(_, Pixel (x, y)) <- getBounds i
return (x + 1, y + 1)
getPix :: Color c => Image s c -> Pixel -> ST s c
getPix (Image i) = readArray i
getPixels :: Color c => Image s c -> ST s [c]
getPixels (Image i) = getElems i
setPix :: Color c => Image s c -> Pixel -> c -> ST s ()
setPix (Image i) = writeArray i
fill :: Color c => Image s c -> c -> ST s ()
fill (Image i) c = getBounds i >>= mapM_ f . range
where f p = writeArray i p c
mapImage :: (Color c, Color c') =>
(c -> c') -> Image s c -> ST s (Image s c')
mapImage f (Image i) = liftM Image $ mapArray f i
This module provides an instance of Color.
module Bitmap.RGB(module Bitmap.RGB) where
import Bitmap
import Control.Monad.ST
newtype RGB = RGB (Int, Int, Int) deriving (Eq, Ord)
instance Color RGB where
luminance (RGB (r, g, b)) = round x
where x = 0.2126*r' + 0.7152*g' + 0.0722*b'
(r', g', b') = (toEnum r, toEnum g, toEnum b)
black = RGB (0, 0, 0)
white = RGB (255, 255, 255)
toNetpbm = concatMap f
where f (RGB (r, g, b)) = [toEnum r, toEnum g, toEnum b]
fromNetpbm [] = []
fromNetpbm (r : g : b : rest) = RGB (r, g, b) : fromNetpbm rest
netpbmMagicNumber _ = "P6"
netpbmMaxval _ = "255"
toRGBImage :: Color c => Image s c -> ST s (Image s RGB)
toRGBImage = mapImage $ f . luminance
where f x = RGB (x, x, x)
[edit] J
A number of addon packages are available for J that work with common image formats (including PPM), but here we will show a basic bitmap storage type as per the task description.
The structure is a 3-dimensional array of numbers. The shape of the array is height by width by 3. Each 1-dimensional cell of size 3 contains R, G and B numbers, in that order. Indexing is zero based.
No parameter validity checks are currently implemented.
In J, allocating an uninitialized image would not normally be separated from creating
the colored image, so makeRGB allows the specification of color during allocation. As a monad, makeRGB creates a black image with the specified height and width. It can also take a left argument (dyadic form) specifying the color(s) of the image. fillRGB requires a left argument specifying the color(s), but takes a bitmap (RGB) structure as the right argument.
Solution:
makeRGB=: 0&$: : (($,)~ ,&3)
fillRGB=: makeRGB }:@$
setPixels=: (1&{::@[)`(<"1@(0&{::@[))`]}
getPixels=: <"1@[ { ]
Examples:
myimg=: makeRGB 5 8 NB. create a bitmap with height 5 and width 8 (black)
myimg=: 255 makeRGB 5 8 NB. create a white bitmap with height 5 and width 8
myimg=: 0 255 0 makeRGB 5 8 NB. create a green bitmap with height 5 and width 8
myimg=: 0 0 255 fillRGB myimg NB. fill myimg with blue
colors=: 0 255 {~ #: i.8 NB. black,blue,green,cyan,red,magenta,yellow,white
myimg=: colors fillRGB myimg NB. fill myimg with vertical stripes of colors
2 4 getPixels myimg NB. get the pixel color from point (2, 4)
255 0 0
myimg=: (2 4 ; 255 255 255) setPixels myimg NB. set pixel at point (2, 4) to white
2 4 getPixels myimg NB. get the pixel color from point (2, 4)
255 255 255
}:$ myimg NB. get height and width of the image
5 8
getPixels and setPixels are generalized to set and get lists/arrays of pixels.
pixellist=: ,"0/~ i. 10 NB. row and column indices for 10 by 10 block of pixels
NB. create 10 by 10 block of magenta pixels in the middle of a 300 by 300 green image
myimg=: ((145 + pixellist) ; 255 0 255) setPixels 0 255 0 makeRGB 300 300
NB. get pixel color for 10x10 block offset from magenta block
subimg=: (140 + pixellist) getPixels myimg
To display the image in a window at any point for verification:
require 'viewmat'
viewRGB=: [: viewrgb 256&#.
viewRGB myimg
[edit] Java
Solution Library: AWT:
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.image.BufferedImage;
public class BasicBitmapStorage {
private BufferedImage image;
public BasicBitmapStorage(int width, int height) {
image = new BufferedImage(width, height, BufferedImage.TYPE_3BYTE_BGR);
}
public void fill(Color c) {
Graphics g = image.getGraphics();
g.setColor(c);
g.fillRect(0, 0, image.getWidth(), image.getHeight());
}
public void setPixel(int x, int y, Color c) {
image.setRGB(x, y, c.getRGB());
}
public Color getPixel(int x, int y) {
return new Color(image.getRGB(x, y));
}
public Image getImage() {
return image;
}
}
Test Program Library: JUnit:
import java.awt.Color;
import junit.framework.TestCase;
public class BasicBitmapStorageTest extends TestCase {
public static final int WIDTH = 640;
public static final int HEIGHT = 480;
BasicBitmapStorage bbs = new BasicBitmapStorage(WIDTH,HEIGHT);
public void testHappy() {
bbs.fill(Color.cyan);
bbs.setPixel(WIDTH/2, HEIGHT/2, Color.BLACK);
Color c1 = bbs.getPixel(WIDTH/2, HEIGHT/2);
Color c2 = bbs.getPixel(20, 20);
assertEquals(Color.BLACK, c1);
assertEquals(Color.CYAN, c2);
}
}
[edit] MAXScript
MAXScript provides a built-in Bitmap class.
local myBitmap = bitmap 512 512
Filling the image with a single colour can be accomplished at creation time by setting the color property.
local myBitmap = bitmap 512 512 color:(color 128 128 128)
Use setPixels to set the colour of a pixel. This function takes an array of colours and is optimised to set the colours of a whole row of pixels.
setPixels myBitmap [256, 256] #((color 255 255 255))
Use getPixels to retrieve the colour of a pixel. As with setPixels, this function is optimised to retrieve one row at a time as an array of colour values.
local myPixel = getPixels myBitmap [256, 256] 1
[edit] Modula-3
Since this code is for use with other tasks, it uses an interface as well as the implementation module.
INTERFACE Bitmap;
TYPE UByte = BITS 8 FOR [0 .. 16_FF];
Pixel = RECORD R, G, B: UByte; END;
Point = RECORD x, y: UByte; END;
T = REF ARRAY OF ARRAY OF Pixel;
CONST
Black = Pixel{0, 0, 0};
White = Pixel{255, 255, 255};
Red = Pixel{255, 0, 0};
Green = Pixel{0, 255, 0};
Blue = Pixel{0, 0, 255};
Yellow = Pixel{255, 255, 0};
EXCEPTION BadImage;
BadColor;
PROCEDURE NewImage(height, width: UByte): T RAISES {BadImage};
PROCEDURE Fill(VAR pic: T; color: Pixel);
PROCEDURE GetPixel(VAR pic: T; point: Point): Pixel RAISES {BadColor};
PROCEDURE SetPixel(VAR pic: T; point: Point; color: Pixel);
END Bitmap.
MODULE Bitmap;
PROCEDURE NewImage(height, width: UByte): T RAISES {BadImage} =
(* To make things easier, limit image size to also
be UByte (0 to 255), and to have equal dimensions. *)
BEGIN
IF height # width THEN
RAISE BadImage;
END;
RETURN NEW(T, height, width);
END NewImage;
PROCEDURE Fill(VAR pic: T; color: Pixel) =
BEGIN
FOR i := FIRST(pic^) TO LAST(pic^) DO
FOR j := FIRST(pic[0]) TO LAST(pic[0]) DO
pic[i,j] := color;
END;
END;
END Fill;
PROCEDURE GetPixel(VAR pic: T; point: Point): Pixel RAISES {BadColor} =
VAR pixel := pic[point.x, point.y];
BEGIN
IF pixel = White THEN
RETURN White;
ELSIF pixel = Black THEN
RETURN Black;
ELSIF pixel = Red THEN
RETURN Red;
ELSIF pixel = Green THEN
RETURN Green;
ELSIF pixel = Blue THEN
RETURN Blue;
ELSIF pixel = Yellow THEN
RETURN Yellow;
ELSE
RAISE BadColor;
END;
END GetPixel;
PROCEDURE SetPixel(VAR pic: T; point: Point; color: Pixel) =
BEGIN
pic[point.x, point.y] := color;
END SetPixel;
BEGIN
END Bitmap.
[edit] OCaml
let new_img ~width ~height =
let all_channels =
let kind = Bigarray.int8_unsigned
and layout = Bigarray.c_layout
in
Bigarray.Array3.create kind layout 3 width height
in
let r_channel = Bigarray.Array3.slice_left_2 all_channels 0
and g_channel = Bigarray.Array3.slice_left_2 all_channels 1
and b_channel = Bigarray.Array3.slice_left_2 all_channels 2
in
(all_channels,
r_channel,
g_channel,
b_channel)
and here is the type of the raster image this function returns:
type raster = (int, Bigarray.int8_unsigned_elt, Bigarray.c_layout) Bigarray.Array3.t * (int, Bigarray.int8_unsigned_elt, Bigarray.c_layout) Bigarray.Array2.t * (int, Bigarray.int8_unsigned_elt, Bigarray.c_layout) Bigarray.Array2.t * (int, Bigarray.int8_unsigned_elt, Bigarray.c_layout) Bigarray.Array2.t
What is particular with this allocation and its associated type is that there is not only one buffer for each RGB channel, but also an additionnal one that handles all the three channels, and what is important here is that it is not additionnal memory, the memory is shared, so there are 2 ways to access the raster buffer: through the separated RGB channels, or through the joint channel (all_channels).
This solution have a lot of advantages across a more naive one: this type is compatible to memory-map a file (a ppm file for instance, where the data is not compressed), the buffer can be shared/exchanged with C (for OpenGL textures for instance), etc.
A more naive form would be this one:
let new_img ~width ~height =
let r_channel, g_channel, b_channel =
let kind = Bigarray.int8_unsigned
and layout = Bigarray.c_layout
in
(Bigarray.Array2.create kind layout width height,
Bigarray.Array2.create kind layout width height,
Bigarray.Array2.create kind layout width height)
in
(r_channel,
g_channel,
b_channel)
Here are the functions to fill with a color and to set one given pixel:
let fill_img ~img:(_, r_channel, g_channel, b_channel) ~color:(r,g,b) =
Bigarray.Array2.fill r_channel r;
Bigarray.Array2.fill g_channel g;
Bigarray.Array2.fill b_channel b;
;;
let put_pixel_unsafe (_, r_channel, g_channel, b_channel) (r,g,b) =
(fun x y ->
r_channel.{x,y} <- r;
g_channel.{x,y} <- g;
b_channel.{x,y} <- b;
)
let get_pixel_unsafe (_, r_channel, g_channel, b_channel) =
(fun x y ->
(r_channel.{x,y},
g_channel.{x,y},
b_channel.{x,y})
)
we can overload these functions to make some bound checks:
let put_pixel img color x y =
let _, r_channel,_,_ = img in
let width = Bigarray.Array2.dim1 r_channel
and height = Bigarray.Array2.dim2 r_channel in
if (x < 0) || (x >= width) then invalid_arg "x out of bounds";
if (y < 0) || (y >= height) then invalid_arg "y out of bounds";
let r, g, b = color in
if (r < 0) || (r > 255) then invalid_arg "red out of bounds";
if (g < 0) || (g > 255) then invalid_arg "green out of bounds";
if (b < 0) || (b > 255) then invalid_arg "blue out of bounds";
put_pixel_unsafe img color x y;
;;
let get_pixel ~img ~pt:(x, y) =
let _, r_channel,_,_ = img in
let width = Bigarray.Array2.dim1 r_channel
and height = Bigarray.Array2.dim2 r_channel in
if (x < 0) || (x >= width) then invalid_arg "x out of bounds";
if (y < 0) || (y >= height) then invalid_arg "y out of bounds";
get_pixel_unsafe img x y;
;;
and a function to get the dimensions:
let get_dims ~img:(_, r_channel, _, _) =
let width = Bigarray.Array2.dim1 r_channel
and height = Bigarray.Array2.dim2 r_channel in
(width, height)
[edit] Octave
In Octave, images are matrix. A grayscale W×H image is stored as a W×H matrix, and RGB W×H image is stored as a W×H×3 image. Possible levels depend on the class of the storage: if it is double, the intensity is a floating point double number between 0 and 1; if it is uint8, the intensity is from 0 to 255; if it is uint16, the intensity is between 0 and 65535.
im = zeros(W, H, 3, "uint8"); % create an RGB image of width W and height H
% and intensity from 0 to 255; black (all zeros)
im(:,:,1) = 255; % set R to 255
im(:,:,2) = 100; % set G to 100
im(:,:,3) = 155; % set B to 155
im(floor(W/2), floor(H/2), :) = 0; % pixel in the center made black
disp(im(floor(W/3), floor(H/3), :)) % display intensities of the pixel
% at W/3, H/3
p = im(40,40,:); % or just store it in the vector p, so that
% p(1) is R, p(2) G and p(3) is B
We can hide this in helper functions like:
function im = create_rgb_image(w, h)
im = zeros(w, h, 3, "uint8");
endfunction
function set_background(im, colorvector)
im(:,:,1) = colorvector(1);
im(:,:,2) = colorvector(2);
im(:,:,3) = colorvector(3);
endfunction
function set_pixel(im, coord, colorvector)
im(coord(1), coord(2), 1) = colorvector(1);
im(coord(1), coord(2), 2) = colorvector(2);
im(coord(1), coord(2), 3) = colorvector(3);
endfunction
function [r, g, b] = get_pixel(im, coord)
r = im(coord(1), coord(2), 1)
g = im(coord(1), coord(2), 2)
b = im(coord(1), coord(2), 3)
endfunction
The only thing to note is that indexing start from 1.
%example
im = create_rgb_image(200,200);
for x = 1:128
im = set_pixel(im, [x, x], [200, 50, 220]);
endfor
% it seems like saveimage wants double class on [0,1]
saveimage("image.ppm", double(im)./256, "ppm");
[edit] Oz
We first create a 2D array data type as a functor in a file "Array2D.oz":
functor
export
New
Get
Set
Transform
define
fun {New Width Height Init}
C = {Array.new 1 Height unit}
in
for Row in 1..Height do
C.Row := {Array.new 1 Width Init}
end
array2d(width:Width
height:Height
contents:C)
end
fun {Get array2d(contents:C ...) X Y}
C.Y.X
end
proc {Set array2d(contents:C ...) X Y Val}
C.Y.X := Val
end
proc {Transform array2d(contents:C width:W height:H ...) Fun}
for Y in 1..H do
for X in 1..W do
C.Y.X := {Fun C.Y.X}
end
end
end
%% omitted: Clone, Map, Fold, ForAll
end
Based on this, we create a functor "Bitmap.oz":
%% For real task prefer QTk's images:
%% http://www.mozart-oz.org/home/doc/mozart-stdlib/wp/qtk/html/node38.html
functor
import
Array2D
export
New
Fill
GetPixel
SetPixel
define
Black = color(0x00 0x00 0x00)
fun {New Width Height}
bitmap( {Array2D.new Width Height Black} )
end
proc {Fill bitmap(Arr) Color}
{Array2D.transform Arr fun {$ _} Color end}
end
fun {GetPixel bitmap(Arr) X Y}
{Array2D.get Arr X Y}
end
proc {SetPixel bitmap(Arr) X Y Color}
{Array2D.set Arr X Y Color}
end
%% Omitted: MaxValue, ForAllPixels, Transform
end
Some functions that are used in other tasks were omitted. See here for the complete module definitions: Basic bitmap storage/Oz
[edit] Perl
Library: Imlib2
#! /usr/bin/perl
use strict;
use Image::Imlib2;
# create the "canvas"
my $img = Image::Imlib2->new(200,200);
# fill with a plain RGB(A) color
$img->set_color(255, 0, 0, 255);
$img->fill_rectangle(0,0, 200, 200);
# set a pixel to green (at 40,40)
$img->set_color(0, 255, 0, 255);
$img->draw_point(40,40);
# "get" pixel rgb(a)
my ($red, $green, $blue, $alpha) = $img->query_pixel(40,40);
undef $img;
# another way of creating a canvas with a bg colour (or from
# an existing "raw" data)
my $col = pack("CCCC", 255, 255, 0, 0); # a, r, g, b
my $img = Image::Imlib2->new_using_data(200, 200, $col x (200 * 200));
exit 0;
[edit] PHP
class Bitmap {
public $data;
public $w;
public $h;
public function __construct($w = 16, $h = 16){
$white = array_fill(0, $w, array(255,255,255));
$this->data = array_fill(0, $h, $white);
$this->w = $w;
$this->h = $h;
}
//Fills a rectangle, or the whole image with black by default
public function fill($x = 0, $y = 0, $w = null, $h = null, $color = array(0,0,0)){
if (is_null($w)) $w = $this->w;
if (is_null($h)) $h = $this->h;
$w += $x;
$h += $y;
for ($i = $y; $i < $h; $i++){
for ($j = $x; $j < $w; $j++){
$this->setPixel($j, $i, $color);
}
}
}
public function setPixel($x, $y, $color = array(0,0,0)){
if ($x >= $this->w) return false;
if ($x < 0) return false;
if ($y >= $this->h) return false;
if ($y < 0) return false;
$this->data[$y][$x] = $color;
}
public function getPixel($x, $y){
return $this->data[$y][$x];
}
}
$b = new Bitmap(16,16);
$b->fill();
$b->fill(2, 2, 18, 18, array(240,240,240));
$b->setPixel(0, 15, array(255,0,0));
print_r($b->getPixel(3,3)); //(240,240,240)
[edit] PL/I
/* Declaration for an image, suitable for BMP files. */
declare image(0:500, 0:500) bit (24) aligned;
image = '000000000000000011111111'b;
/* Sets the entire image to red. */
image(10,40) = '111111110000000000000000'b;
/* Sets one pixel to blue. */
declare color bit (24) aligned;
color = image(20,50); /* Obtain the color of a pixel */
/* To allocate an image of size (x,y) */
allocate_image: procedure (image, x, y);
declare image (*, *) controlled bit (24) aligned;
declare (x, y) fixed binary (31);
allocate image (0:x, 0:y);
end allocate_image;
/* To use the above procedure, it's necessary to define */
/* the image in the calling program thus, for BMP images: */
declare image(*,*) controlled bit (24) aligned;
[edit] PicoLisp
For time critical applications this would be done with inline-C in PicoLisp, but especially for small bitmaps the following makes sense.
# Create an empty image of 120 x 90 pixels
(setq *Ppm (make (do 90 (link (need 120)))))
# Fill an image with a given color
(de ppmFill (Ppm R G B)
(for Y Ppm
(map
'((X) (set X (list R G B)))
Y ) ) )
# Set pixel with a color
(de ppmSetPixel (Ppm X Y R G B)
(set (nth Ppm Y X) (list R G B)) )
# Get the color of a pixel
(de ppmGetPixel (Ppm X Y)
(get Ppm Y X) )
[edit] PureBasic
w=800 : h=600
CreateImage(1,w,h)
;1 is internal id of image
StartDrawing(ImageOutput(1))
; fill with color red
Box(0,0,w,h,$ff)
; or using another (but slower) way in green
FillArea(0,0,-1,$ff00)
; a green Dot
Plot(10,10,$ff0000)
; check if we set it right (should be 255)
Debug Blue(Point(10,10))
[edit] Python
See Basic bitmap storage/Python
[edit] R
Library: pixmap
R can write to most bitmap image formats by default (mostly for the purpose of saving graphs), however there is no built-in way of manipulating images. The pixmap package reads, writes and manipulates portable bitmap file types: PBM, PGM, PPM. See also, the image function, and the rimage and ReadImage packages, which use libjpeg to read JPEG and PNG files.
# See the class definitions and constructors with, e.g.
getClass("pixmapIndexed", package=pixmap)
pixmapIndexed
# Image with all one colour
plot(p1 <- pixmapIndexed(matrix(0, nrow=3, ncol=4), col="red"))
# Image with one pixel specified
cols <- rep("blue", 12); cols[7] <- "red"
plot(p2 <- pixmapIndexed(matrix(1:12, nrow=3, ncol=4), col=cols))
# Retrieve colour of a pixel
getcol <- (pm, i, j)
{
pmcol <- pm@col
dim(pmcol) <- dim(pm@index)
pmcol[i,j]
}
getcol(p2, 3, 4) #red
[edit] RapidQ
QCanvas is an empty image on which you can draw. QForm is the main window of the application. The commands to draw on the canvas are in the procedure PaintCanvas, which is executed each time the canvas need to be (re)painted.
DECLARE SUB PaintCanvas
CREATE form AS QForm
Width = 640
Height = 480
CREATE canvas AS QCanvas
Height = form.ClientHeight
Width = form.ClientWidth
OnPaint = PaintCanvas
END CREATE
END CREATE
SUB PaintCanvas
' Fill background
canvas.FillRect(0, 0, canvas.Width, canvas.Height, &H301000)
' Draw a pixel
canvas.Pset(300, 200, &H00ddff)
' Read pixel color
PRINT canvas.Pixel(300, 200)
END SUB
form.ShowModal
[edit] Ruby
I haven't been able to find any kind of package for manipulating bitmap images, so let's roll one
class RGBColour
def initialize(red, green, blue)
unless red.between?(0,255) and green.between?(0,255) and blue.between?(0,255)
raise ArgumentError, "invalid RGB parameters: #{[red, green, blue].inspect}"
end
@red, @green, @blue = red, green, blue
end
attr_reader :red, :green, :blue
alias_method :r, :red
alias_method :g, :green
alias_method :b, :blue
RED = RGBColour.new(255,0,0)
GREEN = RGBColour.new(0,255,0)
BLUE = RGBColour.new(0,0,255)
BLACK = RGBColour.new(0,0,0)
WHITE = RGBColour.new(255,255,255)
end
class Pixmap
def initialize(width, height)
@width = width
@height = height
@data = fill(RGBColour::WHITE)
end
attr_reader :width, :height
def fill(colour)
@data = Array.new(@width) {Array.new(@height, colour)}
end
def validate_pixel(x,y)
unless x.between?(0, @width-1) and y.between?(0, @height-1)
raise ArgumentError, "requested pixel (#{x}, #{y}) is outside dimensions of this bitmap"
end
end
def [](x,y)
validate_pixel(x,y)
@data[x][y]
end
alias_method :get_pixel, :[]
def []=(x,y,colour)
validate_pixel(x,y)
@data[x][y] = colour
end
alias_method :set_pixel, :[]=
end
[edit] Scheme
Works with: Scheme version R5RS
Definitions of list procedures:
(define (make-list length object)
(if (= length 0)
(list)
(cons object (make-list (- length 1) object))))
(define (list-fill! list object)
(if (not (null? list))
(begin (set-car! list object) (list-fill! (cdr list) object))))
(define (list-set! list element object)
(if (= element 1)
(set-car! list object)
(list-set! (cdr list) (- element 1) object)))
(define (list-get list element)
(if (= element 1)
(car list)
(list-get (cdr list) (- element 1))))
Definitions of image procedures:
(define (make-image columns rows)
(if (= rows 0)
(list)
(cons (make-list columns (list)) (make-image columns (- rows 1)))))
(define (image-fill! image colour)
(if (not (null? image))
(begin (list-fill! (car image) colour) (image-fill! (cdr image) colour))))
(define (image-set! image column row colour)
(list-set! (list-get image row) column colour))
(define (image-get image column row)
(list-get (list-get image row) column))
Definitions of some colours:
(define *black* (list 0 0 0))
(define *white* (list 255 255 255))
(define *red* (list 255 0 0))
(define *green* (list 0 255 0))
(define *blue* (list 0 0 255))
This creates a small image with a black background and a single blue pixel:
(define image (make-image 3 2))
(image-fill! image *black*)
(image-set! image 2 1 *blue*)
(display image)
(newline)
Output:
(((0 0 0) (0 0 255) (0 0 0)) ((0 0 0) (0 0 0) (0 0 0)))
[edit] Tcl
Library: Tk
package require Tcl 8.5
package require Tk
namespace path ::tcl::mathfunc ;# for [max] function
proc newImage {width height} {
return [image create photo -width $width -height $height]
}
proc fill {image colour} {
$image put $colour -to 0 0 [$image cget -width] [$image cget -height]
}
proc setPixel {image colour point} {
lassign $point x y
$image put $colour -to [max 0 $x] [max 0 $y]
}
proc getPixel {image point} {
lassign $point x y
# [$img get] returns a list: {r g b}; this proc should return a colour value
format {#%02x%02x%02x} {*}[$image get $x $y]
}
# create the image and display it
set img [newImage 150 150]
label .l -image $img
pack .l
fill $img red
setPixel $img green {40 40}
set rbg [getPixel $img {40 40}]
[edit] TI-89 BASIC
TI-89 BASIC does not have user-defined data structures. The Rosetta Code tasks which use this image type have instead been implemented using the TI-89's graph screen.
[edit] Visual Basic .NET
' The StructLayout attribute allows fields to overlap in memory.
<System.Runtime.InteropServices.StructLayout(LayoutKind.Explicit)> _
Public Structure Rgb
<FieldOffset(0)> _
Public Rgb As Integer
<FieldOffset(0)> _
Public B As Byte
<FieldOffset(1)> _
Public G As Byte
<FieldOffset(2)> _
Public R As Byte
Public Sub New(ByVal r As Byte, ByVal g As Byte, ByVal b As Byte)
Me.R = r
Me.G = g
Me.B = b
End Sub
End Structure
Public Class RasterBitmap
Private m_pixels() As Rgb
Private m_width As Integer
Public ReadOnly Property Width As Integer
Get
Return m_width
End Get
End Property
Private m_height As Integer
Public ReadOnly Property Height As Integer
Get
Return m_height
End Get
End Property
Public Sub New(ByVal width As Integer, ByVal height As Integer)
m_pixels = New Rgb(width * height - 1) {}
m_width = width
m_height = height
End Sub
Public Sub Clear(ByVal color As Rgb)
For i As Integer = 0 To m_pixels.Length - 1
m_pixels(i) = color
Next
End Sub
Public Sub SetPixel(ByVal x As Integer, ByVal y As Integer, ByVal color As Rgb)
m_pixels((y * m_width) + x) = color
End Sub
Public Function GetPixel(ByVal x As Integer, ByVal y As Integer) As Rgb
Return m_pixels((y * m_width) + x)
End Function
End Class
[edit] Vedit macro language
An edit buffer is used to store pixel data. In order to allow unlimited image size, a temporary file (here pixel.data) can be assosicated to the buffer. You could directly open the image file you are creating (as in the task Dragon_curve, but here we first create just the plain pixel data so that the required image file format can be decided later.
#11 = 400 // Width of the image
#12 = 300 // Height of the image
// Create an empty RGB image and fill it with black color
//
File_Open("|(VEDIT_TEMP)\pixel.data", OVERWRITE+NOEVENT)
BOF
Del_Char(ALL)
#10 = Buf_Num
Repeat(#11 * #12) {
Ins_Char(0, COUNT, 3)
}
// Fill the image with dark blue color
//
#5 = 0 // Red
#6 = 0 // Green
#7 = 64 // Blue
Call("FILL_IMAGE")
// Draw one pixel in orange color
//
#1 = 100 // x
#2 = 50 // y
#5 = 255 #6 = 128 #7 = 0 // Orange color
Call("DRAW_PIXEL")
// Get the color of a pixel
//
#1 = 10
#2 = 3
Call("GET_COLOR")
Buf_Switch(#10) Buf_Quit(OK)
Return
/////////////////////////////////////////////////////////////////////
//
// Fill image with given color: #5 = Red, #6 = Green, #7 = Blue
//
:FILL_IMAGE:
BOF
Repeat (File_Size/3) {
IC(#5,OVERWRITE) IC(#6,OVERWRITE) IC(#7,OVERWRITE)
}
Return
/////////////////////////////////////////////////////////////////////
//
// Daw a pixel. #1 = x, #2 = y
//
:DRAW_PIXEL:
Goto_Pos((#1 + #2*#11)*3)
IC(#5,OVERWRITE) IC(#6,OVERWRITE) IC(#7,OVERWRITE)
Return
/////////////////////////////////////////////////////////////////////
//
// Get color of a pixel. #1 = x, #2 = y
// Return: #5 = Red, #6 = Green, #7 = Blue
//
:GET_COLOR:
Goto_Pos((#1 + #2*#11)*3)
#5 = Cur_Char
#6 = Cur_Char(1)
#7 = Cur_Char(2)
Return

