the Xbitmap class


This is version 2 of my XBitmap class.
The colorselector is replaced.
Errors showing up under Delphi-10 are resolved.

The Xbitmap class adds following drawing options to the Bitmap class:
    1. dash-dot lines with a penwidth of 1 to 32 pixels
    2. lines with arrows at begin,end or both (16 arrow types selectable)
    3. 4 levels (0..3) of drawing
    4. xdot[x,y] method for fast drawing of dots in selected penwidth
    5. improved stretchdraw method
    6. clipping rectangle
    7. fast direct access to individual pixels with the xpixel[ ] method
    8. floodfill styles of 8 x 8 or 24 x 24 pixels, 16 styles selectable
    9. modification rectangle : the area that changed during the last operation

Creation and pixelformat.

To create a xbitmap:
var myxbitmap : TXbitmap;
 myxbitmap := TXbitmap.create;
 with myxbitmap do
   width := 600;
   height := 400;
Do not use the pixelformat property.
Xbitmap only operates in the pf32bit mode and this is included in the setting of width and height.

The extra properties and methods are added to the Bitmap class, not to the canvas.

In the pf32bit pixelmode, the position of the red and blue fields in a 32 bit word are swapped compared to
the Windows color format.
    Windows vs pf32bit color format
To trade the red and blue fields in a 32 bit word use:
function swapcolor(c : DWORD) : DWORD;
where c is the color.

For the xpencolor and xbrushcolor properties, the Windows format is used and the RB colorfields are
traded internally.
For the xpixel[ , ] method, the color is in pf32bit format for speed purposes.

Internally, Xbitmap modifies pixels using pointers to the pixel location in memory.
Therefore it needs the pointer to row 0, column 0 and the increment value of a pointer to the next row.
These values are obtained by method xadjust when setting width or height, using the scanline[ ] property twice.

Loading the Xbitmap from memory:
with myxbitmap do
  xadjust; //restores the pf32bit property
After a loadfromfile, xadjust must be called to insure that the pixelformat is pf32bit and to recalculate
the pointer to (0,0) and the row increment value.

Note: Pixels in a (x)bitmap are located in the computer memory and are therefor not visible.
To make a (x)bitmap visible it has to be copied to a screen canvas (such as a paintbox).
Use the canvas.draw(x,y,sbm) to copy an entire bitmap or the canvas.copyrect(dr,scv,sr) method
for a partial copy where:
    x, y : screen coordinates
    sbm : the source bitmap
    dr : destination rectangle
    scv : the source canvas
    sr : the source rectangle

1. dash-dot lines

Lines, ellipses and arcs may be drawn solid or dash-dotted.
The penwidth is selectable from 1 to 32 pixels.
The fatter lines are mainly needed when drawing on a bitmap that is later copied to a printer canvas.
For printers with a horizontal resolution of 2400 pixels, dimensions will be multiplied by 3 in general,
to obtain the same drawing size as on the screen.

The property xpenstyle selects the dash-dot pattern
    0 : solid
    1..19 dash-dot styles
Figure 1 shows the dash-dot styles for a penwidth of 3
Example: draw a line with style of 10, width of 3 from (20,40) to (120,40):
 with myxbitmap do
   xpenwidth := 3;
   xpenstyle:= 10;

2. arrows

Lines and arcs may have an arrow at begin or end.
There are 16 selectable arrow shapes : 4 widths and 4 lengths combined.
Fig2. below shows all arrow styles for a penwidth of 2
The type of arrow (or no arrow) is set in property xarrowcode: (see figure 3)
Bits 0,1 together with the xpenwidth make the width of the arrow.
Bits 2,3 together with the xpenwidth make the length of the arrow.

see example below
    with myxbitmap do
      xpenwidth := 5;
      xpenstyle := 11;
      xarrowcode := $cf;

3. drawing levels (0..3)

Each pixel has a level. Level 0 is the highest- , level 3 is the lowest level.
The properties xpenlevel and xbrushlevel set the level of the pen or the brush.
A lower level pen or brush cannot alter a higher level pixel.
The level is coded in bits 0,1 of the blue color field so, bits 0 an1 of the pf32bit pixel represent the level.

Levels could be used in a drawing as
    - 3: for system backgrounds
    - 2: for user supplied backgrounds
    - 1: grids
    - 0: user supplied lines, ellipses etc.
Example below shows a possible effect:
    with myxbitmap do
      xpenwidth := 10;
      xarrowcode := 0;
      xpenstyle := 0;
      xpenlevel := 0;
      xpencolor := $000000;//black
      xpenlevel := 1;
      xpencolor := $0000ff;//red
      xpenlevel := 2;
      xpencolor := $00ff00;//green
      xpenlevel := 3;
      xpencolor := $ff0000;//blue
The black line is written at first with the highest level (0).
The other colors have a lower level and never overwrite the black line.

4. xdot[x,y] method for fast drawing of dots in selected penwidth

xdot(x,y) draws a dot at position (x,y) using the selected pencolor and penwidth.
This method is much faster than if using an ellipse. figure below shows some dots:
with myxbitmap do
  xpenwidth := 10;
  xpencolor := $000000;//black
  xpencolor := $ff0000;//blue
  xpenwidth := 32;

5. improved stretchdraw method

The xstretchdraw method copies a source bitmap while adjusting it's width and/or height.
xstretchdraw may operate in two modes:
    fullsource (xstretchmode = smFullSource)
    full destination (xstretchmode = smFullDest)
In fullsource mode, the source image is adjusted to fit the destination rectangle.
No part is lost. Part of the destination rectangle may not be covered.
In full destination mode, the destination rectangle is fully covered but a part of the
source rectangle may be lost.
var rs,rd : Trect;//source, dest rectangle;
      bm : Tbitmap;	//imported 500*350 
with myxbitmap do
  rd := rect(20,20,300,500);
  rs := rect(bm.left,,bm.width,bm.height);
  //full bitmap
  xstretchmode := smfullsource;
  rd := rect(320,20,600,500);
  xstretchmode := smfulldest;
left: fullsource, right:fulldest...

6. clipping rectangle

Sometimes lines, circles or arcs must be limited to a predefined rectangle.
In the xbitmap class, this rectangle is the xcliprect : Trect property.
Default, xcliprect is the full width and height of the bitmap.
Drawing outside the xcliprect is not possible (for xline, xellipse, xarc....methods).
Picture below shows some effects:
with myxbitmap do
  xcliprect := rect(20,20,250,250);
  xpenwidth := 20;
  xpencolor := $000000;
  xpencolor := $0000ff;
clipping rectangle example...

7. fast direct access to individual pixels with the xpixel[ ] method

The bitmap canvas has the pixel[x,y] property to read or write individual pixels.
This method is very slow because windows is called to do the job.
The xpixel[x,y] property is at least 40 times faster. The pixel is addressed directly in memory.
pf32bit colors are used, so conversion to/from the windows format must be done by
the function swapcolor(c : DWORD) : DWORD;

8. floodfill styles of 8 x 8 or 24 x 24 pixels, 16 styles selectable

xfloodfill(x,y) fills the area within a shape with a selected fill pattern.
The shape must be bound by pixels of colorlevel 0.
Below are the selectable shapes
property xfillstyle : byte;//0..15
selects the pattern.
xfillmapsize : Txfillmapsize;//selects fms8 or fms24 
the size of the filling tiles.
Use fms8 for the screen and fms24 if the bitmap is to be copied to a printer canvas.

9. modification rectangle.

When a line, ellipse, drawn a certain rectangle of the bitmap is changed.
To make this change visible it must be copied to a paintbox.
Only the modified part needs copying and this part is property xmodrect (type Trect).
Xmodrect is updated after each Xbitmap action.

Sometimes rectangles of several drawing actions have to be combined.
Use the unirect function to accoplish this.
  r := unirect(r,xmodrect);//combines r and xmodrect
Other functions provided that operarte on rectangles
  function InterRect(var r1,r2 : Trect) : Trect;//common part of rectangles
  function PackRect(x1,y1,x2,y2 : integer) : Trect;//coordinates to rectangle

type definitions in Xbitmap

type  PDW = ^DWORD;
      TXFillMapSize = (fms8,fms24);
      TXstretchmode = (smFullSource,smFullDest);

methods in Xbitmap

  Xpixel[x:integer; y:integer]:DWORD;
  Xdot(x,y : integer);
  Xline(x1,y1,x2,y2 : integer);
  Xellipse(x1,y1,x2,y2 : integer);
  Xarc(x1,y1,x2,y2,x3,y3,x4,y4 : integer);
  Xpolygon(var pa : array of Tpoint);
  XfillRect(x1,y1,x2,y2 : integer; r : byte);
  Xfloodfill(x1,y1 : integer);
  XstretchRect(drt : Trect; sbm : TXBitmap;srt : Trect);
XpixPos[x,y] reads the pointer location of the pixel.

XfillRect draws a rectangle with rounded angles (0 for sharp angles) and fills with xbrushcolor.

properties in Xbitmap

   XpenWidth : byte;
   Xpencolor : DWORD;
   XLineStyle : byte;
   Xbrushcolor : DWORD;
   Xpenlevel : byte;
   Xbrushlevel : byte;
   XFillMapSize : TXFillMapsize;
   XfillStyle : byte;
   XarrowCode : byte;
   XClipRect : Trect;
   XUseBrush : boolean;
   Xstretchmode : TXstretchmode;
   XModRect : Trect;
Xusebrush is true for the filling of rectangles or ellipses and is false for no filling.

The Xbitmap project

Programming language is Delpi-3.
However, the xbitmap class fits any Delphi version.
The project has the following units:
    unit1: Exerciser. Event trapping and Components
    controlunit: settings,selections, handling of events
    xbitmap : the xbitmap class, type definitions and some support procedures
The exerciser allows to explore all the features of the xbitmap class.
The form is self explanatory.
Some remarks:
The shape of a polygon may be changed by positioning the mousepointer over an angle,
pressing the mousebutton and moving.
Hold the "shift key" for 1 pixel increments instead of 10 pixel increments.

The exerciser draws pictures in the xcliprect, so first paint the xcliprect before importing a picture.
The xcliprect may the be redimensioned by placing the mousepointer over an angle
and proceding as in 1.

Custom components

The exerciser uses two of my own components:
    - davArrayBtn (an array of buttons)
    - colorpicker (a grid of colors for color selection)


Click below to download: