Bitmap

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.
T Colour = Vec3b V black = Colour(0, 0, 0) V white = Colour(255, 255, 255) T Bitmap Int width, height Colour background [[Colour]] map F (width = 40, height = 40, background = white) assert(width > 0 & height > 0) .width = width .height = height .background = background .map = [[background] * width] * height F fillrect(x, y, width, height, colour = black) assert(x >= 0 & y >= 0 & width > 0 & height > 0) L(h) 0 .< height L(w) 0 .< width .map[y + h][x + w] = colour F chardisplay() V txt = .map.map(row -> row.map(bit -> (I bit == @@.background {‘ ’} E ‘@’)).join(‘’)) txt = txt.map(row -> ‘|’row‘|’) txt.insert(0, ‘+’(‘-’ * .width)‘+’) txt.append(‘+’(‘-’ * .width)‘+’) print(reversed(txt).join("\n")) F set(x, y, colour = black) .map[y][x] = colour F get(x, y) R .map[y][x] V bitmap = Bitmap(20, 10) bitmap.fillrect(4, 5, 6, 3) assert(bitmap.get(5, 5) == black) assert(bitmap.get(0, 1) == white) bitmap.set(0, 1, black) assert(bitmap.get(0, 1) == black) bitmap.chardisplay()- Output:
+--------------------+ | | | | | @@@@@@ | | @@@@@@ | | @@@@@@ | | | | | | | |@ | | | +--------------------+
Part of the solution can be found in RGBIMAGE.ACT
INCLUDE "H6:RGBIMAGE.ACT" ;from task Bitmap RGB black,yellow,violet,blue PROC DrawImage(RgbImage POINTER img BYTE x,y) RGB c BYTE i,j FOR j=0 TO img.h-1 DO FOR i=0 TO img.w-1 DO GetRgbPixel(img,i,j,c) IF RgbEqual(c,yellow) THEN Color=1 ELSEIF RgbEqual(c,violet) THEN Color=2 ELSEIF RgbEqual(c,blue) THEN Color=3 ELSE Color=0 FI Plot(x+i,y+j) OD OD RETURN PROC Main() RgbImage img BYTE CH=$02FC,width=[80],height=[60] BYTE ARRAY ptr(14400) BYTE i,x,y,c Graphics(7+16) SetColor(0,13,12) ;yellow SetColor(1,4,10) ;violet SetColor(2,8,6) ;blue SetColor(4,0,0) ;black RgbBlack(black) RgbYellow(yellow) RgbViolet(violet) RgbBlue(blue) InitRgbImage(img,width,height,ptr) FillRgbImage(img,blue) FOR i=1 TO 1000 DO c=Rand(3) x=Rand(width) y=Rand(height) IF c=0 THEN SetRgbPixel(img,x,y,yellow) ELSEIF c=1 THEN SetRgbPixel(img,x,y,violet) ELSE SetRgbPixel(img,x,y,black) FI OD DrawImage(img,(160-width)/2,(96-height)/2) DO UNTIL CH#$FF OD CH=$FF RETURN- Output:
Screenshot from Atari 8-bit computer
ActionScript 3 has a BitmapData class (in the flash.display package) which can be used for storage and handling of bitmap images. To display these images, the Bitmap class can be used.
// To import the BitmapData class: import flash.display.BitmapData; // Creates a new BitmapData object with a width of 500 pixels and a height of 300 pixels. var bitmap:BitmapData = new BitmapData(500, 300); // Create a BitmapData with transparency disallowed var opaqueBitmap:BitmapData = new BitmapData(500, 300, false); // Bitmap with initial fill colour, as 0xAARRGGBB (default is white) var redFilledBitmap:BitmapData = new BitmapData(400, 300, true, 0xFFFF0000); // Get the colour value of the pixel at point (200, 200) bitmap.getPixel(200, 200) // As 0xRRGGBB bitmap.getPixel32(200, 200) // As 0xAARRGGBB // Set the colour value of the pixel at point (300, 200) to blue bitmap.setPixel(300, 200, 0x0000FF); // As 0xRRGGBB bitmap.setPixel32(300, 200, 0xFF0000FF); // As 0xAARRGGBB // Fill the bitmap with a given colour (as 0xAARRGGBB) after construction bitmap.fillRect(bitmap.rect, 0xFF44FF44); The package interface:
package Bitmap_Store is type Luminance is mod 2**8; type Pixel is record R, G, B : Luminance := Luminance'First; end record; Black : constant Pixel := (others => Luminance'First); White : constant Pixel := (others => Luminance'Last); 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 p of Picture loop x:= Color;end loop; end Fill; procedure Print (Picture : Image) is begin for I in Picture'Range (1) loop for J in Picture'Range (2) loop Put (if Picture (I, J) = White then ' ' else 'H'); 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);
File: prelude/Bitmap.a68 (a translation of the Ada sample) is available on Rosetta Code ALGOL 68/prelude#prelude/Bitmap.a68
File: test/Bitmap.a68
#!/usr/bin/a68g --script # # -*- coding: utf-8 -*- # ### The test program ### PR READ "prelude/Bitmap.a68" PR; test:( REF IMAGE x := INIT LOC[1:16, 1:16]PIXEL; (fill OF class image) (x, white OF class image); (print OF class image) (x) )- Output:
(A 16x16 white block)
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
The Bitmap Address (BA) of the image is 24576 in order to maximize available space for the image without clobbering hi-res graphics memory. Just enough room is allocated for a P6 header. The Bitmap Beginning (BB) is just after the header.
HIMEM is set to 8192 which is just below hi-res graphics memory. It isn't necessary to protect hi-res graphics memory, but it doesn't hurt. Larger images can be allocated by using a lower Bitmap Address.
100 W = 8 110 H = 8 120 BB = 24576 + LEN ( STR$ (W) + STR$ (H)) + 9: REM P6 HEADER 130 HIMEM: 8192 140 R = 255 150 G = 255 160 B = 0 170 C = R + G * 256 + B * 65536 180 GOSUB 600FILL 190 X = 4 200 Y = 5 210 R = 127 220 G = 127 230 B = 255 240 C = R + G * 256 + B * 65536 250 GOSUB 500"SET PIXEL" 260 X = 3 270 Y = 2 280 GOSUB 400"GET PIXEL" 290 PRINT "COLOR="C" RED="R" GREEN="G" BLUE="B; 300 END 400 A = BB + X * 3 + Y * W * 3 410 R = PEEK (A) 420 G = PEEK (A + 1) 430 B = PEEK (A + 2) 440 C = R + G * 256 + B * 65536 450 RETURN 500 R = C - INT (C / 256) * 256 510 B = INT (C / 65536) 520 G = INT (C / 256) - B * 256 530 A = BB + X * 3 + Y * W * 3 540 POKE A,R 550 POKE A + 1,G 560 POKE A + 2,B 570 RETURN 600 FOR Y = 0 TO H - 1 610 FOR X = 0 TO W - 1 620 GOSUB 500"SET PIXEL" 630 NEXT X,Y 640 RETURN The Game Boy Advance's video memory is located at address 0x06000000, and is 240 pixels by 160 pixels, with 16 bits defining the color of each pixel. This is a linear array of memory; storing 0xFFFF at 0x06000000 for example will immediately make the top-left pixel of the screen turn white. The following routines are intended for the bitmap screen modes, and have only been tested in screen mode 3. There is no need to allocate this video memory as it is always available thanks to the hardware.
Bitmap_FloodFill: ;input: ;r0 = color to fill screen with (15-bit color) STMFD sp!,{r0-r12,lr} MOV R2,#160 MOV R4,#0x06000000 outerloop_floodfill: MOV R1,#240 ;restore inner loop counter innerloop_floodfill: strH r0,[r4] add r4,r4,#2 ;next pixel subs r1,r1,#1 ;decrement loop counter bne innerloop_floodfill subs r2,r2,#1 bne outerloop_floodfill LDMFD sp!,{r0-r12,pc} Bitmap_Locate: ;given x and y coordinates, offsets vram addr to that pixel on screen. ;input: ;r0 = x ;r1 = y ;output: r2 = vram area STMFD sp!,{r4-r12,lr} mov r2,#0x06000000 ;vram base mov r4,#240*2 ;240 pixels across, 2 bytes per pixel mul r1,r4,r1 add r2,r2,r1 ;add y*480 add r2,r2,r0,lsl #1 ;add x*2 LDMFD sp!,{r4-r12,pc} Bitmap_StorePixel: ;input: r3 = color ;r0 = x ;r1 = y bl Bitmap_Locate strH r3,[r2] ;store the pixel color in video memory bx lr Bitmap_GetPixel: ;retrieves the color of the pixel at [r2] and stores its color value in r3. ;r0 = x ;r1 = y ;output in r3 bl Bitmap_Locate ldrH r3,[r2] bx lrBecause this code will be used in other tasks, I have separated it into "static" and "dynamic" source files. The former is the equivalent of an "interface" file in some other languages, and the latter is equivalent of an "implementation" file. I included some test code that gets compiled if you put the correct option on the compiler command line.
The ATS static file
This file should be called bitmap_task.sats.
#define ATS_PACKNAME "Rosetta_Code.bitmap_task" (*------------------------------------------------------------------*) (* I am going to do this at the most primitive level. So here is the "abstractified" type, or really a whole set of different types: w-by-h pixmap of values of type a, with pixel storage at address p. The type is linear (‘use it once and only once’). We will make pixmap a boxed type, so its size will be equal to that of a pointer. (This is actually a general 2-dimensional array type! But let us ignore that.) *) absvtype pixmap (a : t@ype, w : int, h : int, p : addr) = ptr (* A shorthand for a pixmap with its pixel storage at "some" address. *) vtypedef pixmap (a : t@ype, w : int, h : int) = [p : addr] pixmap (a, w, h, p) (* A shorthand for a pixmap with "some" width and height, and with its pixel storage at "some" address. *) vtypedef pixmap (a : t@ype) = [w, h : int] pixmap (a, w, h) (* A shorthand for a pixmap with "some" POSITIVE width and POSITIVE height, and with its pixel storage at "some" address. *) vtypedef pixmap1 (a : t@ype) = [w, h : pos] pixmap (a, w, h) (*------------------------------------------------------------------*) (* Here are definitions for a small set of operations, including the ones requested in the task document. But note that, in ATS, we are careful about uninitialized data. It is POSSIBLE to create an uninitialized pixmap, but NOT possible to set or get individual pixels, if the pixmap is not already fully initialized by some other means (such as "fill" or "load"). *) fn {} pixmap_width : {a : t@ype} {w, h : int} (!pixmap (a, w, h)) -<> size_t w fn {} pixmap_height : {a : t@ype} {w, h : int} (!pixmap (a, w, h)) -<> size_t h fn {a : t@ype} pixmap_make_array : (* Make a new pixmap from an existing array. The array may be anywhere (for instance, a stack frame or the heap), and need not be initialized. *) {w, h : int} {p : addr} (array_v (a, p, w * h) | size_t w, size_t h, ptr p) -> pixmap (a, w, h, p) fn {a : t@ype} pixmap_unmake : (* Essentially the reverse of pixmap_make_array. Temporarily treat a pixmap as an array. The array will be organized as rows from left to right, with the rows themselves going from top to bottom. Thus an index would be i = x + (y * w). *) {w, h : int} {p : addr} pixmap (a, w, h, p) -> @(array_v (a, p, w * h) | size_t w, size_t h, ptr p) prfn pixmap_prove_index_bounds : (* A proof that i = x + (y * w) is within bounds of the array returned by pixmap_unmake. *) {w, h : int} {x, y : nat | x < w; y < h} () -<prf> [0 <= x + (y * w); x + (y * w) < w * h] void fn {a : t@ype} pixmap_make_uninitized : (* Make a new uninitialized pixmap, with the pixels stored in the heap. *) {w, h : int} (size_t w, size_t h) -> [p : addr | null < p] @(mfree_gc_v p | pixmap (a?, w, h, p)) fn {a : t@ype} pixmap_make_elt : (* Make a new pixmap, initialized with a given element, with the pixels stored in the heap. *) {w, h : int} (size_t w, size_t h, a) -> [p : addr | null < p] @(mfree_gc_v p | pixmap (a, w, h, p)) fn {} pixmap_free_storage_return : (* Free a pixmap, returning the storage array to the user. *) {a : t@ype} {w, h : int} {p : addr} pixmap (a, w, h, p) -> @(array_v (a, p, w * h) | ptr p) fn {} pixmap_free_storage_free : (* If a pixmap's pixels were allocated in the heap, then free its storage. *) {a : t@ype} {w, h : int} {p : addr} (mfree_gc_v p | pixmap (a, w, h, p)) -> void fn {a : t@ype} pixmap_fill_elt : (* Fill a pixmap with the given element. (Technically speaking, the value of the first argument is consumed, and replaced by a new value. Its type before and after is linear.) *) {w, h : int} {p : addr} (* The question mark means that the pixmap elements can start out uninitialized. *) (!pixmap (a?, w, h, p) >> pixmap (a, w, h, p), a) -> void fn {a : t@ype} {tk : tkind} pixmap_set_at_guint : (* Set a pixel at unsigned integer coordinates. You can do this only on a pixmap that has been initialized. (It would be prohibitively tedious to safely work with randomly located pixels, if the array were not already fully initialized.) *) {w, h : int} {x, y : int | x < w; y < h} (!pixmap (a, w, h), g1uint (tk, x), g1uint (tk, y), a) -> void fn {a : t@ype} {tk : tkind} pixmap_set_at_gint : (* Set a pixel, but with signed integer coordinates. *) {w, h : int} {x, y : nat | x < w; y < h} (!pixmap (a, w, h), g1int (tk, x), g1int (tk, y), a) -> void fn {a : t@ype} {tk : tkind} pixmap_get_at_guint : (* Get a pixel at unsigned integer coordinates. You can do this only on a pixmap that has been initialized. *) {w, h : int} {x, y : int | x < w; y < h} (!pixmap (a, w, h), g1uint (tk, x), g1uint (tk, y)) -> a fn {a : t@ype} {tk : tkind} pixmap_get_at_gint : (* Get a pixel, but with signed integer coordinates. *) {w, h : int} {x, y : nat | x < w; y < h} (!pixmap (a, w, h), g1int (tk, x), g1int (tk, y)) -> a fn {a : t@ype} pixmap_dump : (* Dump the contents of a pixmap to an output stream, row by row as in a PPM. You must implement the pixmap$pixels_dump template function. (We are anticipating the task to write a PPM file, and wish to do it in a nice way. I am likely to end up actually using this code, after all.) *) {w, h : int} (* I return a success-or-failure value, to avoid committing to using an exception here. There are circumstances in which exceptions are not the best approach. *) (FILEref, !pixmap (a, w, h)) -> bool (* success *) fn {a : t@ype} pixmap$pixels_dump : (* A function that the writes n pixels to an output stream. (It could be one pixel, it could be the entire image. From the user's standpoint, it makes no difference. It is an implementation detail HOW the function is called by pixmap_dump.) *) {n : int} (FILEref, &array (a, n), size_t n) -> bool (* success *) fn {a : t@ype} pixmap_load : (* Load the contents of a pixmap from an input stream, row by row as in a PPM. You must implement the pixmap$pixels_load template function. A value of type a has to be given, to initialize the array with if the loading fails. *) {w, h : int} {p : addr} (FILEref, !pixmap (a?, w, h, p) >> pixmap (a, w, h, p), a) -> bool (* success *) fn {a : t@ype} pixmap$pixels_load : (* A function that the reads n pixels from an input stream. (It could be one pixel, it could be the entire image. From the user's standpoint, it makes no difference. It is an implementation detail HOW the function is called by pixmap_load.) *) {n : int} (FILEref, &array (a?, n) >> array (a, n), size_t n, a) -> bool (* success *) overload pixmap_make with pixmap_make_array overload pixmap_make with pixmap_make_uninitized overload pixmap_make with pixmap_make_elt overload pixmap_free with pixmap_free_storage_return overload pixmap_free with pixmap_free_storage_free overload free with pixmap_free_storage_free overload fill with pixmap_fill_elt overload pixmap_set_at with pixmap_set_at_guint overload pixmap_set_at with pixmap_set_at_gint overload [] with pixmap_set_at overload pixmap_get_at with pixmap_get_at_guint overload pixmap_get_at with pixmap_get_at_gint overload [] with pixmap_get_at overload dump with pixmap_dump overload load with pixmap_load overload width with pixmap_width overload height with pixmap_height (*------------------------------------------------------------------*) (* Here is a type for 24-bit RGB data. An RGB pixmap type thus can be written as "pixmap (rgb24, w, h, p)". There are, though you cannot see it here (they are in the dynamic file), default implementations of pixmap$pixels_dump<rgb24> and pixmap$pixels_load<rgb24>. These implementations are for dumping raw data in PPM format. *) (* It is an abstract type, the size of a triple of uint8. (It is, in fact, a triple of uint8, but we hide this fact, so the template system will not confuse the type with other triples of uint8. It is a subtle matter. *) abst@ype rgb24 = @(uint8, uint8, uint8) fn {tk : tkind} rgb24_make_uint_uint_uint : (g0uint tk, g0uint tk, g0uint tk) -<> rgb24 fn {tk : tkind} rgb24_make_int_int_int : (g0int tk, g0int tk, g0int tk) -<> rgb24 fn {} rgb24_make_tuple : @(uint8, uint8, uint8) -<> rgb24 fn {} rgb24_values : rgb24 -<> @(uint8, uint8, uint8) overload rgb24_make with rgb24_make_uint_uint_uint overload rgb24_make with rgb24_make_int_int_int overload rgb24_make with rgb24_make_tuple (*------------------------------------------------------------------*)The ATS dynamic file
This file should be called bitmap_task.dats.
(*------------------------------------------------------------------*) #define ATS_DYNLOADFLAG 0 #define ATS_PACKNAME "Rosetta_Code.bitmap_task" #include "share/atspre_staload.hats" staload "bitmap_task.sats" (*------------------------------------------------------------------*) (* The actual type, normally not seen by the user, is a boxed record. *) datavtype _pixmap (a : t@ype, w : int, h : int, p : addr) = | _pixmap of @{ pf = array_v (a, p, w * h) | w = size_t w, h = size_t h, p = ptr p } (* Here is one of the ways to tie an abstract type to its implementation: *) assume pixmap (a, w, h, p) = _pixmap (a, w, h, p) (* Another way is to use casts. *) (*------------------------------------------------------------------*) implement {} pixmap_width pix = case+ pix of _pixmap record => record.w implement {} pixmap_height pix = case+ pix of _pixmap record => record.h implement {a} pixmap_make_array (pf | w, h, p) = _pixmap @{pf = pf | w = w, h = h, p = p} implement {a} pixmap_unmake pix = case+ pix of | ~ _pixmap @{pf = pf | w = w, h = h, p = p} => @(pf | w, h, p) primplement pixmap_prove_index_bounds {w, h} {x, y} () = let prval () = mul_gte_gte_gte {y, w} () prval () = mul_gte_gte_gte {h - (y + 1), w} () in end implement {a} pixmap_make_uninitized {w, h} (w, h) = let prval () = lemma_g1uint_param w (* Proves w >= 0. *) prval () = lemma_g1uint_param h (* Proves h >= 0. *) prval () = mul_gte_gte_gte {w, h} () (* Proves w*h >= 0. *) val @(pf, pfgc | p) = array_ptr_alloc<a> (w * h) val pix = pixmap_make<a?> (pf | w, h, p) in @(pfgc | pix) end implement {a} pixmap_make_elt (w, h, elt) = let val @(pfgc | pix) = pixmap_make<a> (w, h) in fill<a> (pix, elt); @(pfgc | pix) end implement {} pixmap_free_storage_return pix = case+ pix of | ~ _pixmap record => @(record.pf | record.p) implement {} pixmap_free_storage_free (pfgc | pix) = let val @(pf | p) = pixmap_free pix in array_ptr_free (pf, pfgc | p) end implement {a} pixmap_fill_elt {w, h} {p} (pix, elt) = case+ pix of | @ _pixmap record => let prval () = lemma_g1uint_param (record.w) prval () = lemma_g1uint_param (record.h) prval () = mul_gte_gte_gte {w, h} () stadef n = w * h val n : size_t n = record.w * record.h and p : ptr p = record.p fun loop {i : nat | i <= n} .<n - i>. (pf_lft : array_v (a, p, i), pf_rgt : array_v (a?, p + (i * sizeof a), n - i) | i : size_t i) : @(array_v (a, p, n) | ) = if i = n then let prval () = array_v_unnil pf_rgt in @(pf_lft | ) end else let prval @(pf_elt, pf_rgt) = array_v_uncons pf_rgt val () = ptr_set<a> (pf_elt | ptr_add<a> (p, i), elt) prval pf_lft = array_v_extend (pf_lft, pf_elt) in loop (pf_lft, pf_rgt | succ i) end val @(pf | ) = loop (array_v_nil (), record.pf | i2sz 0) prval () = record.pf := pf prval () = fold@ pix in end implement {a} {tk} pixmap_set_at_guint {w, h} {x, y} (pix, x, y, elt) = case+ pix of | @ _pixmap record => let prval () = lemma_g1uint_param x prval () = lemma_g1uint_param y stadef n = w * h stadef i = x + (y * w) prval () = pixmap_prove_index_bounds {w, h} {x, y} () prval () = prop_verify {0 <= i && i < n} () (* I purposely store the data in an order such that you can write something such as a PPM without looping separately over x and y. Also, even if you did do an outer loop over y and an inner loop over x, you would get the advantage of data locality. *) val i : size_t i = g1u2u x + (g1u2u y * record.w) macdef pixels = !(record.p) val () = pixels[i] := elt prval () = fold@ pix in end implement {a} {tk} pixmap_set_at_gint (pix, x, y, elt) = pixmap_set_at_guint<a><sizeknd> (pix, g1i2u x, g1i2u y, elt) implement {a} {tk} pixmap_get_at_guint {w, h} {x, y} (pix, x, y) = case+ pix of | @ _pixmap record => let prval () = lemma_g1uint_param x prval () = lemma_g1uint_param y stadef n = w * h stadef i = x + (y * w) prval () = pixmap_prove_index_bounds {w, h} {x, y} () prval () = prop_verify {0 <= i && i < n} () val i : size_t i = g1u2u x + (g1u2u y * record.w) macdef pixels = !(record.p) val elt = pixels[i] prval () = fold@ pix in elt end implement {a} {tk} pixmap_get_at_gint (pix, x, y) = pixmap_get_at_guint<a><sizeknd> (pix, g1i2u x, g1i2u y) implement {a} pixmap_dump (outf, pix) = case+ pix of | @ _pixmap record => let macdef pixels = !(record.p) val n = record.w * record.h val success = pixmap$pixels_dump<a> (outf, pixels, n) prval () = fold@ pix in success end implement {a} pixmap_load (inpf, pix, elt) = case+ pix of | @ _pixmap record => let macdef pixels = !(record.p) val n = record.w * record.h val success = pixmap$pixels_load<a> (inpf, pixels, n, elt) prval () = fold@ pix in success end (*------------------------------------------------------------------*) typedef FILEstar = $extype"FILE *" extern castfn FILEref2star : FILEref -<> FILEstar implement pixmap$pixels_dump<rgb24> (outf, pixels, n) = let val num_written = $extfcall (size_t, "fwrite", addr@ pixels, sizeof<rgb24>, n, FILEref2star outf) in num_written = n end implement pixmap$pixels_load<rgb24> (inpf, pixels, n, elt) = let prval [n : int] EQINT () = eqint_make_guint n val num_read = $extfcall (size_t, "fread", addr@ pixels, sizeof<rgb24>, n, FILEref2star inpf) in if num_read = n then let prval () = $UNSAFE.castvwtp2void{@[rgb24][n]} pixels in true end else begin array_initize_elt<rgb24> (pixels, n, elt); false end end (*------------------------------------------------------------------*) assume rgb24 = @(uint8, uint8, uint8) implement {tk} rgb24_make_uint_uint_uint (r, g, b) = let (* The prelude tends to miss implementations for type conversions to uint8, so let us at least implement conversion from uint to uint8. (I do not wish to use a general unsafe cast, because that sort of code has caused me bugs before. C does not always know how to do a type conversion correctly.) The ats2-xprelude package has a much more complete set of implementations (generated en masse by m4 macros), but for this task I am avoiding such dependencies. *) implement g0uint2uint<uintknd,uint8knd> i = let extern castfn g0uint2uint_uint_uint8 : uint -<> uint8 in g0uint2uint_uint_uint8 i end in rgb24_make_tuple @(g0u2u r, g0u2u g, g0u2u b) end implement {tk} rgb24_make_int_int_int (r, g, b) = let (* See the comment in rgb24_make_uint_uint_uint. *) implement g0int2uint<intknd,uint8knd> i = let extern castfn g0int2uint_int_uint8 : int -<> uint8 in g0int2uint_int_uint8 i end in rgb24_make @(g0i2u r, g0i2u g, g0i2u b) end implement {} rgb24_make_tuple tup = tup implement {} rgb24_values rgb = rgb (*------------------------------------------------------------------*) #ifdef BITMAP_TASK_TEST #then %{^ #include <limits.h> %} fn test_sizeof_rgb24 () : void = (* We want to be sure rgb24 takes up exactly 24 bits. Our dump and load implementations depend on that. (If it prove not the case on some platform, one can write, for that unanticipated platform, special implementations of dump and load.) *) let val- true = sizeof<rgb24> = i2sz 3 val- true = sizeof<rgb24> * $extval (size_t, "CHAR_BIT") = i2sz 24 in end fn test_pixel_load_copy_dump () : void = (* Test loading, copying, and dumping of raw 24-bit RGB data from SIPI image "Peppers", 4.2.07.tiff: https://sipi.usc.edu/database/database.php?volume=misc&image=13#top I have the data stored as "4.2.07.raw". *) let val failure_color = rgb24_make (0xFF, 0x00, 0x00) val @(pfgc1 | pix1) = pixmap_make<rgb24> (i2sz 512, i2sz 512) val inpf = fileref_open_exn ("4.2.07.raw", file_mode_r) val success = load<rgb24> (inpf, pix1, failure_color) val () = fileref_close inpf val- true = success val @(pfgc2 | pix2) = pixmap_make<rgb24> (i2sz 512, i2sz 512, failure_color) fun copy_pixels {x, y : nat | x <= 512; y <= 512} .<512 - x, 512 - y>. (pix1 : !pixmap (rgb24, 512, 512), pix2 : !pixmap (rgb24, 512, 512), x : int x, y : int y) : void = if x = 512 then () else if y = 512 then copy_pixels (pix1, pix2, succ x, 0) else begin pix2[x, y] := pix1[x, y]; copy_pixels (pix1, pix2, x, succ y) end val () = copy_pixels (pix1, pix2, 0, 0) val outf = fileref_open_exn ("4.2.07.raw.dumped", file_mode_w) val success = dump<rgb24> (outf, pix2) val () = fileref_close outf val- true = success val status = $extfcall (int, "system", "cmp 4.2.07.raw 4.2.07.raw.dumped") val- true = status = 0 in free (pfgc1 | pix1); free (pfgc2 | pix2) end implement main0 () = begin test_sizeof_rgb24 (); test_pixel_load_copy_dump () end #endif (*------------------------------------------------------------------*)A test can be run if one has a 786432-byte file and names it 4.2.07.raw. I used the raw data from a commonly used 512x512 test image. You can compile and run the test program thus:
$ patscc -std=gnu2x -g -O2 -DATS_MEMALLOC_LIBC -DATS BITMAP_TASK_TEST bitmap_task.sats bitmap_task.dats $ ./a.out
You should end up with a copy of the data in a file named 4.2.07.raw.dumped.
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 } All of the functions specified in the task are built in to Axe. Note that bitmaps are always 96x64 black and white. Thus, since each pixel takes 1 bit, a complete bitmap is 768 bytes.
Two bitmaps can be masked together to create 3- and 4-color grayscale.
Buff(768)→Pic1 Fill(Pic1,768,255) Pxl-Off(45,30,Pic1) .Display the bitmap to demonstrate Copy(Pic1) DispGraph Pause 4500 Disp pxl-Test(50,50,Pic1)▶Dec,i
graphsize 30,30 call fill(rgb(255,0,0)) call setpixel(10,10,rgb(0,255,255)) print "pixel 10,10 is " + pixel(10,10) print "pixel 20,20 is " + pixel(20,10) imgsave "BASIC256_bitmap.png" end subroutine fill(c) color c rect 0,0,graphwidth, graphheight end subroutine subroutine setpixel(x,y,c) color c plot x,y end subroutine- Output:
pixel 10,10 is 4278255615 pixel 20,20 is 4294901760
BBC BASIC expects a bitmap always to be associated with a window; for simplicity this code uses the main output window.
Width% = 200 Height% = 200 REM Set window size: VDU 23,22,Width%;Height%;8,16,16,128 REM Fill with an RGB colour: PROCfill(100,150,200) REM Set a pixel: PROCsetpixel(100,100,255,255,0) REM Get a pixel: rgb% = FNgetpixel(100,100) PRINT RIGHT$("00000" + STR$~rgb%, 6) END DEF PROCfill(r%,g%,b%) COLOUR 1,r%,g%,b% GCOL 1+128 CLG ENDPROC DEF PROCsetpixel(x%,y%,r%,g%,b%) COLOUR 1,r%,g%,b% GCOL 1 LINE x%*2,y%*2,x%*2,y%*2 ENDPROC DEF FNgetpixel(x%,y%) LOCAL col% col% = TINT(x%*2,y%*2) SWAP ?^col%,?(^col%+2) = col% Working excerpt from imglib.h usable as "interface" (some includes are needed for other functions of the same category). This code uses functions from category Raster graphics operations. One must create files imglib.h and imglib.c using code from these pages. Start from bitmap page
#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); } 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; } } #include <iostream> #include <boost/gil/gil_all.hpp> int main() { using namespace boost::gil; // create 30x40 image rgb8_image_t img(30, 40); // fill with red rgb8_pixel_t red(255, 0, 0); fill_pixels(view(img), red); // set pixel at 10x20 to blue rgb8_pixel_t blue(0, 0, 255); view(img)(10, 20) = blue; // read the value of pixel at 11x20 rgb8_pixel_t px = const_view(img)(11, 20); std::cout << "the pixel at 11, 20 is " << (unsigned)px[0] << ':' << (unsigned)px[1] << ':' << (unsigned)px[2] << '\n'; } See also Basic bitmap storage/C++
(import '[java.awt Color Graphics Image] '[java.awt.image BufferedImage]) (defn blank-bitmap [width height] (BufferedImage. width height BufferedImage/TYPE_3BYTE_BGR)) (defn fill [image color] (doto (.getGraphics image) (.setColor color) (.fillRect 0 0 (.getWidth image) (.getHeight image)))) (defn set-pixel [image x y color] (.setRGB image x y (.getRGB color))) (defn get-pixel [image x y] (Color. (.getRGB image x y))) (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+) class RGBColor getter red, green, blue def initialize(@red = 0_u8, @green = 0_u8, @blue = 0_u8) end RED = new(red: 255_u8) GREEN = new(green: 255_u8) BLUE = new(blue: 255_u8) BLACK = new WHITE = new(255_u8, 255_u8, 255_u8) end class Pixmap getter width, height @data : Array(Array(RGBColor)) def initialize(@width : Int32, @height : Int32) @data = Array.new(@width) { Array.new(@height, RGBColor::WHITE) } end def fill(color) @data.each &.fill(color) end def [](x, y) @data[x][y] end def []=(x, y, color) @data[x][y] = color end end bmap = Pixmap.new(5, 5) pp bmap This code is a little complex because many Tasks use this module for various purposes.
module bitmap; import std.stdio, std.array, std.exception, std.string, std.conv, std.algorithm, std.ascii; final class Image(T) { static if (is(typeof({ auto x = T.black; }))) const static T black = T.black; else const static T black = T.init; static if (is(typeof({ auto x = T.white; }))) const static T white = T.white; T[] image; private size_t nx_, ny_; this(in int nxx=0, in int nyy=0, in bool inizialize=true) pure nothrow { allocate(nxx, nyy, inizialize); } void allocate(in int nxx=0, in int nyy=0, in bool inizialize=true) pure nothrow @safe in { assert(nxx >= 0 && nyy >= 0); } body { this.nx_ = nxx; this.ny_ = nyy; if (nxx * nyy > 0) { if (inizialize) image.length = nxx * nyy; else // Optimization. image = minimallyInitializedArray!(typeof(image)) (nxx * nyy); } } @property Image dup() const pure nothrow @safe { auto result = new Image(); result.image = this.image.dup; result.nx_ = this.nx; result.ny_ = this.ny; return result; } static Image fromData(T[] data, in size_t nxx=0, in size_t nyy=0) pure nothrow @safe in { assert(nxx >= 0 && nyy >= 0 && data.length == nxx * nyy); } body { auto result = new Image(); result.image = data; result.nx_ = nxx; result.ny_ = nyy; return result; } @property size_t nx() const pure nothrow @safe @nogc { return nx_; } @property size_t ny() const pure nothrow @safe @nogc { return ny_; } ref T opIndex(in size_t x, in size_t y) pure nothrow @safe @nogc in { assert(x < nx_ && y < ny_); //assert(x < nx_, format("opIndex, x=%d, nx=%d", x, nx)); //assert(y < ny_, format("opIndex, y=%d, ny=%d", y, ny)); } body { return image[x + y * nx_]; } T opIndex(in size_t x, in size_t y) const pure nothrow @safe @nogc in { assert(x < nx_ && y < ny_); //assert(x < nx_, format("opIndex, x=%d, nx=%d", x, nx)); //assert(y < ny_, format("opIndex, y=%d, ny=%d", y, ny)); } body { return image[x + y * nx_]; } T opIndexAssign(in T color, in size_t x, in size_t y) pure nothrow @safe @nogc in { assert(x < nx_ && y < ny_); //assert(x < nx_, format("opIndex, x=%d, nx=%d", x, nx)); //assert(y < ny_, format("opIndex, y=%d, ny=%d", y, ny)); } body { return image[x + y * nx_] = color; } void opIndexUnary(string op)(in size_t x, in size_t y) pure nothrow @safe @nogc if (op == "++" || op == "--") in { assert(x < nx_ && y < ny_); } body { mixin("image[x + y * nx_] " ~ op ~ ";"); } void clear(in T color=this.black) pure nothrow @safe @nogc { image[] = color; } /// Convert a 2D array of chars to a binary Image. static Image fromText(in string txt, in char one='#', in char zero='.') pure { auto M = txt .strip .split .map!(row => row .filter!(c => c == one || c == zero) .map!(c => T(c == one)) .array) .array; assert(M.join.length > 0); // Not empty. foreach (row; M) assert(row.length == M[0].length); // Rectangular return Image.fromData(M.join, M[0].length, M.length); } /// The axis origin is at the top left. void textualShow(in char bl='#', in char wh='.') const nothrow { size_t i = 0; foreach (immutable y; 0 .. ny_) { foreach (immutable x; 0 .. nx_) putchar(image[i++] == black ? bl : wh); putchar('\n'); } } } struct RGB { ubyte r, g, b; static immutable black = typeof(this)(); static immutable white = typeof(this)(255, 255, 255); } Image!RGB loadPPM6(ref Image!RGB img, in string fileName) { if (img is null) img = new Image!RGB; auto f = File(fileName, "rb"); enforce(f.readln.strip == "P6"); string line; do { line = f.readln(); } while (line.length && line[0] == '#'); // Skip comments. const size = line.split; enforce(size.length == 2); img.allocate(size[0].to!uint, size[1].to!uint); enforce(f.readln().strip() == "255"); auto l = new ubyte[img.nx * 3]; size_t i = 0; foreach (immutable y; 0 .. img.ny) { f.rawRead!ubyte(l); foreach (immutable x; 0 .. img.nx) img.image[i++] = RGB(l[x * 3], l[x * 3 + 1], l[x * 3 + 2]); } return img; } void savePPM6(in Image!RGB img, in string fileName) in { assert(img !is null); assert(img.nx > 0 && img.nx > 0); } body { auto f = File(fileName, "wb"); f.writefln("P6\n%d %d\n255", img.nx, img.ny); size_t i = 0; foreach (immutable y; 0 .. img.ny) foreach (immutable x; 0 .. img.nx) { immutable p = img.image[i++]; f.write(cast(char)p.r, cast(char)p.g, cast(char)p.b); } } version (bitmap_main) { void main() { auto img = new Image!RGB(30, 10); img[4, 5] = RGB.white; img.textualShow; } } Compiling it with version=bitmap_main prints:
- Output:
############################## ############################## ############################## ############################## ############################## ####.######################### ############################## ############################## ############################## ##############################
program BitmapTest; {$APPTYPE CONSOLE} type TColor = record private function GetColor: Cardinal; procedure SetColor(const Value: Cardinal); public Red, Green, Blue, Alpha: Byte; property Color: Cardinal read GetColor write SetColor; end; TBitmap = class private FPixels: array of array of TColor; FHeight: Integer; FWidth: Integer; function GetPixel(X, Y: integer): TColor; public procedure Fill(aColor: TColor); overload; procedure Fill(aColor: Cardinal); overload; procedure SetSize(w, h: Integer); constructor Create(); overload; constructor Create(w, h: Integer); overload; property Height: Integer read FHeight; property Width: Integer read FWidth; property Pixel[X, Y: integer]: TColor read GetPixel; end; { TColor } function TColor.GetColor: Cardinal; begin Result := (alpha shl 24) + (red shl 16) + (green shl 8) + blue; end; procedure TColor.SetColor(const Value: Cardinal); begin blue := (Value and $FF); green := ((Value shr 8) and $FF); red := ((Value shr 16) and $FF); alpha := ((Value shr 24) and $FF); end; { TBitmap } constructor TBitmap.Create; begin inherited; FHeight := 0; FWidth := 0; end; constructor TBitmap.Create(w, h: Integer); begin Create; SetSize(w, h); end; procedure TBitmap.Fill(aColor: Cardinal); var x, y: Integer; begin if (Width > 0) and (Height > 0) then for x := 0 to width - 1 do for y := 0 to height - 1 do FPixels[x, y].Color := aColor; end; procedure TBitmap.Fill(aColor: TColor); begin Fill(aColor.Color); end; function TBitmap.GetPixel(X, Y: integer): TColor; begin Result := FPixels[X, Y]; end; procedure TBitmap.SetSize(w, h: Integer); var i: Integer; begin if (h = 0) or (w = 0) then begin h := 0; w := 0; end; FHeight := h; FWidth := w; SetLength(FPixels, w); if w > 0 then for i := 0 to w - 1 do SetLength(FPixels[i], h); end; var bmp: TBitmap; x, y: Integer; begin bmp := TBitmap.Create(200, 200); bmp.Fill($00FF0000); for y := 0 to bmp.Height - 1 do for x := 0 to bmp.Width - 1 do begin if x mod 2 = 1 then bmp.Pixel[x, y].Color := $0000FF; end; bmp.Free; end.
This is a pure Delphi example using standard Delphi controls and libraries that already have raster and bitmap objects and operations built in.
Bascially, Delphi has a powerful set of tools for manipulating graphic objects. All graphic objects including Screens, Printers, Windows or Bitmaps, have a property called a "Canvas." As a consequence, the same code can draw on the Screen, the Printer, a Window or a Bitmap. A Canvas has powerful function that allow you to draw pixels, lines, rectangles, circles, elispes, polygons and text on any graphic object. The code below demonstrates many of the function available in a canvas.

procedure ShowBitmapFunctions(Image: TImage); {Code to demonstrate some of the main features the Delphi "TCanvas" object} var I,X,Y: integer; var C: TColor; begin {Draw red rectangle with 3 pixels wide lines} Image.Canvas.Pen.Color:=clRed; Image.Canvas.Pen.Width:=3; Image.Canvas.Rectangle(50,50,500,300); {Flood fill rectangle blue} Image.Canvas.Brush.Color:=clBlue; Image.Canvas.FloodFill(55,55,clRed,fsBorder); {Draw random dots on the screen} for I:=1 to 1000 do begin X:=trunc((Random * 450) + 50); Y:=trunc((Random * 250) + 50); C:=RGB(Random(255),Random(255),Random(255)); {draw 9 pixels for each point to make dots more visible} Image.Canvas.Pixels[X-1,Y-1]:=C; Image.Canvas.Pixels[X ,Y-1]:=C; Image.Canvas.Pixels[X+1,Y-1]:=C; Image.Canvas.Pixels[X-1,Y ]:=C; Image.Canvas.Pixels[X ,Y ]:=C; Image.Canvas.Pixels[X+1,Y ]:=C; Image.Canvas.Pixels[X-1,Y+1]:=C; Image.Canvas.Pixels[X ,Y+1]:=C; Image.Canvas.Pixels[X+1,Y+1]:=C; end; {Draw lime-green line from corner to cornder} Image.Canvas.Pen.Color:=clLime; Image.Canvas.MoveTo(50,50); Image.Canvas.LineTo(500,300); {Sample pixel color at 51,51} C:=Image.Canvas.Pixels[51,51]; {Display the color value } Image.Canvas.Brush.Color:=clAqua; Image.Canvas.Font.Size:=25; Image.Canvas.Font.Color:=clRed; Image.Canvas.TextOut(5,5,IntToHex(C,8)); {Tell Delphi to update the Window} Image.Repaint; end; - Output:
Elapsed Time: 39.038 ms.
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>))(lib 'plot) (define width 600) (define height 400) (plot-size width height) ;; set image size (define (blue x y) (rgb 0.0 0.0 1.0)) ;; a constant function (plot-rgb blue 1 1) ;; blue everywhere (lib 'types) ;; uint32 and uint8 vector types ;; bit-map pixel access (define bitmap (pixels->uint32-vector)) ;; screen to vector of int32 → 240000 (define (pix-at x y) (vector-ref bitmap (+ x (* y width)))) (rgb->list (pix-at 100 200)) → (0 0 255 255) ;; rgb blue ;; writing to bitmap (define (set-color-xy x y col) (vector-set! bitmap (+ x (* y width)) col)) (for* ((x 100)(y 200)) (set-color-xy x y (rgb 1 1 0))) ;; to bitmap (vector->pixels bitmap) ;; bitmap to screen ;; bit-map color components (r g b a) = index (0 1 2 3) access (define bitmap (pixels->uint8-clamped-vector)) ;; screen to vector of uint8 (vector-length bitmap) → 960000 (define (blue-at-xy x y) (vector-ref bitmap (+ x 3 (* y width)))) ;; 3 = blue component (blue-at-xy 100 200) → 255 Translation of the erlang version of the code.
defmodule RosBitmap do defrecord Bitmap, pixels: nil, shape: {0, 0} defp new(width, height, {:rgb, r, g, b}) do Bitmap[ pixels: :array.new(width * height, {:default, <<r::size(8), g::size(8), b::size(8)>>}), shape: {width, height}] end def new(width, height), do: new(width, height, {:rgb, 0, 0, 0}) def fill(Bitmap[shape: {width, height}], {:rgb, _r, _g, _b}=color) do new(width, height, color) end def set_pixel(Bitmap[pixels: pixels, shape: {width, _height}]=bitmap, {:at, x, y}, {:rgb, r, g, b}) do index = x + y * width bitmap.pixels(:array.set(index, <<r::size(8), g::size(8), b::size(8)>>, pixels)) end def get_pixel(Bitmap[pixels: pixels, shape: {width, _height}], {:at, x, y}) do index = x + y * width <<r::size(8), g::size(8), b::size(8)>> = :array.get(index, pixels) {:rgb, r, g, b} end end Stores pixels as a 1d array and colors as binaries.
-module(ros_bitmap). -export([new/2, fill/2, set_pixel/3, get_pixel/2]). -record(bitmap, { pixels = nil, shape = {0, 0} }). new(Width, Height) -> #bitmap{pixels=array:new(Width * Height, {default, <<0:8, 0:8, 0:8>>}), shape={Width, Height}}. fill(#bitmap{shape={Width, Height}}, {rgb, R, G, B}) -> #bitmap{ pixels=array:new(Width * Height, {default, <<R:8, G:8, B:8>>}), shape={Width, Height}}. set_pixel(#bitmap{pixels=Pixels, shape={Width, _Height}}=Bitmap, {at, X, Y}, {rgb, R, G, B}) -> Index = X + Y * Width, Bitmap#bitmap{pixels=array:set(Index, <<R:8, G:8, B:8>>, Pixels)}. get_pixel(#bitmap{pixels=Pixels, shape={Width, _Height}}, {at, X, Y}) -> Index = X + Y * Width, <<R:8, G:8, B:8>> = array:get(Index, Pixels), {rgb, R, G, B}. -- Some color constants: constant black = #000000, white = #FFFFFF, red = #FF0000, green = #00FF00, blue = #0000FF -- Create new image filled with some color function new_image(integer width, integer height, atom fill_color) return repeat(repeat(fill_color,height),width) end function -- Usage example: sequence image image = new_image(800,600,black) -- Set pixel color: image[400][300] = red -- Get pixel color atom color color = image[400][300] -- Now color is #FF0000?color -- Should print out 16711680
FSharp can accomplish this task in several ways. This version is purely functional. The bitmap data structure does not mutate. Set pixel, for example, simply transforms the input bitmap into a new bitmap with that pixel set to the input color. If you have Framework 4.5, you can use ImmutableArray to force this immutability.
Solution:
//pure functional version ... changing a pixel color provides a new Bitmap type Color = {red: byte; green: byte; blue: byte} type Point = {x:uint32; y:uint32} type Bitmap = {color: Color array; maxX: uint32; maxY: uint32} let colorBlack = {red = (byte) 0; green = (byte) 0; blue = (byte) 0} let emptyBitmap = {color = Array.empty; maxX = (uint32) 0; maxY = (uint32) 0} let bitmap (width: uint32) (height: uint32) = match width, height with | 0u,0u | 0u,_ | _, 0u -> emptyBitmap | _,_ -> {color = Array.create ((int) (width * height)) colorBlack; maxX = width; maxY = height} let getPixel point bitmap = match bitmap.color with | c when c |> Array.isEmpty -> None | c when (uint32) c.Length <= (point.y * bitmap.maxY + point.x) -> None | c -> Some c.[(int) (point.y * bitmap.maxY + point.x)] let setPixel point color bitmap = {bitmap with color = bitmap.color |> Array.mapi (function | i when i = (int) (point.y * bitmap.maxY + point.x) -> (fun _ -> color) | _ -> id)} let fill color bitmap = {bitmap with color = bitmap.color |> Array.map (fun _ ->color)} Tests:
//setups //==check pixel for color function let check bitmap color (x,y) = match (getPixel {x=x;y=y} bitmap) with | Some(v) -> v = color | _ -> false let allPixels i j = [for x in [0u..(i-1u)] do for y in [0u..(j-1u)] -> (x,y)] //create new empty bitmap let myBitmap = bitmap 0u 0u printfn "Is empty: %b" (myBitmap = emptyBitmap) let myBitmap2 = bitmap 1u 0u printfn "Is empty: %b" (myBitmap2 = emptyBitmap) let myBitmap3 = bitmap 0u 1u printfn "Is empty: %b" (myBitmap3 = emptyBitmap) //create normal bitmap let myBitmap4 = bitmap 14u 14u printfn "Is not empty: %b" (not (myBitmap4 = emptyBitmap)) //just check one color printfn "Is 1,1 black: %b" (check myBitmap4 colorBlack (1u,1u)) //check out of range color printfn "Is 100,100 nothing: %b" (not(check myBitmap4 colorBlack (100u,100u))) //make sure all pixels are black printfn "Is all black: %b" ((allPixels 14u 14u) |> List.forall (check myBitmap4 colorBlack)) //fill bitmap color let colorWhite = {red = (byte) 255; green = (byte) 255; blue = (byte) 255} let myBitmap5 = myBitmap4 |> fill colorWhite printfn "Is all white: %b" ((allPixels 14u 14u) |> List.forall (check myBitmap5 colorWhite)) //change just one pixel let myBitmap6 = myBitmap5 |> setPixel {x=5u;y=10u} colorBlack printfn "Is 5,10 black: %b" (check myBitmap4 colorBlack (5u,10u)) - Output:
Is empty
Is empty: true
Is empty: true
Is not empty: true
Is 1,1 black: true
Is 100,100 nothing: true
Is all black: true
Is all white: true
Is 5,10 black: true Usage:
bitmap 14u 14u |> fill {red = (byte) 200; green = (byte) 0; blue = (byte) 10} |> setPixel {x=5u;y=10u} {red = (byte) 0; green = (byte) 0; blue = (byte) 0} |> getPixel {x=5u;y=10u} |> printfn "%A" - Output:
Some {red = 0uy;
green = 0uy; blue = 0uy;}
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 Volatility in FBSL is a feature uncommon to most other languages. It is the ability of its intrinsic functions as well as its user-defined functions, DynAsm and DynC blocks, and functions imported from 3rd-party DLL's to preserve their return values between function calls in FBSL Variants that have the same names as their respective functions but use neither the parentheses nor the arguments. These Variants belong to the global namespace and can be used throughout the entire script until another fully qualified function call to their respective functions is made, whereby they change their values accordingly. The feature minimizes the need for temporary variables and assignments.
This feature is a logical extension of VisualBasic way to formalize its function return value by assigning it to a Variant of the same name as that of the respective function. However, the VB Variant is only effective within the scope of its own function.
Using pure FBSL's built-in graphics functions:
#DEFINE WM_LBUTTONDOWN 513 #DEFINE WM_RBUTTONDOWN 516 #DEFINE WM_CLOSE 16 FBSLSETFORMCOLOR(ME, RGB(0, 255, 255)) ' Cyan: set persistent background color DRAWWIDTH(5) ' Adjust point size FBSL.GETDC(ME) ' Use volatile FBSL.GETDC below to avoid extra assignments RESIZE(ME, 0, 0, 300, 200) CENTER(ME) SHOW(ME) BEGIN EVENTS SELECT CASE CBMSG CASE WM_LBUTTONDOWN ' Set color at current coords as hex literal PSET(FBSL.GETDC, LOWORD(CBLPARAM), HIWORD(CBLPARAM), &H0000FF) ' Red: Windows stores colors in BGR order CASE WM_RBUTTONDOWN ' Get color at current coords as hex literal FBSLSETTEXT(ME, "&H" & HEX(POINT(FBSL.GETDC, LOWORD(CBLPARAM), HIWORD(CBLPARAM)))) CASE WM_CLOSE ' Clean up FBSL.RELEASEDC(ME, FBSL.GETDC) END SELECT END EVENTS - Output:
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 See Basic bitmap storage/Fortran
Screenres 320, 240, 8 Dim Shared As Integer w, h Screeninfo w, h Const As Ubyte cyan = 3 Const As Ubyte red = 4 Sub rellenar(c As Integer) Line (0,0) - (w/3, h/3), red, BF End Sub Sub establecePixel(x As Integer, y As Integer, c As Integer) Pset (x,y), cyan End Sub rellenar(12) establecePixel(10,10, cyan) Locate 12 Print "pixel 10,10 es " & Point(10,10) Print "pixel 20,20 es " & Point(20,10) Bsave "FreeBASIC_bitmap.bmp", 0 Sleep include "NSLog.incl" /* This task creates an image with a background filled with red pixels. Then sets one pixel to blue in the center of the image. Then gets the RGB color values at that pixel position. Then saves the image as a jpg to the desktop. */ _Window = 1 _Horz = 300 _Vert = 100 _X = 150 _Y = 50 window _Window, @"Bitmap window with blue dot",(0,0,_Horz, _Vert) WindowSetBackgroundColor(_Window,fn colorwhite) local fn DrawImage as ImageRef ImageRef image = fn ImageWithSize( fn CGSizeMake(_Horz,_Vert ) ) // create blank image ImageLockFocus( image ) // lock image during drawing CFIndex i for i = 0 to _Horz // fill all horizontal pixels with red dots BezierPathStrokeLine( fn CGPointMake( i, 0 ), fn CGPointMake( i, _Vert ), 1, fn Colorred ) next BezierPathStrokeRect( fn CGRectMake( _X,_Y,1,1), 1.0, fn ColorBlue) // Draw a blue dot in the center. ImageUnlockFocus( image ) // unlock image afer drawing end fn = image // Draw the image ImageRef theImage theImage = fn DrawImage // Display the image imageview 1,, theImage, (0,0,_Horz, _Vert) // Get the color of the pixel at horizontal position X and vertical position Y colorref color color = fn ViewColorAtXY( _Window, _X, _Y ) NSLog( @"RGB Color values at pixel position X,Y are %@", color) // Save the image as a jpg CFURLRef DesktopDirectory,url DesktopDirectory = fn FileManagerURLForDirectory( NSDesktopDirectory, NSUserDomainMask ) url = fn URLByAppendingPathComponent( DesktopDirectory, @"Bitmap Image.jpg" ) bool err err = fn ImageWriteToURL( theImage, url, NSBitmapImageFileTypeJPEG, _true ) // save image as jpg handleevents- Output:
RGB Color values at pixel position X,Y are NSCalibratedRGBColorSpace 0 0 0.960784 1
Standard library
Go's standard library include image, color, and drawing packages and the source for them is easy to read. There is also a Go Blog article on the image package The image.NRGBA type supports everything this task requires (the 'A' is for alpha channel, each are 8 bits, if 16 bits each of RGBA is desired there is also the image.NRGBA64 type). The 'N' of NRGBA stands for Non-alpha-premultiplied, color values can trivially be converted to/from alpha-premultiplied RGBA values via a color.Model.
Here's how to use the standard packages to do what this task requires:
package main import ( "bytes" "fmt" "image" "image/color" "image/draw" "image/png" ) func main() { // A rectangle from 0,0 to 300,240. r := image.Rect(0, 0, 300, 240) // Create an image im := image.NewNRGBA(r) // set some color variables for convience var ( red = color.RGBA{0xff, 0x00, 0x00, 0xff} blue = color.RGBA{0x00, 0x00, 0xff, 0xff} ) // Fill with a uniform color draw.Draw(im, r, &image.Uniform{red}, image.ZP, draw.Src) // Set individual pixels im.Set(10, 20, blue) im.Set(20, 30, color.Black) im.Set(30, 40, color.RGBA{0x10, 0x20, 0x30, 0xff}) // Get the values of specific pixels as color.Color types. // The color will be in the color.Model of the image (in this // case color.NRGBA) but color models can convert their values // to other models. c1 := im.At(0, 0) c2 := im.At(10, 20) // or directly as RGB components (scaled values) redc, greenc, bluec, _ := c1.RGBA() redc, greenc, bluec, _ = im.At(30, 40).RGBA() // Images can be read and writen in various formats var buf bytes.Buffer err := png.Encode(&buf, im) if err != nil { fmt.Println(err) } fmt.Println("Image size:", im.Bounds().Dx(), "×", im.Bounds().Dy()) fmt.Println(buf.Len(), "bytes when encoded as PNG.") fmt.Printf("Pixel at %7v is %v\n", image.Pt(0, 0), c1) fmt.Printf("Pixel at %7v is %#v\n", image.Pt(10, 20), c2) // %#v shows type details fmt.Printf("Pixel at %7v has R=%d, G=%d, B=%d\n", image.Pt(30, 40), redc, greenc, bluec) } - Output:
Image size: 300 × 240 786 bytes when encoded as PNG. Pixel at (0,0) is {255 0 0 255} Pixel at (10,20) is color.NRGBA{R:0x0, G:0x0, B:0xff, A:0xff} Pixel at (30,40) has R=4112, G=8224, B=12336 DIY
Not a complete working program. Presented here are just types and functions requested by the task.
// Raster package used with a number of RC tasks. // // For each task, documentation in package main source will list this // file and others that are necessary to build a raster package with // sufficient functionality for the task. To build a working program, // build a raster package from the files listed, install the package, // and then compile and link the package main that completes the task. // // Alternatively, files in the raster package can be combined as desired // to build a package that meets the needs of multiple tasks. package raster // Rgb is a 24 bit color value represented with a 32 bit int // in the conventional way. This is expected to be convenient // for the programmer in many cases. type Rgb int32 // Pixel has r, g, and b as separate fields. This is used as // the in-memory representation of a bitmap. type Pixel struct { R, G, B byte } // Pixel returns a new Pixel from a Rgb value func (c Rgb) Pixel() Pixel { return Pixel{R: byte(c >> 16), G: byte(c >> 8), B: byte(c)} } // Rgb returns a single Rgb value computed from rgb fields of a Pixel // of a Pixel. func (p Pixel) Rgb() Rgb { return Rgb(p.R)<<16 | Rgb(p.G)<<8 | Rgb(p.B) } // Bitmap is the in-memory representation, or image storage type of a bitmap. // Zero value for type is a valid zero-size bitmap. // The only exported field is Comments. Remaining fields have interdepencies // that are managed by package code and so should not be directly accessed // from outside the package. type Bitmap struct { Comments []string rows, cols int px []Pixel // all pixels as a single slice, row major order pxRow [][]Pixel // rows of pixels as slices of px } const creator = "# Creator: Rosetta Code http://rosettacode.org/" // New is a Bitmap "constructor." Parameters x and y are extents. // That is, the new bitmap will have x columns and y rows. func NewBitmap(x, y int) (b *Bitmap) { b = &Bitmap{ Comments: []string{creator}, rows: y, // named fields here to prevent possible mix-ups. cols: x, px: make([]Pixel, x*y), pxRow: make([][]Pixel, y), } // Note rows of pixels are not allocated separately. // Rather the whole bitmap is allocted in one chunk as px. // This simplifies allocation and maintains locality. x0, x1 := 0, x for i := range b.pxRow { b.pxRow[i] = b.px[x0:x1] // slice operation. does no allocation. x0, x1 = x1, x1+x } return b } // Extent returns bitmap dimensions. func (b *Bitmap) Extent() (cols, rows int) { return b.cols, b.rows } // Fill entire bitmap with solid color. func (b *Bitmap) Fill(p Pixel) { for i := range b.px { b.px[i] = p } } func (b *Bitmap) FillRgb(c Rgb) { b.Fill(c.Pixel()) } // Set a single pixel color value. // Clips to bitmap boundaries. // Returns true if pixel was set, false if clipped. func (b *Bitmap) SetPx(x, y int, p Pixel) bool { defer func() { recover() }() b.pxRow[y][x] = p return true } func (b *Bitmap) SetPxRgb(x, y int, c Rgb) bool { return b.SetPx(x, y, c.Pixel()) } // Note: Clipping to bitmap boundaries is needed for program correctness // but is otherwise not required by the task. It is implemented with the // combination of pxRow and the deferred recover. SetPx, GetPx return the // clipping result as a way for higher level graphics functions to track // plotting and clipping status. As this is not required by tasks though, // it is generally not implemented. // Get a single pixel color value. // Returns pixel and ok=true if coordinates are within bitmap boundaries. // Returns ok=false if coordinates are outside bitmap boundaries. func (b *Bitmap) GetPx(x, y int) (p Pixel, ok bool) { defer func() { recover() }() return b.pxRow[y][x], true } func (b *Bitmap) GetPxRgb(x, y int) (Rgb, bool) { p, ok := b.GetPx(x, y) if !ok { return 0, false } return p.Rgb(), true } 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) The language has a built-in window data type with associated graphics primitives. A bitmap is just a window that isn't visible on-screen at the moment.
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. (We could instead have encoded RGB in a single integer...)
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=: 127 makeRGB 5 8 NB. create a gray 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 Note that height comes before width here. This is inconsistent with marketing of display resolutions, but matches J's treatment of dimensions.
Solution
import java.awt.Color; import java.awt.Graphics; import java.awt.Image; import java.awt.image.BufferedImage; public class BasicBitmapStorage { private final BufferedImage image; public BasicBitmapStorage(int width, int height) { image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); } 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
import static org.junit.Assert.assertEquals; import java.awt.Color; import org.junit.Test; public class BasicBitmapStorageTest { @Test public void testHappy() { int width = 640; int height = 480; BasicBitmapStorage bbs = new BasicBitmapStorage(width, height); 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); } } JavaScript can interact with a drawing context using the HTML5 Canvas API.
// Set up the canvas var canvas = document.createElement("canvas"), ctx = canvas.getContext("2d"), width = 400, height = 400; ctx.canvas.width = width; ctx.canvas.height = height; // Optionaly add it to the current page document.body.appendChild(canvas); // Draw an image var img = document.createElement("img"); img.onload = function(){ // Draw the element into the top-left of the canvas ctx.drawImage(img, 0, 0); }; img.src = "//placehold.it/400x400"; // Fill the canvas with a solid blue color ctx.fillStyle = "blue"; ctx.fillRect(0, 0, width, height); // Place a black pixel in the middle // Note that a pixel is a 1 by 1 rectangle // This is the fastest method as of 2012 benchmarks ctx.fillStyle = "black"; ctx.fillRect(width / 2, height / 2, 1, 1); Using packages (Images.jl, Colors.jl):
using Images, Colors Base.hex(p::RGB{T}) where T = join(hex(c(p), 2) for c in (red, green, blue)) function showhex(m::Matrix{RGB{T}}, pad::Integer=4) where T for r in 1:size(m, 1) println(" " ^ pad, join(hex.(m[r, :]), " ")) end end w, h = 5, 7 cback = RGB(1, 0, 1) cfore = RGB(0, 1, 0) img = Array{RGB{N0f8}}(h, w); println("Uninitialized image:") showhex(img) fill!(img, cback) println("\nImage filled with background color:") showhex(img) img[2, 3] = cfore println("\nImage with a pixel set for foreground color:") showhex(img) - Output:
Uninitialized image: 10DFF8 7F0000 F84A00 0030DA 007F00 4A007F B0DDF8 7F0000 F84A00 00D0DB 0000F0 4A007F D0D9F8 7F0000 F84A00 DFF84A 000050 4A007F 50DAF8 7F0000 007F00 D9F84A 000010 4A007F 30DCF8 0050E0 007F00 DAF84A 000050 4A007F F84A00 00B0D9 007F00 DBF84A 000050 Image filled with background color: FF00FF FF00FF FF00FF FF00FF FF00FF FF00FF FF00FF FF00FF FF00FF FF00FF FF00FF FF00FF FF00FF FF00FF FF00FF FF00FF FF00FF FF00FF FF00FF FF00FF FF00FF FF00FF FF00FF FF00FF FF00FF FF00FF FF00FF FF00FF FF00FF FF00FF FF00FF FF00FF FF00FF FF00FF FF00FF Image with a pixel set for foreground color: FF00FF FF00FF FF00FF FF00FF FF00FF FF00FF FF00FF 00FF00 FF00FF FF00FF FF00FF FF00FF FF00FF FF00FF FF00FF FF00FF FF00FF FF00FF FF00FF FF00FF FF00FF FF00FF FF00FF FF00FF FF00FF FF00FF FF00FF FF00FF FF00FF FF00FF FF00FF FF00FF FF00FF FF00FF FF00FF
function main() { Var:Number shape; Image:New(50, 50, shape) Draw:RectFill(0, 0, 50, 50, 0xFF0000, shape) //one to fill an image with a plain RED color Draw:Pixel(30, 30, 0x0000FF, shape) //set a given pixel at (30,30) with a BLUE color while (B1 == false) { Image:Blit(10, 10, shape, screen) Screen:Render() } }// version 1.1.4-3 import java.awt.Color import java.awt.Graphics import java.awt.image.BufferedImage class BasicBitmapStorage(width: Int, height: Int) { val image = BufferedImage(width, height, BufferedImage.TYPE_3BYTE_BGR) fun fill(c: Color) { val g = image.graphics g.color = c g.fillRect(0, 0, image.width, image.height) } fun setPixel(x: Int, y: Int, c: Color) = image.setRGB(x, y, c.getRGB()) fun getPixel(x: Int, y: Int) = Color(image.getRGB(x, y)) } fun main(args: Array<String>) { val width = 640 val height = 480 val bbs = BasicBitmapStorage(width, height) with (bbs) { fill(Color.cyan) setPixel(width / 2, height / 2, Color.black) val c1 = getPixel(width / 2, height / 2) val c2 = getPixel(20, 20) print("The color of the pixel at (${width / 2}, ${height / 2}) is ") println(if (c1 == Color.black) "black" else "unknown") print("The color of the pixel at (120, 120) is ") println(if (c2 == Color.cyan) "cyan" else "unknown") } } - Output:
The color of the pixel at (320, 240) is black The color of the pixel at (120, 120) is cyan
-- Creates a new image object of size 640x480 pixel and 32-bit color depth img = image(640, 480, 32) -- Fills image with plain red img.fill(img.rect, rgb(255,0,0)) -- Gets the color value of the pixel at point (320, 240) col = img.getPixel(320, 240) -- Changes the color of the pixel at point (320, 240) to black img.setPixel(320, 240, rgb(0,0,0))LiveCode has built in support for importing and exporting PBM, JPEG, GIF, BMP or PNG graphics formats
-- create an image container box at the center of the current stack window with default properties create image "test" -- programtically choose the paint bucket tool choose bucket tool -- LiveCode engine has built-in color keywords: set the brushColor to "dark green" -- programtically mouse click at the center of image container box to fill click at the loc of image "test" -- get the RGBA values of the first pixel in the image box put byteToNum(byte 1 of the imageData of image "test") into tRed put byteToNum(byte 2 of the imageData of image "test") into tGreen put byteToNum(byte 3 of the imageData of image "test") into tBlue put byteToNum(byte 4 of the imageData of image "test") into tAlpha -- log message the info in the message box put "First Pixel Color is Red:"& tRed &" Green:"& tGreen &" Blue:"& tBlue &" Transparency:"& tAlpha -- just for fun replace the contents with RosettaCode logo wait 2 seconds set the filename of image "test" to "http://rosettacode.org/mw/title.png" -- the next line is copy of the Write a PPM task: export image "test" to file "~/Test.PPM" as paint -- paint format is one of PBM, PGM, or PPMOriginal
function Allocate_Bitmap( width, height ) local bitmap = {} for i = 1, width do bitmap[i] = {} for j = 1, height do bitmap[i][j] = {} end end return bitmap end function Fill_Bitmap( bitmap, color ) for i = 1, #bitmap do for j = 1, #bitmap[1] do bitmap[i][j] = color end end end function Get_Pixel( bitmap, x, y ) return bitmap[x][y] end This can be used like:
bitmap = Allocate_Bitmap( 100, 50 ) Fill_Bitmap( bitmap, { 15, 200, 80 } ) pixel = Get_Pixel( bitmap, 20, 25 ) print( pixel[1], pixel[2], pixel[3] ) Alternate
A more object-oriented and extensible approach for easier re-use elsewhere.
local Bitmap = { new = function(self, width, height) local instance = setmetatable({ width=width, height=height }, self) instance:alloc() return instance end, alloc = function(self) self.pixels = {} for y = 1, self.height do self.pixels[y] = {} for x = 1, self.width do self.pixels[y][x] = 0x00000000 end end end, clear = function(self, c) for y = 1, self.height do for x = 1, self.width do self.pixels[y][x] = c or 0x00000000 end end end, get = function(self, x, y) x, y = math.floor(x+1), math.floor(y+1) -- given 0-based indices, use 1-based indices if ((x>=1) and (x<=self.width) and (y>=1) and (y<=self.height)) then return self.pixels[y][x] else return nil end end, set = function(self, x, y, c) x, y = math.floor(x+1), math.floor(y+1) -- given 0-based indices, use 1-based indices if ((x>=1) and (x<=self.width) and (y>=1) and (y<=self.height)) then self.pixels[y][x] = c or 0x00000000 end end, } Bitmap.__index = Bitmap setmetatable(Bitmap, { __call = function (t, ...) return t:new(...) end }) Usage:
local bitmap = Bitmap(32,32) -- default pixel representation is 32-bit packed ARGB on [0,255] bitmap:clear(0xFFFF0000) -- fill with red bitmap:set(1, 1, 0xFF00FF00) -- one green pixel bitmap:set(2, 2, 0xFF0000FF) -- one blue pixel print(string.format("pixel at 0,0 = %x", bitmap:get(0,0))) print(string.format("pixel at 1,1 = %x", bitmap:get(1,1))) print(string.format("pixel at 2,2 = %x", bitmap:get(2,2))) -- but note that pixel representation is agnostic.. -- (it's just a wrapper around a 2d-array of any valid type) -- want to switch to RGB-tuple on [0,1]?? bitmap:clear({1,0,0}) -- fill with red bitmap:set(1, 1, {0,1,0}) -- one green pixel bitmap:set(2, 2, {0,0,1}) -- one blue pixel print(string.format("pixel at 0,0 = %s", table.concat(bitmap:get(0,0),", "))) print(string.format("pixel at 1,1 = %s", table.concat(bitmap:get(1,1),", "))) print(string.format("pixel at 2,2 = %s", table.concat(bitmap:get(2,2),", "))) -- or strings?? bitmap:clear("red") -- fill with red bitmap:set(1, 1, "green") -- one green pixel bitmap:set(2, 2, "blue") -- one blue pixel print(string.format("pixel at 0,0 = %s", bitmap:get(0,0))) print(string.format("pixel at 1,1 = %s", bitmap:get(1,1))) print(string.format("pixel at 2,2 = %s", bitmap:get(2,2))) Caveat: Just be aware that as currently written the storage of complex types are referenced rather than copied. So, for example, using the clear() method with a table representing an RGB-tuple, will store the same identical reference throughout the bitmap - so direct modification of any one pixel's internal components would affect all other pixels as well. You should override the clear() method as appropriate to better support your desired pixel representation if this is not the behavior you desire.
- Output:
pixel at 0,0 = ffff0000 pixel at 1,1 = ff00ff00 pixel at 2,2 = ff0000ff pixel at 0,0 = 1, 0, 0 pixel at 1,1 = 0, 1, 0 pixel at 2,2 = 0, 0, 1 pixel at 0,0 = red pixel at 1,1 = green pixel at 2,2 = blue
The easy way is to make a function to return an object with all functions on it, for specific image. We have to make the image in a way to render it to screen. The render statement get data in a string using a header of 12 characters (24 bytes). Raster lines are in down-top order. So last raster line is the top one. Also RGB is BGR in this data structure. Raster lines has to be aligned proper, so we may have add some bytes.
There are four functions (lambda functions) in the returned group, each of them has closures, an one of that closure is a pointer to a buffer object. We use this object to set and get pixels.
First two functions are for set and get pixel. Third return image as a string. Forth function copy an image as string to buffer, if they have the same width and height (else we get error)
P3 ppm
Module Checkit { Function Bitmap (x as long, y as long) { if x<1 or y<1 then Error "Wrong dimensions" structure rgb { red as byte green as byte blue as byte } m=len(rgb)*x mod 4 if m>0 then m=4-m ' add some bytes to raster line m+=len(rgb) *x Structure rasterline { { pad as byte*m } \\ union pad+hline hline as rgb*x } Structure Raster { magic as integer*4 w as integer*4 h as integer*4 lines as rasterline*y } Buffer Clear Image1 as Raster \\ 24 chars as header to be used from bitmap render build in functions Return Image1, 0!magic:="cDIB", 0!w:=Hex$(x,2), 0!h:=Hex$(y, 2) \\ fill white (all 255) \\ Str$(string) convert to ascii, so we get all characters from words width to byte width Return Image1, 0!lines:=Str$(String$(chrcode$(255), Len(rasterline)*y)) Buffer Clear Pad as Byte*4 SetPixel=Lambda Image1, Pad,aLines=Len(Raster)-Len(Rasterline), blines=-Len(Rasterline) (x, y, c) ->{ where=alines+3*x+blines*y if c>0 then c=color(c) c-! Return Pad, 0:=c as long Return Image1, 0!where:=Eval(Pad, 2) as byte, 0!where+1:=Eval(Pad, 1) as byte, 0!where+2:=Eval(Pad, 0) as byte } GetPixel=Lambda Image1,aLines=Len(Raster)-Len(Rasterline), blines=-Len(Rasterline) (x,y) ->{ where=alines+3*x+blines*y =color(Eval(image1, where+2 as byte), Eval(image1, where+1 as byte), Eval(image1, where as byte)) } StrDib$=Lambda$ Image1, Raster -> { =Eval$(Image1, 0, Len(Raster)) } CopyImage=Lambda Image1 (image$) -> { if left$(image$,12)=Eval$(Image1, 0, 24 ) Then { Return Image1, 0:=Image$ } Else Error "Can't Copy Image" } Export2File=Lambda Image1, x, y, r=len(rasterline) (f) -> { \\ use this between open and close Print #f, "P3" Print #f,"# Created using M2000 Interpreter" Print #f, x;" ";y Print #f, 255 x2=x-1 For y1= y-1 to 0 { a$="" where=24+r*y1 x1=0 Print #f, Eval(Image1, where +2 as byte);" "; Print #f, Eval(Image1, where+1 as byte);" "; Print #f, Eval(Image1, where as byte); where+=3 For x1=1 to x2 { Print #f, " ";Eval(Image1, where +2 as byte);" "; Print #f, Eval(Image1, where+1 as byte);" "; Print #f, Eval(Image1, where as byte); where+=3 } Print #f } } Group Bitmap { SetPixel=SetPixel GetPixel=GetPixel Image$=StrDib$ Copy=CopyImage ToFile=Export2File } =Bitmap } A=Bitmap(150,100) For i=0 to 98 { Call A.SetPixel(i, i, 5) Call A.SetPixel(99, i, color(128,0,255)) } Call A.SetPixel(i,i,0) Call A.SetPixel(30,50, color(128,0,255)) Print A.GetPixel(30,50)=color(128,0,255) move 3000, 3000 Image A.image$() profiler Open "A2.PPM" for Output as #F Call A.ToFile(F) Close #f print timecount } Checkit P6 ppm
Module P6 { Function Bitmap { def x as long, y as long, Import as boolean If match("NN") then Read x, y else.if Match("N") Then \\ is a file? Read f as long byte whitespace[0] if not Eof(f) then get #f, whitespace :P6$=chr$(whitespace[0]) get #f, whitespace : P6$+=chr$(whitespace[0]) boolean getW=true, getH=true, getV=true long v If p6$="P6" Then do get #f, whitespace select case whitespace[0] case 35 {do get #f, whitespace until whitespace[0]=10 } case 32, 9, 13, 10 { if getW and x<>0 then getW=false else.if getH and y<>0 then getH=false else.if getV and v<>0 then getV=false end if } case 48 to 57 {if getW then x*=10 x+=whitespace[0]-48 else.if getH then y*=10 y+=whitespace[0]-48 else.if getV then v*=10 v+=whitespace[0]-48 end if } End Select iF eof(f) then Error "Not a ppm file" until getV=false else Error "Not a P6 ppm" end if Import=True end if else Error "No proper arguments" end if if x<1 or y<1 then Error "Wrong dimensions" structure rgb { red as byte green as byte blue as byte } m=len(rgb)*x mod 4 if m>0 then m=4-m ' add some bytes to raster line m+=len(rgb) *x Structure rasterline { { pad as byte*m } hline as rgb*x } Structure Raster { magic as integer*4 w as integer*4 h as integer*4 { linesB as byte*len(rasterline)*y } lines as rasterline*y } Buffer Clear Image1 as Raster Return Image1, 0!magic:="cDIB", 0!w:=Hex$(x,2), 0!h:=Hex$(y, 2) if not Import then Return Image1, 0!lines:=Str$(String$(chrcode$(255), Len(rasterline)*y)) Buffer Clear Pad as Byte*4 SetPixel=Lambda Image1, Pad, aLines=Len(Raster)-Len(Rasterline), blines=-Len(Rasterline) (x, y, c) ->{ where=alines+3*x+blines*y if c>0 then c=color(c) c-! Return Pad, 0:=c as long Return Image1, 0!where:=Eval(Pad, 2) as byte, 0!where+1:=Eval(Pad, 1) as byte, 0!where+2:=Eval(Pad, 0) as byte } GetPixel=Lambda Image1,aLines=Len(Raster)-Len(Rasterline), blines=-Len(Rasterline) (x,y) ->{ where=alines+3*x+blines*y =color(Eval(image1, where+2 as byte), Eval(image1, where+1 as byte), Eval(image1, where as byte)) } StrDib$=Lambda$ Image1, Raster -> { =Eval$(Image1, 0, Len(Raster)) } CopyImage=Lambda Image1 (image$) -> { if left$(image$,12)=Eval$(Image1, 0, 24 ) Then { Return Image1, 0:=Image$ } Else Error "Can't Copy Image" } Export2File=Lambda Image1, x, y (f) -> { Print #f, "P6";chr$(10);"# Created using M2000 Interpreter";chr$(10); Print #f, x;" ";y;" 255";chr$(10); x2=x-1 : where=0 x0=x*3 structure rgbP6 { r as byte g as byte b as byte } buffer Pad as rgbP6*x*y For y1=y-1 to 0 { Return pad, x*y1:=eval$(image1, 0!linesB!where, x0) where+=x0 m=where mod 4 : if m<>0 then where+=4-m } For x1=0 to x*y-1 { Push Eval(pad, x1!b) : Return pad, x1!b:=Eval(pad, x1!r), x1!r:=Number } Put #f, pad } if Import then { x0=x-1 : where=0 structure rgbP6 { r as byte g as byte b as byte } buffer Pad1 as rgbP6*x*y Get #f, Pad1 For x1=0 to x*y-1 { Push Eval(pad1, x1!b) : Return pad1, x1!b:=Eval(pad1, x1!r), x1!r:=Number } x1=x*3 For y1=y-1 to 0 { Return Image1, 0!linesB!where:=Eval$(Pad1, y1*x, x1) where+=3*(x0+1) m=where mod 4 : if m<>0 then where+=4-m } } Group Bitmap { SetPixel=SetPixel GetPixel=GetPixel Image$=StrDib$ Copy=CopyImage ToFile=Export2File } =Bitmap } A=Bitmap(150,100) For i=0 to 98 { Call A.SetPixel(i, i, 0) Call A.SetPixel(99, i, 0) } Call A.SetPixel(i,i,0) Copy 200*twipsx, 100*twipsy use A.Image$() Profiler Open "a.ppm" for output as #F Call A.tofile(f) Close #f Print Filelen("a.ppm") Print Timecount/1000;"sec" Profiler Image A.Image$() Export "a.jpg", 100 ' per cent quality Print Filelen("a.jpg") Image A.Image$() Export "a1.jpg", 10 ' per cent quality Print Filelen("a1.jpg") Image A.Image$() Export "a.bmp" Print Filelen("a.bmp") ' no compression Print Timecount/1000;"sec" Move 5000,5000 ' twips Image "a.jpg" Move 5000,8000 Image "a1.jpg" Move 8000, 5000 Image "a.bmp" } P6 Export using M2000 code for ppm is slower than using internal jpg and bmp encoders. Jpg encoder has a 100% quality, and because this image is black and white we get the best compression. Time 0.304sec is for three exports, two jpg and one bmp.
- Output:
45049 7.0107981sec 1018 691 45254 0.1786929sec
allocateImg := proc(width, height) return Array(1..width, 1..height, 1..3); end proc: fillColor := proc(img, rgb::list) local i; for i from 1 to 3 do img[..,..,i] := map(x->rgb[i], img[..,..,i]): end do: end proc: setColor := proc(x, y, img, rgb::list) local i: for i from 1 to 3 do img[x,y,i] := rgb[i]: end do: end proc: getColor := proc(x,y,img) local rgb,i: rgb := Array(1..3): for i from 1 to 3 do rgb(i) := img[x,y,i]: end do: return rgb: end proc: - Use:
a := allocateImg(200,200); fillColor(a,[255,223,0]); setColor(150,150, a, [0,0,0]); getColor(150,150,a); #Output the image ImageTools:-Embed(ImageTools:-Create(a))
In Mathematica 7/8:
img = Image[ConstantArray[{1, 0, 0}, {1000, 1000}]]; img = ReplacePart[img, {1, 1, 1} -> {0, 0, 1}]; ImageValue[img, {1, 1}] In Mathematica 9:
img = Image[ConstantArray[{1, 0, 0}, {1000, 1000}]]; img = ReplacePixelValue[img, {1, 1} -> {0, 0, 1}]; ImageValue[img, {1, 1}] Save this in a file named Bitmap.mat in a folder named @Bitmap in your MATLAB root directory.
%Bitmap class % %Implements a class to manage bitmap images without the need for the %various conversion and display functions % %Available functions: % %fill(obj,color) %setPixel(obj,pixel,color) %getPixel(obj,pixel,[optional: color channel]) %display(obj) %disp(obj) %plot(obj) %image(obj) %save(obj) %open(obj) classdef Bitmap %% Public Properties properties %Channel arrays red; green; blue; end %% Public Methods methods %Creates image and defaults it to black function obj = Bitmap(width,height) obj.red = zeros(height,width,'uint8'); obj.green = zeros(height,width,'uint8'); obj.blue = zeros(height,width,'uint8'); end % End Bitmap Constructor %Fill the image with a specified color %color = [red green blue] max for each is 255 function fill(obj,color) obj.red(:,:) = color(1); obj.green(:,:) = color(2); obj.blue(:,:) = color(3); assignin('caller',inputname(1),obj); %saves the changes to the object end %Set a pixel to a specified color %pixel = [x y] %color = [red green blue] function setPixel(obj,pixel,color) obj.red(pixel(2),pixel(1)) = color(1); obj.green(pixel(2),pixel(1)) = color(2); obj.blue(pixel(2),pixel(1)) = color(3); assignin('caller',inputname(1),obj); %saves the changes to the object end %Get pixel color %pixel = [x y] %varargin can be: % no input for all channels % 'r' or 'red' for red channel % 'g' or 'green' for green channel % 'b' or 'blue' for blue channel function color = getPixel(obj,pixel,varargin) if( ~isempty(varargin) ) switch (varargin{1}) case {'r','red'} color = obj.red(pixel(2),pixel(1)); case {'g','green'} color = obj.red(pixel(2),pixel(1)); case {'b','blue'} color = obj.red(pixel(2),pixel(1)); end else color = [obj.red(pixel(2),pixel(1)) obj.green(pixel(2),pixel(1)) obj.blue(pixel(2),pixel(1))]; end end %Display the image %varargin can be: % no input for all channels % 'r' or 'red' for red channel % 'g' or 'green' for green channel % 'b' or 'blue' for blue channel function display(obj,varargin) if( ~isempty(varargin) ) switch (varargin{1}) case {'r','red'} image(obj.red) case {'g','green'} image(obj.green) case {'b','blue'} image(obj.blue) end colormap bone; else bitmap = cat(3,obj.red,obj.green,obj.blue); image(bitmap); end end %Overload several commonly used display functions function disp(obj,varargin) display(obj,varargin{:}); end function plot(obj,varargin) display(obj,varargin{:}); end function image(obj,varargin) display(obj,varargin{:}); end %Saves the image function save(obj) %Open file dialogue [fileName,pathName,success] = uiputfile({'*.bmp','Bitmap Image (*.bmp)'},'Save Bitmap As'); if( not(success == 0) ) imwrite(cat(3,obj.red,obj.green,obj.blue),[pathName fileName],'bmp'); %Write image file to disk disp('Save Complete'); end end %Opens an image and overwrites what is currently stored function success = open(obj) %Open file dialogue [fileName,pathName,success] = uigetfile({'*.bmp','Bitmap Image (*.bmp)'},'Open Bitmap '); if( not(success == 0) ) channels = imread([pathName fileName], 'bmp'); %returns color indexed data %Store each channel obj.red = channels(:,:,1); obj.green = channels(:,:,2); obj.blue = channels(:,:,3); assignin('caller',inputname(1),obj); %saves the changes to the object success = true; return else success = false; return end end end %methods end %classdef Sample Usage:
>> img = Bitmap(20,30); >> img.fill([30 30 150]); >> img.setPixel([10 15],[20 130 66]); >> disp(img) >> img.getPixel([10 15]) ans = 20 130 66 >> img.getPixel([10 15],'red') ans = 20 >> img.save() Save Complete MAXScript provides a built-in Bitmap class.
local myBitmap = bitmap 512 512Filling 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] 1This GUI implementation is for use with Mini Micro.
// MiniMicro version of MiniScript has all the // necessary methods built-in to complete this task. width = 256 height = 256 colr = color.aqua // Create the image with specified width/heigh. With // no parameters, it defaults width/height to 64 and // color to black img = Image.create(width, height, colr) // Create a diagonal line of multiple colors. Uses // Cartesian coordinates so (0, 0) is lower left corner. for i in range(0, 255) img.setPixel i, i, color.rgb(i, i, i) end for // Get pixel color as RGBA hex values print "Color at pixel (100, 100): " + img.pixel(100, 100) print "Color at pixel (0, 0): " + img.pixel(0, 0) print "Color at pixel (127, 127): " + img.pixel(127, 127) print "Color at pixel (255, 255): " + img.pixel(255, 255) // Display the image, resizing it to 127 x 127 gfx.drawImage img, 0, 0, 127, 127 // Save the file - accepted file extensions: // tga, jpg, jpeg, and png (retains transparency) // Optional third parameter is JPG compression quality. file.saveImage "/usr/test.png", img 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. type Luminance* = uint8 Index* = int Color* = tuple r, g, b: Luminance Image* = ref object w*, h*: Index pixels*: seq[Color] Point* = tuple x, y: Index proc color*(r, g, b: SomeInteger): Color = ## Build a color value from R, G and B values. result.r = r.uint8 result.g = g.uint8 result.b = b.uint8 const Black* = color( 0, 0, 0) White* = color(255, 255, 255) proc newImage*(width, height: int): Image = ## Create an image with given width and height. new(result) result.w = width result.h = height result.pixels.setLen(width * height) iterator indices*(img: Image): Point = ## Yield the pixels coordinates as tuples. for y in 0 ..< img.h: for x in 0 ..< img.w: yield (x, y) proc `[]`*(img: Image; x, y: int): Color = ## Get a pixel RGB value. img.pixels[y * img.w + x] proc `[]=`*(img: Image; x, y: int; c: Color) = ## Set a pixel RGB value to given color. img.pixels[y * img.w + x] = c proc fill*(img: Image; color: Color) = ## Fill the image with a color. for x, y in img.indices: img[x, y] = color proc print*(img: Image) = ## Output an ASCII representation of the image. for x, y in img.indices: if x mod img.w == 0: stdout.write '\n' stdout.write if img[x, y] == White: '.' else: 'H' stdout.write '\n' when isMainModule: var img = newImage(100, 20) img.fill color(255, 255, 255) img[1, 2] = color(255, 0, 0) img[3, 4] = img[1, 2] img.print 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) 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"); 'GENERIC BITMAP type pixel byte r,g,b '=========== class BitMap '=========== % sp sizeof(pixel) sys wx,wy,px,py string buf sys pb method Constructor(sys x=640,y=480) { wx=x : wy=y : buf=nuls x*y*sp : pb=strptr buf} method Destructor() {buf="" : wx=0 : wy=0 : pb=0} method GetPixel(sys x,y,pixel*p) {copy @p,pb+(y*wx+x)*sp,sp} method SetPixel(sys x,y,pixel*p) {copy pb+(y*wx+x)*sp,@p,sp} ' method Fill(pixel*p) sys i, e=wx*wy*sp+pb-1 for i=pb to e step sp {copy i,@p,sp} end method end class pixel p,q new BitMap m(400,400) 'width, height in pixels p<=100,120,140 'red,green,blue m.fill p m.getPixel 200,100,q print "" q.r "," q.g "," q.b 'result 100,120,140 q<=10,20,40 m.setPixel 200,100,q m.getPixel 200,100,p print "" p.r "," p.g "," p.b 'result 10,20,40 del mWe 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 endBased 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 endSome functions that are used in other tasks were omitted. See here for the complete module definitions: Basic bitmap storage/Oz
Interface uses crt, { GetDir } graph; { function GetPixel } type { integer numbers } { from unit bitmaps XPERT software production Tamer Fakhoury } _bit = $00000000..$00000001; {number 1 bit without sign = (0..1) } _byte = $00000000..$000000FF; {number 1 byte without sign = (0..255)} _word = $00000000..$0000FFFF; {number 2 bytes without sign = (0..65 535)} _dWord = $00000000..$7FFFFFFF; {number 4 bytes without sign = (0..4 294 967 296)} _longInt = $80000000..$7FFFFFFF; {number 4 bytes with sign = (-2 147 483 648..2 147 483 648} TbmpFileHeader = record ID: _word; { Must be 'BM' =19778=$424D for windows } FileSize: _dWord; { Size of this file in bytes } Reserved: _dWord; { ??? } bmpDataOffset: _dword; { = 54 = $36 from begining of file to begining of bmp data } end; TbmpInfoHeader = record InfoHeaderSize: _dword; { Size of Info header = 28h = 40 (decimal) for windows } Width, Height: _longInt; { Width and Height of image in pixels } Planes, { number of planes of bitmap } BitsPerPixel: _word; { Bits can be 1, 4, 8, 24 or 32 } Compression, bmpDataSize: _dword; { in bytes rounded to the next 4 byte boundary } XPixPerMeter, { horizontal resolution in pixels } YPixPerMeter: _longInt; { vertical } NumbColorsUsed, NumbImportantColors: _dword; {= NumbColorUsed} end; { TbmpHeader = Record ... } T32Color = record { 4 byte = 32 bit } Blue: byte; Green: byte; Red: byte; Alfa: byte end; var directory, bmpFileName: string; bmpFile: file; { untyped file } bmpFileHeader: TbmpFileHeader; bmpInfoHeader: TbmpInfoHeader; color32: T32Color; RowSizeInBytes: integer; BytesPerPixel: integer; const defaultBmpFileName = 'test'; DefaultDirectory = 'c:\bp\'; DefaultExtension = '.bmp'; bmpFileHeaderSize = 14; { compression specyfication } bi_RGB = 0; { compression } bi_RLE8 = 1; bi_RLE4 = 2; bi_BITFIELDS = 3; bmp_OK = 0; bmp_NotBMP = 1; bmp_OpenError = 2; bmp_ReadError = 3; Procedure CreateBmpFile32(directory: string; FileName: string; iWidth, iHeight: _LongInt); {************************************************} Implementation {-----------------------------} {************************************************} Procedure CreateBmpFile32(directory: string; FileName: string; iWidth, iHeight: _LongInt); var x, y: integer; begin if directory = '' then GetDir(0, directory); if FileName = '' then FileName: = DefaultBmpFileName; { create a new file on a disk in a given directory with given name } Assign(bmpFile, directory + FileName + DefaultExtension); ReWrite(bmpFile, 1); { fill the headers } with bmpInfoHeader, bmpFileHeader do begin ID := 19778; InfoheaderSize := 40; width := iWidth; height := iHeight; BitsPerPixel := 32; BytesPerPixel := BitsPerPixel div 8; reserved := 0; bmpDataOffset := InfoHeaderSize + bmpFileHeaderSize; planes := 1; compression := bi_RGB; XPixPerMeter := 0; YPixPerMeter := 0; NumbColorsUsed := 0; NumbImportantColors := 0; RowSizeInBytes := (Width * BytesPerPixel); { only for >=8 bits per pixel } bmpDataSize := height * RowSizeinBytes; FileSize := InfoHeaderSize + bmpFileHeaderSize + bmpDataSize; { copy headers to disk file } BlockWrite(bmpFile, bmpFileHeader, bmpFileHeaderSize); BlockWrite(bmpFile, bmpInfoHeader, infoHeaderSize); { fill the pixel data area } for y := (height - 1) downto 0 do begin for x := 0 to (width - 1) do begin { Pixel(x,y) } color32.Blue := 255; color32.Green := 0; color32.Red := 0; color32.Alfa := 0; BlockWrite(bmpFile, color32, 4); end; { for x ... } end; { for y ... } Close(bmpFile); end; { with bmpInfoHeader, bmpFileHeader } end; { procedure } #! /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; Copy of Euphoria
with javascript_semantics -- Some colour constants: constant black = #000000, -- blue = #0000FF, -- green = #00FF00, -- red = #FF0000, white = #FFFFFF -- Create new image filled with some colour function new_image(integer width, integer height, integer fill_colour=black) return repeat(repeat(fill_colour,height),width) end function -- Usage example: sequence image = new_image(800,600) -- Set pixel color: image[400][300] = white -- Get pixel color integer colour = image[400][300] -- Now colour is #FFFFFF
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) 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) )/* 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;Pluto already has a 'canvas' class in its standard library which is used for creating or manipulating bitmaps. The following script shows how to create a simple image and save it to a .bmp file where it can be viewed by an external utility for your platform.
local canvas = require "canvas" -- Create a new canvas object: 400 pixels wide and 400 pixels high. local c = canvas.new(400, 400) -- Color the whole canvas blue. c:fill(0xff0000) -- Draw a red square in the middle. for i = 1, 51 do for j = 1, 51 do c:set(174 + i, 174 + j, 0x0000ff) end end -- Print to the terminal the color (as an integer) of a pixel. print(c:get(200, 200)) -- 255 -- Convert the canvas to a BMP image. local image = c:tobmp() -- Save the image to a file. io.contents("mybmp.bmp", image) Alternatively, we can use the above module which wraps the canvas class to make drawing a little easier.
require "bitmap" -- Create a new bitmap object: 400 pixels wide and 400 pixels high local bmp = bitmap.of(400, 400, color.blue, "mybmp") -- Draw a red square in the middle. bmp:square(200, 200, 50, color.red, 0, true) -- Print to the terminal the color (as an integer) of a pixel. print(bmp:get(200, 200)) -- 255 -- View the image using the default viewer for the platform. bmp:view() -- Save the image to the file mybmp.bmp in the current directory. bmp:save() //cmd: +w300 +h300 +am2 +a0.01 #version 3.7; #global_settings {assumed_gamma 1} #default{ finish{ ambient 0.1 diffuse 0.9 }} background {rgb 0} #macro mapInit(DimX, DimY) #local Map = array[DimX][DimY]; mapFillSolid(Map, rgb<0,0,0>) Map #end #macro mapFillSolid(Map, Colour) mapFillRect(Map,<0,0>,<dimension_size(Map,1),dimension_size(Map,2)>, Colour) #end #macro mapFillRect(Map, RectLowerLeft, RectUpperRight, Colour) #for (X, RectLowerLeft.x, RectUpperRight.x - 1) #for (Y, RectLowerLeft.y, RectUpperRight.y - 1) #local Map[X][Y] = Colour; #end #end #end #macro mapSetPixel(Map, Pixel, Colour) #local Map[Pixel.x][Pixel.y] = Colour; #end #macro mapGetPixel(Map, Pixel) Map[Pixel.x][Pixel.y] #end #macro mapObject(Map) // to visualize the map, each pixel is rendered as a sphere #for (X,0,dimension_size(Map,1)-1) #for (Y,0,dimension_size(Map,2)-1) sphere{ <X, Y, 0>, 0.5 pigment{colour Map[X][Y]} } #end #end #end //== Scene #declare DimX = 100; #declare DimY = 100; #declare ImgMap = mapInit(DimX, DimY); mapFillSolid(ImgMap, rgb<1, 0, 0>) mapSetPixel(ImgMap, <25,25>, rgb<1,1,1>) mapFillRect(ImgMap, <50,50>, <75,75>, rgb<0,0,1>) #debug concat("Colour at: <", vstr(2,<25,25>,", ",0,0),"> is: <", vstr(3, mapGetPixel(ImgMap, <25,25>),", ",0,0),">\n") mapObject(ImgMap) camera{ location <DimX/2, DimY/2, -110> look_at <DimX/2, DimY/2, 0> right x*image_width/image_height } light_source{ <DimX/2, DimY/2, -3000> rgb 1 } - Output:
PGraphics bitmap = createGraphics(100,100); // Create the bitmap bitmap.beginDraw(); bitmap.background(255, 0, 0); // Fill bitmap with red rgb color bitmap.endDraw(); image(bitmap, 0, 0); // Place bitmap on screen. color b = color(0, 0, 255); // Define a blue rgb color set(50, 50, b); // Set blue colored pixel in the middle of the screen color c = get(50, 50); // Get the color of same pixel if(b == c) print("Color changed correctly"); // Verify :- module(bitmap, [ new_bitmap/3, fill_bitmap/3, get_pixel0/3, set_pixel0/4 ]). :- use_module(library(lists)). %-----------------------------------------------------------------------------% % Convenience Predicates replicate(Term,Times,L):- length(L,Times), maplist(=(Term),L). replace0(N,OL,E,NL):- nth0(N,OL,_,TL), nth0(N,NL,E,TL). %-----------------------------------------------------------------------------% % Bitmap Utilities % % The Bitmap structure is a list with pixels kept in row major order: % [dimensions-[X,Y],pixels-[[n11,n12...],[n21,n22...]]] % In this code what exactly an RGB value is doesn't matter however % in other bitmap tasks it is assumed to be a list [R,G,B] where % each is an int between 0 and 255, in code: rgb_pixel(RGB):- length(RGB,3), maplist(integer,RGB), maplist(between(0,255),RGB). %new_bitmap(Bitmap,Dimensions,RGB) new_bitmap([[X,Y],Pixels],[X,Y],RGB) :- replicate(RGB,X,Row), replicate(Row,Y,Pixels). %fill_bitmap(New_Bitmap,Bitmap,RGB) fill_bitmap(New_Bitmap,[[X,Y],_],RGB) :- new_bitmap(New_Bitmap,[X,Y],RGB). %here get and set use 0 based indexing %get_pixel0(Bitmap,Coordinates,RGB) get_pixel0([[_DimX,_DimY],Pixels],[X,Y],RGB) :- nth0(Y,Pixels,Row), nth0(X,Row,RGB). %set_pixel0(New Bitmap, Bitmap, Coordinates, RGB) set_pixel0([[DimX,DimY],New_Pixels],[[DimX,DimY],Pixels],[X,Y],RGB) :- nth0(Y,Pixels,Row), replace0(X,Row,RGB,New_Row), replace0(Y,Pixels,New_Row,New_Pixels). 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)) See Basic bitmap storage/Python
SUB establecePixel (x AS INTEGER, y AS INTEGER, c AS INTEGER) PSET (x, y), cyan END SUB SUB rellenar (c AS INTEGER) SHARED w, h LINE (0, 0)-(w / 3, h / 3), red, BF END SUB SCREEN 13 w = 320: h = 200 CONST cyan = 3, red = 4 rellenar (12) CALL establecePixel(10, 10, cyan) LOCATE 12 PRINT "pixel 10,10 is "; POINT(10, 10) PRINT "pixel 20,20 is "; POINT(20, 10) 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 <- function(pm, i, j) { pmcol <- pm@col dim(pmcol) <- dim(pm@index) pmcol[i,j] } getcol(p2, 3, 4) #red #lang racket ;; The racket/draw libraries provide imperative drawing functions. ;; http://docs.racket-lang.org/draw/index.html (require racket/draw) ;; To create an image with width and height, use the make-bitmap ;; function. ;; For example, let's make a small image here: (define bm (make-bitmap 640 480)) ;; We use a drawing context handle, a "dc", to operate on the bitmap. (define dc (send bm make-dc)) ;; We can fill the bitmap with a color by using a combination of ;; setting the background, and clearing. (send dc set-background (make-object color% 0 0 0)) ;; Color it black. (send dc clear) ;; Let's set a few pixels to a greenish color with set-pixel: (define aquamarine (send the-color-database find-color "aquamarine")) (for ([i 480]) (send dc set-pixel i i aquamarine)) ;; We can get at the color of a bitmap pixel by using the get-pixel ;; method. However, it may be faster to use get-argb-pixels if we ;; need a block of the pixels. Let's use get-argb-pixels and look ;; at a row starting at (0, 42) (define buffer (make-bytes (* 480 4))) ;; alpha, red, green, blue (send dc get-argb-pixels 0 42 480 1 buffer) ;; We can inspect the buffer (bytes-ref buffer 0) ;; and see that the first pixel's alpha is 255, (bytes-ref buffer 1) ;; and the red, green, and blue components are 0. (bytes-ref buffer 2) (bytes-ref buffer 3) ;; If we are using DrRacket, we can just print the bm as a toplevel expression ;; to view the final image: bm (formerly Perl 6)
class Pixel { has UInt ($.R, $.G, $.B) } class Bitmap { has UInt ($.width, $.height); has Pixel @!data; method fill(Pixel $p) { @!data = $p.clone xx ($!width*$!height) } method pixel( $i where ^$!width, $j where ^$!height --> Pixel ) is rw { @!data[$i + $j * $!width] } method set-pixel ($i, $j, Pixel $p) { self.pixel($i, $j) = $p.clone; } method get-pixel ($i, $j) returns Pixel { self.pixel($i, $j); } } my Bitmap $b = Bitmap.new( width => 10, height => 10); $b.fill( Pixel.new( R => 0, G => 0, B => 200) ); $b.set-pixel( 7, 5, Pixel.new( R => 100, G => 200, B => 0) ); say $b.perl; Thanks to the rw trait on the pixel method, we don't actually need to define two separate methods, set-pixel and get-pixel, but that is an explicit requirement of the task. (Beware your presuppositions! In Raku, accessors only determine identity, not use. In particular, identity is considered orthogonal to lvalue/rvalue context.)
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.ShowModalversion 1
The REXX language has no need to declare the size of (stemmed) arrays.
Indeed, there is no way to declare array sizes (or any variable, for that matter).
The image (raster) created was also written to a file (image.PPM) to show verification of the image.
/*REXX program demonstrates how to process/display */ /* a simple RGB raster graphics image.*/ red = 'ff 00 00'x /*a method to define a red value. */ blue = '00 00 ff'x /*' ' ' ' ' blue ' */ pixel='' /*define entire pixel. array to nulls.*/ outFN = 'image' /*the filename of the output image PPM */ sWidth = 500; sHeight= 500 /*the screen width and height in pixels*/ Call RGBfill red /*set the entire image to red. */ x=10; y=40 /*set pixel's coördinates. */ Call RGBset x,y,blue /*set a pixel (at 10,40) to blue. */ color = RGBget(x,y) /*get the color of a pixel. */ hexV = c2x(color) /*get hex value of pixel's color. */ binV = x2b(hexV) /* " binary " " " " */ bin3V = left(binV,8) substr(binV,9,8) right(binV,8) hex3V = left(hexV,2) substr(hexV,3,2) right(hexV,2) xy= '('||x','y')' /*create a handy-dandy literal for SAY.*/ Say xy ' pixel in binary: ' binV /*show the binary value of 20,50 */ Say xy ' pixel in binary: ' bin3V /*show again,but with spaces. */ Say /*show a blank between bin & hex. */ Say xy ' pixel in hex: ' hexV /*show again,but in hexadecimal. */ Say xy ' pixel in hex: ' hex3V /*show again,but with spaces. */ Call PPMwrite outFN,sWidth,sHeight /*create a PPM (output) file */ /* ?¦¦¦¦¦¦¦¦ not part of this task.*/ Say /*show a blank. */ Say 'The file ' outFN'.PPM was created.' /*inform user */ Exit /*stick a fork in it, we're all done. */ /*---------------------------------------------------------------------*/ RGBfill: pixel.=arg(1); Return /*fill image with a color.*/ RGBget: Parse arg px,py; Return pixel.px.py /*get a pixel's color. */ RGBset: Parse arg px,py,psep; pixel.px.py=psep; Return /*set a pixel */ /*---------------------------------------------------------------------*/ PPMwrite: Parse arg oFN,width,height oFID= oFN'.PPM' /* fileID */ sep='9'x; /* separator */ maxcol=255 /* max color value. */ Call charout oFID,,1 /*set the position of the file's output*/ Call charout oFID,'P6'width||sep||height||sep||maxcol||sep /* header */ Do i=1 To width Do j=1 To height; Call charout oFID,pixel.i.j End End Call charout oFID /* close the output file just to be safe */ Return - output:
(10,40) pixel in binary: 000000000000000011111111 (10,40) pixel in binary: 00000000 00000000 11111111 (10,40) pixel in hex: 0000FF (10,40) pixel in hex: 00 00 FF The file image.PPM was created.
version 2
This program actually creates a BMP file
/* REXX *************************************************************** * Draw a picture from pixels * 16.06.2014 Walter Pachl **********************************************************************/ oid='pic.bmp'; 'erase' oid blue ='FF0000'x; green='00FF00'x; red ='0000FF'x; white='ffffff'x; black='000000'x; w=600 /* width */ h=300 /* height */ w3=w*3 bfType ='BM' bfSize ='46000000'x bfReserved ='00000000'x bfOffBits ='36000000'x biSize ='28000000'x biWidth =lend(w) biHeight =lend(h) biPlanes ='0100'x biBitCount ='1800'x biCompression ='00000000'x biSizeImage ='10000000'x biXPelsPerMeter='00000000'x biYPelsPerMeter='00000000'x biClrUsed ='00000000'x biClrImportant ='00000000'x s=bfType||, bfSize||, bfReserved||, bfOffBits||, biSize||, biWidth||, biHeight||, biPlanes||, biBitCount||, biCompression||, biSizeImage||, biXPelsPerMeter||, biYPelsPerMeter||, biClrUsed||, biClrImportant pic=copies(red,w*h) /* fill the rectangle with color red */ Call rect 100,100,180,180,green /* draw a green rectangle */ Call rect 100,100,160,160,blue /* and a blue rectangle within that */ Call dot 120,120,white /* one pixel is hardly visible */ Do x=98 To 102 /* draw a square of 25 pixels */ Do y=98 To 102 Call dot x,y,white End End Call charout oid,s||pic /* write the picture to file */ dmy=col(97,98) dmy=col(98,98) Exit lend: Procedure /********************************************************************** * compute the representation of a number (little endian) **********************************************************************/ Parse Arg n res=reverse(d2c(n,4)) rev=reverse(res) say 'lend:' arg(1) '->' c2x(res) '=>' c2d(rev) Return res rect: Procedure Expose pic w h w3 /********************************************************************** * Fill a rectangle with center at x,y and width/height = wr/hr **********************************************************************/ Parse Arg x,y,wr,hr,color Say x y wr hr c2x(color) i=w3*(y-1)+3*(x-1)+1 /* Pixel position of center */ ia=max(w3*(y-1)+1,i-3*(wr%2)) /* position of left border */ ib=min(i+3*wr%2,w3*y) /* position of right border */ lc=ib-ia /* length of horizontal line */ If lc>=0 Then Do os=copies(color,lc%3) /* the horizontal line */ Do hi=-hr%2 to hr%2 /* loop from lower to upper border*/ i=trunc(ia+w3*hi) /* position of line's left border */ If i>1 Then Do pic=overlay(os,pic,i) /* put the line into the picture */ j=i%w3 End End End Return dot: Procedure Expose pic w h w3 /********************************************************************** * Put a dot at position x/y into the picture **********************************************************************/ Parse Arg x,y,color i=w3*(y-1)+3*(x-1) pic=overlay(color,pic,i+1) Return col: Procedure Expose pic w h w3 /********************************************************************** * get the color at position x/y **********************************************************************/ Parse Arg x,y,color i=w3*(y-1)+3*(x-1) say 'color at pixel' x'/'y'='c2x(substr(pic,i+1,3)) Return c2x(substr(pic,i+1,3)) - Output:
lend: 600 -> 58020000 => 600 lend: 300 -> 2C010000 => 300 100 100 180 180 00FF00 100 100 160 160 FF0000 color at pixel 97/98=FF0000 color at pixel 98/98=FFFFFF and have a look at the file pic.bmp created by this program
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 #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct Rgb { pub r: u8, pub g: u8, pub b: u8, } impl Rgb { pub fn new(r: u8, g: u8, b: u8) -> Self { Rgb { r, g, b } } pub const BLACK: Rgb = Rgb { r: 0, g: 0, b: 0 }; pub const RED: Rgb = Rgb { r: 255, g: 0, b: 0 }; pub const GREEN: Rgb = Rgb { r: 0, g: 255, b: 0 }; pub const BLUE: Rgb = Rgb { r: 0, g: 0, b: 255 }; } #[derive(Clone, Debug)] pub struct Image { width: usize, height: usize, pixels: Vec<Rgb>, } impl Image { pub fn new(width: usize, height: usize) -> Self { Image { width, height, pixels: vec![Rgb::BLACK; width * height], } } pub fn width(&self) -> usize { self.width } pub fn height(&self) -> usize { self.height } pub fn fill(&mut self, color: Rgb) { for pixel in &mut self.pixels { *pixel = color; } } pub fn get(&self, row: usize, col: usize) -> Option<&Rgb> { if row >= self.width { return None; } self.pixels.get(row * self.width + col) } pub fn get_mut(&mut self, row: usize, col: usize) -> Option<&mut Rgb> { if row >= self.width { return None; } self.pixels.get_mut(row * self.width + col) } } fn main() { let mut image = Image::new(16, 9); assert_eq!(Some(&Rgb::BLACK), image.get(3, 4)); assert!(image.get(22, 3).is_none()); image.fill(Rgb::RED); assert_eq!(Some(&Rgb::RED), image.get(3, 4)); if let Some(pixel) = image.get_mut(3, 4) { *pixel = Rgb::GREEN; } assert_eq!(Some(&Rgb::GREEN), image.get(3, 4)); if let Some(pixel) = image.get_mut(3, 4) { pixel.g -= 100; pixel.b = 20; } assert_eq!(Some(&Rgb::new(0, 155, 20)), image.get(3, 4)); } Java translation
import java.awt.image.BufferedImage import java.awt.Color class RgbBitmap(val width:Int, val height:Int) { val image=new BufferedImage(width, height, BufferedImage.TYPE_3BYTE_BGR) def fill(c:Color)={ val g=image.getGraphics() g.setColor(c) g.fillRect(0, 0, width, height) } def setPixel(x:Int, y:Int, c:Color)=image.setRGB(x, y, c.getRGB()) def getPixel(x:Int, y:Int)=new Color(image.getRGB(x, y)) } Usage:
val img=new RgbBitmap(50, 50); img.fill(Color.CYAN) img.setPixel(5, 5, Color.BLUE) assert(img.getPixel(1,1)==Color.CYAN) assert(img.getPixel(5,5)==Color.BLUE) assert(img.width==50) assert(img.height==50) Scala idiom
A more Scalesque version could be with the use of its idiom:
- Output:
Best experienced in your browser with Scastie (remote JVM).
import java.awt.image.BufferedImage import java.awt.Color object RgbBitmap extends App { class RgbBitmap(val dim: (Int, Int)) { def width = dim._1 def height = dim._2 private val image = new BufferedImage(width, height, BufferedImage.TYPE_3BYTE_BGR) def apply(x: Int, y: Int) = new Color(image.getRGB(x, y)) def update(x: Int, y: Int, c: Color) = image.setRGB(x, y, c.getRGB) def fill(c: Color) = { val g = image.getGraphics g.setColor(c) g.fillRect(0, 0, width, height) } } object RgbBitmap { def apply(width: Int, height: Int) = new RgbBitmap(width, height) } /** Even Javanese style testing is still possible. */ private val img0 = new RgbBitmap(50, 60) { // Wrappers to enable adhoc Javanese style def getPixel(x: Int, y: Int) = this(x, y) def setPixel(x: Int, y: Int, c: Color) = this(x, y) = c } img0.fill(Color.CYAN) img0.setPixel(5, 6, Color.BLUE) // Testing in Java style assert(img0.getPixel(0, 1) == Color.CYAN) assert(img0.getPixel(5, 6) == Color.BLUE) assert(img0.width == 50) assert(img0.height == 60) println("Tests successfully completed with no errors found.") } 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))) The types and functions requested are predefined in the libraries graph.s7i and draw.s7i:
- The type to handle an RGB raster graphics image is PRIMITIVE_WINDOW.
- The function to create an image is newPixmap.
- An imaged can be filled with a color with clear.
- A given pixel can be set with point.
- The color of a pixel can be retrieved with getPixelColor.
$ include "seed7_05.s7i"; include "draw.s7i"; const proc: main is func local var PRIMITIVE_WINDOW: myPixmap is PRIMITIVE_WINDOW.value; var color: myColor is black; begin myPixmap := newPixmap(300, 200); clear(myPixmap, light_green); point(myPixmap, 20, 30, color(256, 512, 768)); myColor := getPixelColor(myPixmap, 20, 30); writeln(myColor.redLight <& " " <& myColor.greenLight <& " " <& myColor.blueLight); end func;RGB ::= (R: int(0), G: int(0), B: int(0)); newBitmap: int * int -> RGB(2); newBitmap(width, height)[y, x] := (R: 0, G: 0, B: 0) foreach y within 1 ... height, x within 1 ... width; fill: RGB(2) * RGB -> RGB(2); fill(bitmap(2), color)[y, x] := color foreach y within 1 ... size(bitmap), x within 1 ... size(bitmap[y]); setColorAt: RGB(2) * int * int * RGB -> RGB(2); setColorAt(bitmap(2), x, y, color)[Y, X] := color when Y = y and X = x else bitmap[Y, X]; getColorAt: RGB(2) * int * int -> RGB; getColorAt(bitmap(2), x, y) := bitmap[y, x]; lightGreen := (R: 51, G: 255, B: 51); lightRed := (R: 255, G: 51, B: 51); main(args(2)) := let width := 1920; height := 1200; cleanImage := newBitmap(width, height); filledGreen := fill(cleanImage, lightGreen); redCenter := setColorAt(filledGreen, width / 2, height / 2, lightRed); in getColorAt(redCenter, width / 2, height / 2);- Output:
cmd:> main.exe (B:51,G:51,R:255)
|img1 img2| "a depth24 RGB image" img1 := Image width:100 height:200 depth:24. img1 fillRectangle:(0@0 corner:100@100) with:Color red. img1 fillRectangle:(0@100 corner:100@100) with:(Color rgbValue: 16rFF00FF). img1 colorAt:(10 @ 10) put:(Color green). img1 saveOn:'sampleFile.png'. img1 displayOn:Transcript window graphicsContext. Transcript showCR:(img1 colorAt:(100 @ 10) ). "a depth8 palette image" img2 := Image width:100 height:200 depth:8. img2 colorMap:{ Color black. Color red . Color green }. img2 fillRectangle:(0@0 corner:100@100) with:Color red. img2 fillRectangle:(0@100 corner:100@100) with: 16r02. img2 colorAt:(10 @ 10) put:(Color green). img2 saveOn:'sampleFile.gif'. img2 displayOn:Transcript window graphicsContext. Transcript showCR:(img2 colorAt:(100 @ 10) ). 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}] 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.
↯ 50_50_3 Red # Fill with red. ⍜(⊡25_25|⋅White) # Add white spot. ⊸⊡0_0 # Get pixel [0 0].- Output:
See Uiua Pad for a red square with a white dot in it.
typeset -T RGBColor_t=( integer r g b function to_s { printf "%d %d %d" ${_.r} ${_.g} ${_.b} } function white { print "255 255 255"; } function black { print "0 0 0"; } function red { print "255 0 0"; } function green { print "0 255 0"; } function blue { print "0 0 255"; } function yellow { print "255 255 0"; } function magenta { print "255 0 255"; } function cyan { print "0 255 255"; } ) typeset -T Bitmap_t=( integer height integer width typeset -a data function fill { typeset color=$1 if [[ -z ${color:+set} ]]; then print -u2 "error: no fill color specified" return 1 fi integer x y for ((y=0; y<_.height; y++)); do for ((x=0; x<_.width; x++)); do _.data[y][x]="$color" done done } function setpixel { integer x=$1 y=$2 typeset color=$3 _.data[y][x]=$color } function getpixel { integer x=$1 y=$2 print "${_.data[y][x]}" } function to_s { typeset ppm="" ppm+="P3"$'\n' ppm+="${_.width} ${_.height}"$'\n' ppm+="255"$'\n' typeset sep for ((y=0; y<_.height; y++)); do sep="" for ((x=0; x<_.width; x++)); do ppm+="$sep${_.data[y][x]}" sep=" " done ppm+=$'\n' done print -- "$ppm" } ) RGBColor_t color Bitmap_t b=( width=3 height=2 ) b.fill "$(color.white)" b.setpixel 0 0 "$(color.red)" b.setpixel 1 0 "$(color.green)" b.setpixel 2 0 "$(color.blue)" b.setpixel 0 1 "$(color.yellow)" b.setpixel 1 1 "$(color.white)" b.setpixel 2 1 "$(color.black)" echo "$(b.getpixel 0 0)" b.to_s - Output:
255 0 0 P3 3 2 255 255 0 0 0 255 0 0 0 255 255 255 0 255 255 255 0 0 0
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' 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 The above library's ImageData class fits the bill here (version 1.3.0 or later).
import "graphics" for Canvas, ImageData, Color import "dome" for Window class Game { static bmpCreate(name, w, h) { ImageData.create(name, w, h) } static bmpFill(name, col) { var image = ImageData[name] for (x in 0...image.width) { for (y in 0...image.height) image.pset(x, y, col) } } static bmpPset(name, x, y, col) { ImageData[name].pset(x, y, col) } static bmpPget(name, x, y) { ImageData[name].pget(x, y) } static init() { Window.title = "Bitmap" var size = 600 Window.resize(size, size) Canvas.resize(size, size) var bmp = bmpCreate("rcbmp", size/2, size/2) bmpFill("rcbmp", Color.yellow) bmpPset("rcbmp", size/4, size/4, Color.blue) // 'blue' is #29ADFF on the default palette var col = bmpPget("rcbmp", size/4, size/4) System.print(col.toString) // check it's blue - alpha component (FF) will also be shown bmp.draw(150, 150) } static update() {} static draw(alpha) {} } - Output:
Color (#29ADFFFF)
Function CreatePicture(width As Integer, height As Integer) As Picture Return New Picture(width, height) End Function Sub FillPicture(ByRef p As Picture, FillColor As Color) p.Graphics.ForeColor = FillColor p.Graphics.FillRect(0, 0, p.Width, p.Height) End Sub Function GetPixelColor(p As Picture, x As Integer, y As Integer) As Color Return p.RGBSurface.Pixel(x, y) End Function Sub SetPixelColor(p As Picture, x As Integer, y As Integer, pColor As Color) p.RGBSurface.Pixel(x, y) = pColor End Sub
include c:\cxpl\codes; \include 'code' declarations def Width=180, Height=135, Color=$123456; int X, Y; [SetVid($112); \set display for 640x480 graphics in 24-bit RGB color for Y:= 0 to Height-1 do \fill area with Color one pixel at a time for X:= 0 to Width-1 do \(this takes 4.12 ms on a Duron 850) Point(X, Y, Color); Move(60, 60); HexOut(6, ReadPix(0,0)); \show color of pixel at 0,0 X:= ChIn(1); \wait for keystroke SetVid(3); \restore display to normal text mode ]// Rosetta Code problem: http://rosettacode.org/wiki/Bitmap // by Galileo, 07/2022 open window 200, 200 backcolor 255, 0, 0 // red clear window color 0, 255, 0 // green dot 100, 100 c$ = getbit$(100, 100, 100, 100) // get color area 1x1 pixel print c$- Output:
rgb 1,1:00ff00 ---Program done, press RETURN---
const std = @import("std"); pub const Rgb = struct { r: u8, g: u8, b: u8, }; pub const PixelOutOfBounds = error{PixelOutOfBounds}; pub const Bitmap = struct { width: usize, height: usize, pixels: []Rgb, // The ! next to the return type communicates that the function may return an error pub fn new(allocator: std.mem.Allocator, width: usize, height: usize) !Bitmap { // In Zig libraries that allocate receive an allocator // instead of choosing one themselves var pixels = try allocator.alloc(Rgb, width * height); for (0..width*height) | i | { pixels[i] = Rgb { .r = 0, .g = 0, .b = 0 }; } return Bitmap { .width = width, .height = height, .pixels = pixels, }; } pub fn free(self: Bitmap, allocator: std.mem.Allocator) void { allocator.free(self.pixels); } pub fn fill(self: *Bitmap, color: Rgb) void { for (0..self.width*self.height) | i | { self.pixels[i] = color; } } pub fn get_pixel_unchecked(self: Bitmap, x: usize, y: usize) Rgb { return self.pixels[self.height * y + x]; } pub fn get_pixel(self: Bitmap, x: usize, y: usize) !Rgb { if (self.width <= x or self.height <= y) { return error.PixelOutOfBounds; } return self.get_pixel_unchecked(x, y); } pub fn set_pixel_unchecked(self: *Bitmap, x: usize, y: usize, color: Rgb) void { self.pixels[self.height * y + x] = color; } pub fn set_pixel(self: *Bitmap, x: usize, y: usize, color: Rgb) !void { if (self.width <= x or self.height <= y) { return error.PixelOutOfBounds; } return self.set_pixel_unchecked(x, y, color); } }; test "putting a pixel gets the pixel" { var gpa = std.heap.GeneralPurposeAllocator(.{}){}; const allocator = gpa.allocator(); var bm = try Bitmap.new(allocator, 10, 10); defer bm.free(allocator); try bm.set_pixel(4, 4, Rgb {.r=255, .g=0, .b=0}); const pixel = try bm.get_pixel(4, 4); try std.testing.expectEqual(255, pixel.r); } test "filling a pixel gets all the pixels" { var gpa = std.heap.GeneralPurposeAllocator(.{}){}; const allocator = gpa.allocator(); var bm = try Bitmap.new(allocator, 10, 10); defer bm.free(allocator); bm.fill(Rgb {.r=255, .g=0, .b=0}); for (0..10) | x | { for (0..10) | y | { try std.testing.expectEqual(255, bm.get_pixel_unchecked(x, y).r); } } }This solution creates a PPM image. No error checking or clipping.
class PPM{ // (0,0) is logically bottom left fcn init(width,height){ sz:=width*height*3; var [const] data=sz.pump(Data(sz),0), // initialize to Black (RGB=000) w=width, h=height; } fcn fill(rgb){ sz:=data.len()/3; data.clear(); sz.pump(data,T(Void,rgb.toBigEndian(3))); } fcn __sGet(x,y) { data.toBigEndian(3*y*w + 3*x,3); } //ppm[x,y] fcn __sSet(rbg,x,y){ data[3*y*w + 3*x,3]=rbg.toBigEndian(3); } //ppm[x,y]=rgb fcn write(out){ // write bottom to top to move (0,0) from bottom left to bottom left out.write("P6\n#rosettacode PPM\n%d %d\n255\n".fmt(w,h)); [h-1..0, -1].pump(out,'wrap(h){ data.seek(3*h*w); data.read(3*w) }); out.close(); } }ppm:=PPM(256,256); ppm.fill(0x00FF88); foreach x in ([50..200]){ ppm[x,50]=0xff|00|00; } // horizontal red line ppm.write(File("foo.ppm","wb"));- Output:
$ zkl hexDump foo.ppm | less 0: 50 36 0a 23 72 6f 73 65 | 74 74 61 63 6f 64 65 20 P6.#rosettacode 16: 50 50 4d 0a 32 35 36 20 | 32 35 36 0a 32 35 35 0a PPM.256 256.255. 32: 00 ff 88 00 ff 88 00 ff | 88 00 ff 88 00 ff 88 00 ................ 48: ff 88 00 ff 88 00 ff 88 | 00 ff 88 00 ff 88 00 ff ................ 64: 88 00 ff 88 00 ff 88 00 | ff 88 00 ff 88 00 ff 88 ................ 80: 00 ff 88 00 ff 88 00 ff | 88 00 ff 88 00 ff 88 00 ................ ...
- Programming Tasks
- Raster graphics operations
- 11l
- Action!
- Action! Bitmap tools
- ActionScript
- Ada
- ALGOL 68
- Applesoft BASIC
- ARM Assembly
- ATS
- AutoHotkey
- Axe
- BASIC
- BASIC256
- BBC BASIC
- C
- C sharp
- C++
- Boost
- Clojure
- Common Lisp
- Crystal
- D
- Delphi
- SysUtils,StdCtrls
- E
- EchoLisp
- Elixir
- Erlang
- Euphoria
- F Sharp
- Factor
- FBSL
- Forth
- Fortran
- FreeBASIC
- FutureBasic
- Go
- Haskell
- Icon
- Unicon
- J
- Java
- AWT
- JUnit
- JavaScript
- Julia
- KonsolScript
- Kotlin
- Lingo
- LiveCode
- Lua
- M2000 Interpreter
- Maple
- Mathematica
- Wolfram Language
- MATLAB
- MAXScript
- MiniScript
- Modula-3
- Nim
- OCaml
- Octave
- OxygenBasic
- Oz
- Pascal
- Perl
- Imlib2
- Phix
- PHP
- PicoLisp
- PL/I
- Pluto
- Pluto-bitmap
- POV-Ray
- Processing
- Prolog
- PureBasic
- Python
- QBasic
- R
- Pixmap
- Racket
- Raku
- RapidQ
- REXX
- Ruby
- Rust
- Scala
- Scheme
- Seed7
- SequenceL
- Smalltalk
- Tcl
- Tk
- TI-89 BASIC
- Uiua
- UNIX Shell
- Vedit macro language
- Visual Basic .NET
- Wren
- DOME
- Xojo
- XPL0
- Yabasic
- Zig
- Zkl
- AWK/Omit
- PARI/GP/Omit
- Pages with too many expensive parser function calls

