2007-10-24

BMPs with Transparent Backgrounds

Here are some notes on bmp transparencies on vfp, based in some conclusions I took after some discussions in Foxite, specially the ones with Bernard Bout.

BMP image files, when used in the picture property of the image control usually show whites - RGB(255,255,255) as transparent. VFP creates a temporary mask for our pictures in order to show this way.



Picture 1: BMPs can have whites converted to transparent when using the "Picture" property and Backstyle set to "Transparent".

But this works only for the 'Picture' property, not for 'PictureVal' !

The code below creates a simple image on the fly, and saves it to disk. The image on the left uses the picture property, and the right one uses 'PictureVal'.


ImportantRequires VFP9 and GdiplusX library to run.
https://github.com/VFPX/GDIPlusX



PUBLIC oForm
oform = NEWOBJECT("form1")
oform.SHOW
RETURN

DEFINE CLASS form1 AS FORM
 TOP = 13
 LEFT = 17
 HEIGHT = 168
 WIDTH = 314
 DOCREATE = .T.
 CAPTION = "testing pictureval rendering"
 NAME = "form1"

 ADD OBJECT image1 AS IMAGE WITH ;
  BACKSTYLE = 0, ;
  HEIGHT = 120, ;
  LEFT = 24, ;
  TOP = 24, ;
  WIDTH = 120, ;
  NAME = "image1"

 ADD OBJECT image2 AS IMAGE WITH ;
  BACKSTYLE = 0, ;
  HEIGHT = 120, ;
  LEFT = 168, ;
  TOP = 24, ;
  WIDTH = 120, ;
  NAME = "image2"

 PROCEDURE INIT
  DO LOCFILE("system.app")
  LOCAL lobmp AS xfcbitmap
  LOCAL logfx AS xfcgraphics
  WITH _SCREEN.SYSTEM.drawing
   lobmp = .BITMAP.new(60, 60, 0, .imaging.pixelformat.format24bpprgb)
   logfx = .graphics.fromimage(lobmp)
   logfx.CLEAR(.COLOR.white)
   logfx.drawrectangle(.PEN.new(.COLOR.red, 3), 10,10,40,40)
   lobmp.SAVE("c:\tempbmp.bmp", .imaging.imageformat.bmp)
  ENDWITH
  THISFORM.image1.PICTURE = "c:\tempbmp.bmp"
  THISFORM.image2.PICTUREVAL = FILETOSTR("c:\tempbmp.bmp")
 ENDPROC
 ENDDEFINE


Picture 2: BMPs show whites as transparent only when using the "picture" property. When using "Pictureval", images are shown without a transparent mask.

The image from the left uses the picture property, and the right one uses the pictureval property in the most simple aproach: FILETOSTRING("c:\MyPicture.bmp")
That shows us that unfortunately we can't obtain transparencies in BMPs using the pictureval property.

Fortunately, in VFP9 SP2 the VFP team fixed the PNG rendering problem, and we can use PNGs with our VFP image objects. But in this case, we need to set manually the alpha channel, specifying which color (or colors) will become transparent.
With GdiplusX these things become really easy. Just one line will do the trick:

This.oBmp.MakeTransparent(.Color.White)

Replace the above code's Init() procedure with the one below, that just changes the rendering to PNG, and uses the "MakeTransparent" method of the xfcBitmap GdiplusX library:

PROCEDURE INIT
 DO LOCFILE("system.app")
 LOCAL lobmp AS xfcbitmap
 LOCAL logfx AS xfcgraphics
 WITH _SCREEN.SYSTEM.drawing
  lobmp = .BITMAP.new(60, 60) && the default is 32bppargb
  logfx = .graphics.fromimage(lobmp)
  logfx.CLEAR(.COLOR.white)
  logfx.drawrectangle(.PEN.new(.COLOR.red, 3), 10,10,40,40)
  lobmp.maketransparent(.COLOR.white)
  lobmp.SAVE("c:\temppng.png", .imaging.imageformat.png)
 ENDWITH
 THISFORM.image1.PICTURE = "c:\temppng.png"
 THISFORM.image2.PICTUREVAL = FILETOSTR("c:\temppng.png")
ENDPROC




Picture 3: PNGs allow the use of the alpha channel, so transparencies are available both for picture and pictureval properties


Is that enough ?

Still not enough for Bernard - part 1

As he said in one foxite thread: "VFP does have a problem refreshing png's of any reasonable size. they do "flash". the best format to use with vfp is the bmp." - totally true - humpf ! That's very easy to reproduce, create any form, put an image object inside of it, using any png image. then, add another image, but this time use a BMP. set the anchor properties, run the form, and resize it, to understand what happens. maybe for the vast majority of people this is acceptable, but with BMPs we still can have a good result.



Still not enough for Bernard - part 2

He noticed that the bmps originated from the samples that I've been providing using GDI+ could not have their whites to become transparent when used in the image control.

!#*$¨*&¨($%+)(*#$%&(_*%¨#)&*(¨#&*()yuioh%&*_#(*&%(_*#$¨

The truth is that he had reported this last year, when i created a sample for his awesome One Note tabs - "vfp-x gdi+ code samples for "recreating one note tabs in vfp9" from bernard"

He has just brought this subject again in a recent foxite thread, and i finally took the time to make some new tests, and found the problem.

In most cases, when I created my bitmaps from scratch, I used the xfcBitmap.create() method, just like this:

local loBmp as xfcBitmap
loBmp = .Bitmap.New(lnWidth, lnHeight)

This by default created a bitmap with the dimensions lnwidth x lnheight, with 32bppargb pixelformat. that means that for each pixel of the bitmap we would be using 32bits, or 4 bytes - for red, green, blue and alpha (transparency).
but bmps don't support transparencies !
So, the alpha byte is totally useless for the bmp case, making our file to become 25% bigger...
The major problem is that vfp does not transform whites from 32bppargb bitmaps into transparent !!!
So, when creating a bitmap that will be saved in the bmp image format, never use 32bppargb. use 24bpprgb instead ! and this definitely solves our problem, and bernard will be able to continue to develop his masterpieces of design, hopefully, using gdiplusx.
Instead of :
loBmp = .Bitmap.New(lnWidth, lnHeight)

use:
loBmp = .Bitmap.New(60, 60, 0, .Imaging.PixelFormat.Format24BppRgb)

Thanks Bernard ! This was a good lesson to me, I've learned some good things in this investigation. Very nice, since this brings some new possibilities for some new controls.
The GdiplusX 'ImageCanvas' control will also receive some modifications, allowing to render in file mode, saving to TMP files, but using 24bpprgb, to allow the transparencies. Another modification that we agreed is to add a PNG render mode, since pngs allow the use of the alpha channel.
'Vfppaint' was also updated, allowing users to choose between 24bpprgb (new default value) and 32BppArgb.

5 comments:

  1. I AM ALSO WORKING SSAME TYPE OF PROJECT
    I HAVE PROBLEM THAT

    HOW I CAN SUPERIMPOSE 2ND IMAGE INTO 1ST IMAGE WITHOUT DISTURBING 1ST IMAGE

    1ST IMAPGE IS SQURED TYPE BUT 2ND IMAGE IS OF TYPE LIKE KOMOD/BASIN AND I WANT TO DISPLAY ON 1ST IMAGE.


    OR

    UNSHAPED IMAGE CONTROL AVAILABE IN VFP
    Hi,
    That's exactly what I've shown here !
    Use a BMP with a white background or a PNG with the Alpha channel set. Then, set your Image object's to TRANSPARENT property !

    ReplyDelete
  2. You can also use a GIF file using PICTUREVAL() and get the background tranparent by specifying the transparent colour in the GIF.

    Now if only there was a code sample to take any GIF and specify its transparent colour in code, then any GIF can be loaded using PICTUREVAL by modifying the image object in memory, setting it's transparent colour and using PICTUREVAL() to read it in!

    8bit I know but no "flashing" like PNG's.

    Hint hint :)
    Hi Bernard,
    Thanks for the tip.
    I hope to publish ASAP the codes showing how to create GIFs with transparencies with GDI+X. There's a problem in GdiPlus.dll when creating GIFs it uses a fixed color pallette. The perfect solution would be to totally recreate the color palette using the 256 colors that best fit to the created image, but this will need a FLL, because this process is really very slow. For the moment, I'll show how to enable transparencies and choose one of the colors to become transparent. But the image quality will be lousy for this moment - or will take some good time to be generated, as I'll show.
    Regards
    Cesar
    PS: My formatting in your message

    ReplyDelete
  3. First of all, Thanks for all the great work you are doing, and sharing your knowledge with us.
    Maybe this is the DUMBEST question you've heard but HOW DO I INSTALL GDI+X?? How do I use it ? I have the latest version of GDI+X, and I've read the readme file, but I can't find how i am supposed to install GDI+X. The file has a lot of info, but most of that It is not related to the installation, moreover, it says that there's no user manual or something like that. Besides, all the info is for advanced users so I can't understand it, and honestly I'm new on this, but unfortunately, I am in a hurry and need to use GDI+X as soon as possible.
    I've searched all over the VFPX site, and the GDI+X one, and found nothing that can help me. You are my only hope. I'd really appreciate any info, or link that lead me to the use of GDI+X since the begginnig, so I can take advantage of all the work you've done, and that you share with us in your posts.
    Thanks Cesar.
    Hi Albert,
    Thanks for the kind words.
    I admit, we still have a lot to do regarding the documentation. I hope to write some more detailed words on this subjects soon.
    Basically, add all GdiPlusX files to your project. To initialize GdiPlusX, all you have to do is to call the System.prg program, like
    DO SYSTEM.PRG && Don't forget to remove the LOCFILE() !
    Thnaks
    Cesar

    ReplyDelete
  4. Este articulo esta traducido al español en www.PortalFox.com


    -- BMPs con fondos transparentes --

    http://www.portalfox.com/article.php?sid=2541



    ReplyDelete
  5. Thank you very much to this info. Today I spend 2 hours to try find trouble why transparency does not work. Yes, I had 32 bits BMPs. :-)

    ReplyDelete