2
votes

I would like to be able to render a bitmap image superimposed with boundaries between pixels (the color of the boundary results from a home made routine). On zoom and pan the tickness of the boundary should remain the same.

Here is an example image: Image showing how boundary thickness remais unchanged with magnification

For zoom and pan, I'm using graphics32 as described here To draw the boundaries, I thought of using AggPasMod to make a vector image for Delphi 2010, XE, XE2 ... which was updated by Christian Budde here.

However I'm struggling to have both tools interacting since AggPasMod works with its own type of image: TAgg2DImage which I don't know how to plot in Timage and graphics32 allows ploting of TBitmap.

Since I'm no coding expert, I would really appreciate to have some advice on the best way to solve that problem.

Thanks in advance,

2
From your images you just appear to be drawing lines over a pixilated bitmap (i.e. the pixels are not separated by the lines but partially obscured by them). Is this intentional or an artifact of the drawing tool you have used to show us what you intend? Either way I would not do it the way you propose but draw each pixel as a square on the canvas, with lines drawn separately for the edges, which is easier than I suspect you imagine.Dsm
@Dsm: The presented images are just an example, real data would contain more than 3M Pix. I though that is would quicker to zoom in a vector image that redraw the boundaries each time the "zoom" is called. Since the zoom is controled by mouse wheel, one "long" roll of the mouse wheel may imply that the image should be recalculated 3-4 timesLionel Germain
If you are keeping the boundaries a constant width you need to redraw. You only need to redraw the visible pixels so image size doesn't really come into it. I guess you only want to draw boundaries with zoom beyond a certain size - otherwise all you see is boundary. Below that size just use normal image drawing - above that size do a pixel by pixel draw with boundaries. If you have a graphics processor drawing a square and two or 4 lines for edges is very fast because that is all handled in parallel by the graphics processor.Dsm
I understand that imagine drawing a vector graphic over an image would be faster, but in this case KISS is better (IMHO). The vector graphic would be quite complex here, and relatively slow to draw.Dsm
may imply that the image should be recalculated 3-4 times: you could add a timer to circumvent that. See also: How To Zoom with keeping aspect ratio correctly.NGLN

2 Answers

3
votes

You may want to use the latest (beta) version 2.0 of GR32 as it introduced a vector engine. With this you can continue to use your existing code and add vector graphic drawn on top of the pixel image you already have.

To do so first switch to the latest GR32 version. The code can be obtained from the open SVN repository. The trunk can be found here:

https://sourceforge.net/p/graphics32/code/HEAD/tree/trunk/

If you use SVN (recommended) you can check out the code using

svn checkout svn://svn.code.sf.net/p/graphics32/code/trunk graphics32-code

or use TortoiseSVN for explorer integration.

Once you have the code you can start exploration. There are many examples which show you how to use the vector engine. Just look at the examples under Examples\Drawing.

In particular have a look at the 'Polygons' example where you can create (and manipulate) polygons with the mouse (three clicks are required to create a simple triangle).

To create a vector graphic on your own you can use code like this:

uses
  ..., GR32_Polygons, GR32_Paths, GR32_Brushes;

var
  Canvas: TCanvas32;
  Stroke: TStrokeBrush;
begin
  // use a higher level abstraction class to generate the polygons
  Canvas := TCanvas32.Create(Image.Bitmap);

  // add a stroke brush and specify the color and width
  Canvas.Brushes.Add(TStrokeBrush);
  Stroke := TStrokeBrush(Canvas.Brushes[0]);
  Stroke.FillColor := SetAlpha(clBlack32, 200);
  Stroke.StrokeWidth := 2;

  // begin a path
  Canvas.Path.BeginPath;

  // specify 3 vertices
  Canvas.Path.MoveTo(10, 10);
  Canvas.Path.LineTo(20, 90);
  Canvas.Path.LineTo(60, 40);

  // close path
  Canvas.Path.ClosePath;
  Canvas.Path.EndPath;
end;

Additionally you can use the low level API. For this you only need the unit 'GR32_Polygons'. The same code would then look like this:

uses
  ..., GR32_Polygons;

var
  Points: array of TFloatPoint;
begin
  SetLength(Points, 3);

  // specify 3 vertices
  Points[0] := FloatPoint(10, 10);
  Points[1] := FloatPoint(20, 90);
  Points[2] := FloatPoint(60, 40);

  // draw poylgon with certain color and width
  PolylineFS(Image.Bitmap, Points, SetAlpha(clBlack32, 200), True, 2.0);
end;

While this looks simpler in the first place it gets slightly more difficult the more complex your drawings with the vector engine get.

To get rid of entering each vertex separately you can use auxiliary functions from the GR32_VectorUtils unit. It includes

Rectangle(const R: TFloatRect): TArrayOfFloatPoint;

which should be the most useful for your application.

If you want you can also add transformations that are applied before the polygon is drawn.


The same example could also be written entirely using the AggPas code. It's neither faster nor more elegant, but just different.

2
votes

Seeing how you generate the vector image yourself, you could do the following:

  1. Render the main background image on a TBitmap or TBitmap32, save the zoom and panning used here.
  2. Instead of making a vector image save the vector to an array of lines.
  3. Walk the array of lines and do a TBitmap.Canvas.Draw for every line that intersects the clipping rectangle. And don't forget to correct for the clipping offset and zoom when drawing these lines.

    (when zoomed in x2 your lines will be twice as long and start twice as far from the top and left, when panned 50 from the left you draw your line at line.start.x-50 etc...)

You are now drawing over the output image, this allows you to change your line width independent of the background image zoom amount.

Instead of only drawing on the clipping region you can of course render draw the entire bitmap with lines and just redraw when you need a different zoomlevel or line-width. But seeing how you you can have 3MP images it might be faster to only render sections as you display them.

Let me know if you need more information, good luck :)