Lazarus

Programming => Graphics => Graphics and Multimedia => BGRABitmap and LazPaint => Topic started by: evoshroom on June 11, 2012, 10:13:13 am

Title: Basic Use of BGRAVirtualScreen with BGRALayerBitmap
Post by: evoshroom on June 11, 2012, 10:13:13 am
Been trying to gett BGRAVirtualScreen and BGRALayerBitmap working all night with no luck.  I tried to follow the tutorials on the lazarus wiki but they don't cover either of these topics.  For what they did cover, they were helpful though.

I've gone through like a billion iterations of code trying to guess what will work, but nothing ever draws to the VirtualScreen.  Is there a tutorial out there that shows basic usage of the VirtualScreen with a LayeredBitmap?  If not can you tell me what I'm doing wrong if it is obvious?  My basic code was something like:
Code: [Select]
DisplayBitmap := TBGRALayeredBitmap.Create(233,328);
DisplayBitmap.AddLayerFromFile(ExtractFilePath(Application.Exename) + LinSafe('GUI\') + 'Blue' + '.jpg');
DisplayBitmap.LayerOpacity[0] := 128;
DisplayBitmap.LayerVisible[0] := true;
DisplayBitmap.AddLayerFromFile(ExtractFilePath(Application.Exename) + LinSafe('GUI\') + 'Red' + '.jpg');
 DisplayBitmap.LayerOpacity[1] := 128;
DisplayBitmap.LayerVisible[1] := true;   
DisplayBitmap.ComputeFlatImage.Draw(BGRAVirtualScreen1.Canvas, 0, 0);   
LinSafe just swaps \ with / for Windows/Mac/Linux compatibility.

Any help will be appreciated!  Thanks!
Title: Re: Basic Use of BGRAVirtualScreen with BGRALayerBitmap
Post by: circular on June 11, 2012, 06:48:42 pm
I suppose that the problem here is not about layers, but about the way virtual screen works. To draw on it, you need to define a handler for the OnRedraw event. In this event, you have a bitmap parameter that you can modify. If instead you draw on the Canvas, it will be erased as soon as the virtual screen is invalidated.

So instead of
Code: [Select]
DisplayBitmap.ComputeFlatImage.Draw(BGRAVirtualScreen1.Canvas, 0, 0);
Write something like
Code: [Select]
tempBmp := DisplayBitmap.ComputeFlatImage;
Bitmap.PutImage(0,0,temp);
tempBmp.Free;

Or even shorter :
Code: [Select]
DisplayBitmap.Draw(Bitmap,0,0);
If you want the virtual screen to be redrawn, call BGRAVirtualScreen1.RedrawBitmap.
Title: Re: Basic Use of BGRAVirtualScreen with BGRALayerBitmap
Post by: evoshroom on June 11, 2012, 11:33:47 pm
Ah, that does work better.  At least I can draw something now.  I did try PutImage() as well before, but it turned out the problem was I had a BGRAVirtualScreen1.RedrawBitmap right after it, which cleared what I drew.  So I have a couple more questions.

Since BGRAVirtualScreen1.RedrawBitmap clears whatever I draw, how do I actually get it to draw?  Currently I only see what I draw when I move the form and if I call BGRAVirtualScreen1.RedrawBitmap I don't see it at all ever.

Does tempBmp.LoadFromFile() work the same as DisplayBitmap.AddLayerFromFile(), because now that you have me using the tempBmp, (which I defined as a TBGRACustomBitmap) I was trying to load images into it for resampling before I put them in the layers of DisplayBitmap, but I get an error when I try to load my files (jpgs and pngs) into tempBmp even though the same stuff seems to work fine with DisplayBitmap.AddLayerFromFile().

Also, I noticed resampling uses a TBGRACustomBitmap instead of a TBGRADefaultBitmap.  Can I just swap between these two using (defBmp as TBGRACustomBitmap).Resample(50,50); for example, or should I be doing something more involved?

Thanks for all the help!
Title: Re: Basic Use of BGRAVirtualScreen with BGRALayerBitmap
Post by: evoshroom on June 12, 2012, 12:00:22 am
Basic code I'm using now.  I get an error on the first call to tempBmp.LoadFromFile().

Code: [Select]
DisplayBitmap := TBGRALayeredBitmap.Create(BGRAVirtualScreen.Width,BGRAVirtualScreen.Height);
tempBmp := TBGRACustomBitmap.Create(BGRAVirtualScreen.Width,BGRAVirtualScreen.Height);  //really this should
//actually be the size of BB.png, but just using this size for testing to see if i can get it to work at all
...
tempBmp.LoadFromFile(ExtractFilePath(Application.Exename) + LinSafe('GUI\') + 'BB' + '.png');
tempBmp := tempBmp.Resample(DisplayBitmap.Width,DisplayBitmap.Height);
DisplayBitmap.AddLayer('Border',(tempBmp as TBGRABitmap),boLinearBlend,255);
DisplayBitmap.LayerVisible[0] := true;
...
tempBmp.LoadFromFile(ExtractFilePath(Application.Exename) + LinSafe('GUI\') + 'Blue' + '.jpg'); 
tempBmp := tempBmp.Resample(Round(DisplayBitmap.Width*0.93),Round(DisplayBitmap.Height*0.96));
DisplayBitmap.AddLayer('Background',(tempBmp as TBGRABitmap),Point(Round(DisplayBitmap.Width*0.07),Round(DisplayBitmap.Height*0.04)),boLinearAdd,255);
DisplayBitmap.LayerVisible[1] := true;
...
tempBmp := DisplayBitmap.ComputeFlatImage;
BGRAVirtualScreen.Bitmap.PutImage(0,0,tempBmp,dmSet);
tempBmp.Free;
DisplayBitmap.Free;     
Title: Re: Basic Use of BGRAVirtualScreen with BGRALayerBitmap
Post by: circular on June 12, 2012, 04:45:55 pm
If you have a TBGRACustomBitmap and you need a TBGRABitmap parameter, you can write (... as TBGRABitmap).

If you have a TBGRABitmap and need a TBGRACustomBitmap, you don't need to do anything because TBGRABitmap is a descendant of the custom one (might not sound logicial, but it's Lazarus terminology).

To load a bitmap from file, either do
Code: [Select]
tempBmp := TBGRABitmap.Create;
tempBmp.LoadFromFile...
or
Code: [Select]
tempBmp := TBGRABitmap.Create(filename);
Title: Re: Basic Use of BGRAVirtualScreen with BGRALayerBitmap
Post by: evoshroom on June 12, 2012, 05:42:19 pm
That was also helpful and changed my code for the better yet again, though several aspects still aren't working.  For example, instead of calls to BGRAVirtualScreen.RedrawBitmap; refreshing what I draw, BGRAVirtualScreen.RedrawBitmap; simply keeps the Bitmap in its original white state.  The only way I've been able to see anything I draw is by moving the form and then only the first thing I draw.

How is refresh handled?  Also keep in mind I'm on OS X if that matters for any of these questions.
Title: Re: Basic Use of BGRAVirtualScreen with BGRALayerBitmap
Post by: evoshroom on June 12, 2012, 05:58:17 pm
Apparently I answered my own question as BGRAVirtualScreen.Refresh worked. :)
Title: Re: Basic Use of BGRAVirtualScreen with BGRALayerBitmap
Post by: evoshroom on June 13, 2012, 09:43:17 pm
Okay, that all helped very much and I have almost everything for this application working.  I'm converting some applications from Graphics32 to BGRA, and have to say I'm pretty impressed so far.  BGRA has more options, a better font renderer, is more cross-platform, seems faster and the graphics code shrunk to one-third the size it was.  Damn good.

The only issues I seem to have had are with transparent PNG's and with redrawing on app opening, resizing, moving, etc.

As for the PNGS, I'm creating a layer-by-layer composition and the second layer loaded has some transparent bits that are supposed to show through to the first layer loaded.  However, that isn't what occurs.  The final merged output shows black in the transparent areas.  How can I get the transparency to work when I load a PNG into a BGRABitmap, put it into a BGRALayeredBitmap Layer and then get the output via ComputeFlatImage?

As for the redrawing, Graphics32 used to not delete what you drew when you resized the form.  So I setup some of the initial draws in OnCreate and they were there when the form first was revealed.  If I do that with BGRA they do not show up when the form is revealed.  Also, I can't seem to draw anything in Form1.FormResize and get it to show up.  How can I get things to draw while the form is resizing or before/when the form is first drawn.  Basically, I don't want the last image I drew to vanish when the user moves the form or resizes it or a TBGRAShape is made visible, etc.  It seems to redraw the form on certain events and then, *poof,* whatever I drew last in the TBGRAVirtualScreen is gone.  How do I get it to stay?
Title: Re: Basic Use of BGRAVirtualScreen with BGRALayerBitmap
Post by: circular on June 14, 2012, 10:21:41 am
Thanks. I'm not sure if BGRABitmap is faster, but it may be simpler to use. Can you give some example of code that became reduced when converted from Graphics32 ?

The PNG loader of FreePascal seems to be buggy. So maybe the transparency isn't loaded at all. Try to save it in another PNG format (8-bit, 16-bit, indexed) or in TIFF, to see if it is a format issue.

If you want to keep some image, you need to store it in an image. Basically, your image cannot be kept in the virtual screen if its size change. For example if you draw at (200,200) and the virtual screen is reduced to (100,100) then what was at (200,200) simply does not exist anymore.

So for example, create your image (img: TBGRABitmap), let's say 400x400 that contains your drawing. In the OnRedraw event, call Bitmap.PutImage to draw it on the virtual screen.

When you want to change your image, draw on it, and call VirtualScreen.RedrawBitmap.
Title: Re: Basic Use of BGRAVirtualScreen with BGRALayerBitmap
Post by: evoshroom on June 14, 2012, 11:22:49 am
Keep in mind I'm on a Mac.  Graphics32 is heavily optimized for Windows, but on the Mac it doesn't keep all those speed optimizations and it has no Linux support at all (which was my main impetus for moving to BGRA).  Another issue I had with it is on Windows it assumes all antialiasing is done on a white background, so if you have both white and black backgrounds, the ones on the black look horrid (white pixelated outlines around the text) unless you do some hacks.  I figured the hacks would probably take as long to code for what I was doing as switching to BGRA, so I switched over.  The text now looks crisp and clear!

That being said I only switched over one application and a part of another application.  I'm currently studying how feasible it would be to bring the whole app over, which I'd like to for Linux support, if the speed is there.  It's been pretty good going so far though.

As far as the code getting smaller, Graphics32 has no resample function that I noticed.  Resizing is done through a more hackish user-added function.  Graphics32 doesn't have so many options for resampling either as far as filter methods.  You also can't do a Create and Load at the same time. 

Additionally, I saved tons of space because you have to do a TextRect with Wordwrap completely manually using a RenderText function, that is like TextOut but with formatting, so I did it all manually (and semi-poorly, admittedly).  However, I'm going to loose all that because you can't do linespacing yet, so I will have to return to my hacks I guess.  Graphics32 also didn't have any text-alignment features, so I had to code my own in too, but again, if I can't use the TextRect, I guess I'll have to do that again too.

Oh, another reason the code shrunk is that with Graphics32 the text rendering between Mac and Windows was inconsistent, so I had to do it all {$IFDEF DARWIN} and then {$IFDEF MSWINDOWS} and do it all again, so half of the code shrinkage is right there, as BGRABitmap was consistent enough to use the same code and just IFDEF the font, and that's only because I prefer Helvetica if the OS has it.

TIFF doesn't support transparency, does it?  I can try other formats and see how it does.

Thanks for all the help!  This last bit got my app back up to 95%.  Basically all I'm missing is those text niceties.
Title: Re: Basic Use of BGRAVirtualScreen with BGRALayerBitmap
Post by: evoshroom on June 14, 2012, 11:33:15 am
Hmm...so I saved the file as a .tiff and it looks to still have a transparent area in my graphics editor, so maybe TIFF can do transparency.

However, when I attempted to load it as a TIFF Lazarus threw an error:

Project <Program> raised exception class 'Exception' with message: Unknown/Unsupported PCX image type.
Title: Re: Basic Use of BGRAVirtualScreen with BGRALayerBitmap
Post by: evoshroom on June 14, 2012, 11:48:53 am
Next I tried 8-bit PNG and it had the same background issue.  Then I had a bright idea.  The problem it turned out isn't the PNG at all.  The PNG and its transparency works fine.  The problem is this line I was using to set the background:

Background := TBGRABitmap.Create(BGRAVirtualScreen.Width,BGRAVirtualScreen.Height,clBtnFace);

Now, you have an overloaded function for create that takes a TColor, so I assumed that would work, but it doesn't.  It produces a black background.  When I switched Background to a .PNG I created of solid clBtnFace it looked fine, however, that's not going work as the color of clBtnFace isn't consistent across operating systems.

Any ideas?
Title: Re: Basic Use of BGRAVirtualScreen with BGRALayerBitmap
Post by: evoshroom on June 14, 2012, 12:13:43 pm
Okay, I take that back again.  Only the 8bit PNG worked.  I tried to go back to the 24 bit one and it did not work.  Instead it drew white on the transparent areas.  That's fine though, I can stick with the 8bit PNGs now that I know they work.

If you don't have any immediate solution to the TColor overloaded function issue don't worry about it though, as I figured out another nice solution already.

However, maybe take a look at that function and make sure it is working okay for others.
Title: Re: Basic Use of BGRAVirtualScreen with BGRALayerBitmap
Post by: evoshroom on June 14, 2012, 12:15:56 pm
And for others who have the PNG issue, I found this quite handy:

http://www.8bitalpha.com/ (http://www.8bitalpha.com/)
Title: Re: Basic Use of BGRAVirtualScreen with BGRALayerBitmap
Post by: circular on June 14, 2012, 05:46:11 pm
About the color, you may use ColorToRGB(clBtnFace) as a parameter if it is not automatically recognized. System colors are special values and for speed purpose I did not do a call to ColorToRGB anytime a TColor shows up, I only read the red/green/blue values. But maybe it would be just as fast with ColorToRGB anywhere. Anyway, you can call it yourself if it's not already there.

I am surprised that you say that here is no resampling in Graphics32 as, in fact, I was greatly inspired by Graphics32 on this subject. See in G32_Resamplers.pas, the Resample function.

About text rendering in BGRABitmap, I'm proud of it, it's very beautiful. But it's slow and there is limited control over the text flow. That's why I was thinking about doing a typewriter class :
http://www.lazarus.freepascal.org/index.php/topic,17242.0.html
Title: Re: Basic Use of BGRAVirtualScreen with BGRALayerBitmap
Post by: evoshroom on June 14, 2012, 05:51:58 pm
Oh yeah, there are now.  I started my program with Graphics32 version 1.3 though, which didn't come with that resamplers.pas, so the code I was using might have been a bit out of date.

I would greatly appreciate the typewriter addition! :D
TinyPortal © 2005-2018