Lazarus

Programming => Graphics => Graphics and Multimedia => BGRABitmap and LazPaint => Topic started by: sjkn on April 20, 2020, 01:04:09 pm

Title: Use TGreyscaleBitmap as mask (where is the type)?
Post by: sjkn on April 20, 2020, 01:04:09 pm
Hi everyone - this is my first post here, I hope I did not miss any obvious rules or conventions of this board.
My first question is also an embarrassingly basic question:

I wanted to use a mask on a TBGRABitmap, which works fine with another TBGRABitmap. But the wiki startpage of BGRABitmap teases with this:
Quote
As of version 10, additional bitmap types are available:
...
TGrayscaleBitmap: linear 8 bit grayscale. It now has drawing functions, so you can prepare a mask in 8 bit per pixel, avoiding to consume memory.
...

Where can I find the type TGrayscaleBitmap? I just get an "Error: Identifier not found "TGrayscaleBitmap"" (with BGRABitmap and BGRABitmapTypes in the uses clause) when i want to declare a TGrayscaleBitmap variable. So which unit do I have to add, or is there something else entirely to it? I should mention that I tried both with the latest version of the package from github (10.8.1 if i remember correctly) as well as the one I got from the Online Package Manager, which is 10.6.5.   

I think I have exhausted google regarding this, the only mention of the type I could find is the quoted line from the wiki.

Thanks!
Sebastian
Title: Re: Use TGreyscaleBitmap as mask (where is the type)?
Post by: circular on April 20, 2020, 02:55:59 pm
Hi!

The class TGrayscaleMask is in the unit called BGRAGrayscaleMask. It can be created as a regular bitmap though it has less functions.

It is kind of a novelty so I am happy to get some feedbacks about it. If you miss one function, feel free to ask here and we'll see what we can do.

Regards
Title: Re: Use TGreyscaleBitmap as mask (where is the type)?
Post by: Roland57 on April 20, 2020, 06:28:08 pm
Interesting. I hadn't heard of that new class.

@sjkn
Welcome to the forum!
Title: Re: Use TGreyscaleBitmap as mask (where is the type)?
Post by: circular on April 20, 2020, 07:22:46 pm
Oh ok

So there are various formats, they all derive from TGenericUniversalBitmap.
- TGrayscaleBitmap: 8-bit grayscale (Byte)
- TBGRABitmap : BGRA/RGBA 32-bit, each channel is 8-bit (Byte)
- TExpandedBitmap : RGBA 64-bit, each channel is 16-bit (Word)
- TLinearRGBA : RGBA 128-bit, each channel is 32-bit float (Single)
- TWordXYZABitmap : XYZ colorspace, each channel is 16-bit (Word)
- TXYZABitmap : XYZ colorspace, each channel is 32-bit float (Single)

XYZ colorspace allows to use more colors of the gamut, like Lab colors. That can be useful to manipulate RAW photos without loosing deep colors. In HSL terms, you can have more saturated colors. In the end, if you show it on the screen, you need to reduce to RGB. Though there are some colors that you can print but that you cannot display, so that can be useful for that.

You can have a look at the colorspaces with these sample applications:
https://github.com/bgrabitmap/bgrabitmap/tree/master/test/colorspace
Title: Re: Use TGreyscaleBitmap as mask (where is the type)?
Post by: sjkn on April 23, 2020, 12:42:00 pm
Hi and thanks for the great replies and warm welcome :)

I must admit I missed that unit when just briefly going through the folder.

Regarding wishes for functions: Right now I am just beginning to get an overview over all the possibilities. The library is seriously impressive (and I am new to it)!
One thing I was running into is that I can't figure out how to fill a mask with a gradient. For TBGRABitmaps, I  I create a TBGRAMultigradient, fill it with colors (and, most importantly for me at this point, alpha values), and then, with it, I create a TBGRAGradientScanner that I use to fill the bitmap.

Code: Pascal  [Select][+][-]
  1. multigrad := TBGRAMultigradient.Create(colors,positions,false);
  2. grad := TBGRAGradientScanner.Create(multigrad, PointF(PSFRad,PSFRad), PSFRad, PointF(PSFRad,PSFRad), 1);
  3. PSF.Fill(grad);  //PSF is a TBGRABitmap
  4.  

I don't know whether I use these structures as intended, or whether there are more elegant ways, but it works. However, I can't do the same with GrayscaleMasks (no overloaded version of Fill that takes a BGRAGradientScanner). I could use a Brush instead, but then I would have to create a 32 bit image again, defeating the purpose of using the 'lighter' GrayscaleMask.
So my question is: Is there a good way to fill a GrayscaleMask with a multigradient? It might very well be that I am just not seeing an obvious alternative, as I said, I just started using the library :)

Just as background: What I am working on is a program that plots stars in a way that you could print and make a celestial globe out of it. The output is an SVG file and I make heavy use of transparency gradients. For a preview, I want to mimic the gradients generated in SVG - that's why I really like the TBGRAMultiGradient, because it works exactly the same way as the SVG gradients with "stop-offset" and "stop-color", making it easy for me to render the stars exactly as an SVG engine would, and since all the elements are customizable and optional (e.g. the halo and the diffraction spikes of a star), I like that I can draw them independently over each other with transparency masks (see attached image).

EDIT: Maybe I should add that I obtained the desired result also without a mask, by directly setting the alpha values in the multigradient (another thumbs up for this!). However, this means that I have to make a new gradient for every single star (sequentially, not all at the same time), because none of them have exactly the same color. And the catalog I am currently using has 100,000+ stars, so that is a lot of gradients. Hence I thought it would be good to just make a mask once and use it on all the stars when rendering, just like I only define the transparency mask once in the SVG and refer to it afterwards. But maybe I am also overthinking this and the TBGRAMultigradient TBGRAGradientScanner classes are fast to create? On top of that, this currently is mostly curiosity, since I'm at the moment only rendering a few stars for the preview. It might be more relevant if I decide to also add direct output of a raster image instead of the vector graphic. BGRABitmap seems to have all the functionality I'd need for that!   

 
Best wishes, Sebastian

PS: This is still related to the GrayscaleMask type, but if you feel this is getting too far away from the topic I'll open a new one!
Title: Re: Use TGreyscaleBitmap as mask (where is the type)?
Post by: circular on April 23, 2020, 03:30:26 pm
Nice rendering of a star.  :)

The Fill function takes another parameter which is the draw mode. In this case, it doesn't really matter if you use dmSet or dmDrawWithTransparency.
Code: Delphi  [Select][+][-]
  1. gray.Fill(grad, dmSet);  //gray is a TGrayscaleMask

TBGRAGradientScanner implements IBGRAScanner, so it can be used for most filling operations.

Quote
I don't know whether I use these structures as intended, or whether there are more elegant ways, but it works.
You are using it as it was intended.

Then to render the mask with color:
Code: Delphi  [Select][+][-]
  1. PSF.FillMask(0,0, gray, CSSRed, dmDrawWithTransparency);
TinyPortal © 2005-2018