2

I'm using Graphics32 for image processing. Looking at its capabilities, it strikes me that I've yet to see a proper implementation of a clipping mask. I do see the term "clipping" pop up here and there, but it seems to refer to something else.

Simply put, I need one layer to function as a "peeking hole" to another; layer A should be projected onto layer B, but only where layer B is visible. (I see no further need to redefine what a clipping mask is.)

If it were just the bitmap of that other layer that I'd like to present, it wouldn't be so hard to do - then I could use this trick - but what complicates things, is that the bitmap of a layer does not tell much about what would be displayed by the layer; the layer can be:

  • (partially) invisible (when out of the view)
  • moved/stretched + optionally resampled
  • rotated

with no effects on its bitmap.

Is it actually so that there is no ready implementation for this? Any suggestions for doing this myself?

Progress

I found some useful elements in the source of Graphics32. For example, using this declaration:

type
  TLayerAccess = class(TBitmapLayer);

to gain access to protected methods, I can call TLayerAccess(ABitmapLayer).Paint(ABitmap32) to have just this layer painted to a bitmap, exactly as it would to the screen.

Thijs van Dien
  • 6,516
  • 1
  • 29
  • 48
  • graphics32 uses 32nit bitmaps solely and it's the alpha channel of the bitmap that is used for blending. I do not know of another alpha field you can use (eg clipping area etc). You only have another "master alpha". I would. 1. determine alpha bitmap (all white, alpha channel is the clipping path in bitmap coordinates), multiply original bitmap into this one and then render bitmap into destination. – Ritsaert Hornstra Jan 22 '12 at 21:35
  • How do you define what portions of layer B are visible ? – iamjoosy Jan 23 '12 at 15:55
  • @iamjoosy By where I can see it when it is drawn to the container (TImage32). – Thijs van Dien Jan 24 '12 at 00:12

2 Answers2

0

I have looked into this myself a year ago, and quickly resorted to using a black layer with transparent parts. It suited my then needs. But what you want is possible..

You want to couple one TBitmapLayer to another and consider it its mask. I want to avoid these references however (and its potential problems and Graphics32 rework) and see this only as a last resort.

There is a way to do without a dedicated TBitmapLayer, using your own pixel combiner. But it doesn't know about TBitmapLayers and its XY pixels.

To proper occlude (or leave out) parts of a TBitmapLayer while drawing to screen, you could use create a method of type TPixelCombineEvent and assigning this as its OnPixelCombine and setting TBitmapLayer.DrawMode to dmCustom.

Inside that TPixelCombineEvent method you decide what pixels result given the background B and the foreground F given the current M master alpha.

procedure TMyObj.MyPixCombine(F: TColor32; var B: TColor32; M: TColor32);
begin
  if not PseudoThisPixelShouldBeMasked then B := F; // ugly and aliased
end;

Problem here is, that (the pseudo code) PseudoThisPixelShouldBeMasked doesn't really know what pixel this concerns and whether it is inside a mask. So you'd have to extract that value from a component of F, such as its Alpha value.

Back then i opted for the quite fast B := ColorMin(F,B); where F is black or white. This layer is on top always and results in black instead of transparent masks however. This because any rendering to the TBitmapLayer would destroy the mask data and i need to reapply it. Using a TByteMap however as suggested below (who downvoted that?) by iamjoosy might be interesting, perhaps that performance penalty turns out negligible.

Barry Staes
  • 3,890
  • 4
  • 24
  • 30
0

Have a look at TByteMap and its writeTo method.

iamjoosy
  • 3,299
  • 20
  • 30