Recent

Author Topic: About the method of generating 8-bit indexed bitmaps.  (Read 3922 times)

wszgr

  • Newbie
  • Posts: 1
About the method of generating 8-bit indexed bitmaps.
« on: April 26, 2023, 05:35:11 pm »
Code: [Select]
procedure InitializePalette();
var
   bitmap:TBitmap;
   PaletteEntries : TMaxLogPalette;
   Word_Palette:HPALETTE;
begin
   PaletteEntries.palVersion:=$300;
   PaletteEntries.palNumEntries:=4;
   PaletteEntries.palPalEntry[0].peRed:=0;
   PaletteEntries.palPalEntry[0].peGreen:=0;
   PaletteEntries.palPalEntry[0].peBlue:=0;
   PaletteEntries.palPalEntry[0].peFlags:=PC_NOCOLLAPSE;
   PaletteEntries.palPalEntry[1].peRed:=99;
   PaletteEntries.palPalEntry[1].peGreen:=207;
   PaletteEntries.palPalEntry[1].peBlue:=99;
   PaletteEntries.palPalEntry[1].peFlags:=PC_NOCOLLAPSE;
   PaletteEntries.palPalEntry[2].peRed:=57;
   PaletteEntries.palPalEntry[2].peGreen:=51;
   PaletteEntries.palPalEntry[2].peBlue:=255;
   PaletteEntries.palPalEntry[2].peFlags:=PC_NOCOLLAPSE;
   PaletteEntries.palPalEntry[3].peRed:=220;
   PaletteEntries.palPalEntry[3].peGreen:=255;
   PaletteEntries.palPalEntry[3].peBlue:=255;
   PaletteEntries.palPalEntry[3].peFlags:=PC_NOCOLLAPSE;
   Word_Palette:=CreatePalette(PLogPalette(@PaletteEntries)^);
   bitmap:=TBitmap.Create;
   bitmap.PixelFormat:=pf8bit;
   bitmap.ReleasePalette;
   bitmap.Palette:=Word_Palette;
   bitmap.SetSize(128,128);
   Bitmap.SaveToFile('C:\Users\Administrator\Desktop\asd.bmp');
   bitmap.Free;
end;   
     

I wrote this code that first generates a palette, then assigns it to the palette of an 8-bit bitmap, and finally saves it as a bmp format image. This code can run correctly in Delphi, but when brought into Lazarus it reports an error of ‘image palette is too big or absent’. I don’t know why. Please tell me the correct method for generating 8-bit indexed color bitmaps. Thank you!!     
« Last Edit: May 25, 2023, 10:55:12 am by marcov »

KodeZwerg

  • Hero Member
  • *****
  • Posts: 2269
  • Fifty shades of code.
    • Delphi & FreePascal
Re: About the method of generating 8-bit indexed bitmaps.
« Reply #1 on: April 26, 2023, 05:43:46 pm »
I have not checked your code but I can say that on Windows the TBitmap is not working properly, its PixelFormat is always matching the display adapters setting for the destop (in most cases 24 or 32 bit)
« Last Edit: Tomorrow at 31:76:97 xm by KodeZwerg »

Zvoni

  • Hero Member
  • *****
  • Posts: 2913
Re: About the method of generating 8-bit indexed bitmaps.
« Reply #2 on: April 27, 2023, 08:44:19 am »
add {$mode delphi}?

This looks fishy to me, especially since he uses the Record-Type TMaxLogPalette for PaletteEntries
Code: Pascal  [Select][+][-]
  1.  Word_Palette:=CreatePalette(PLogPalette(@PaletteEntries)^);
« Last Edit: April 27, 2023, 09:58:44 am by Zvoni »
One System to rule them all, One Code to find them,
One IDE to bring them all, and to the Framework bind them,
in the Land of Redmond, where the Windows lie
---------------------------------------------------------------------
Code is like a joke: If you have to explain it, it's bad

TRon

  • Hero Member
  • *****
  • Posts: 4148
Re: About the method of generating 8-bit indexed bitmaps.
« Reply #3 on: April 27, 2023, 03:45:33 pm »
Please tell me the correct method for generating 8-bit indexed color bitmaps. Thank you!!   
For BMP indexed color bitmap then see attachment (Hopefully, I did that right: unfortunately documentation seems scarce).
Today is tomorrow's yesterday.

wp

  • Hero Member
  • *****
  • Posts: 12683
Re: About the method of generating 8-bit indexed bitmaps.
« Reply #4 on: April 27, 2023, 04:44:41 pm »
Nice example. Would you mind me to add it to the wiki?

I was close to answer that this cannot be done since I only found code in which the palette was skipped. BTW, do you know of a way how to use a canvas for drawing on a palettized bitmap? All the canvas methods which are more advanced than setting pixel colors use a TFPColor (fp-image) or TColor (LCL), but never a palette index to define a color.

TRon

  • Hero Member
  • *****
  • Posts: 4148
Re: About the method of generating 8-bit indexed bitmaps.
« Reply #5 on: April 27, 2023, 04:58:26 pm »
Nice example. Would you mind me to add it to the wiki?
No problem at all placing the example in the wiki. Thank you for considering that. As said, I do not know if my solution is the recommended way of doing such a thing. So, please note the "It works for me" tm

Quote
I was close to answer that this cannot be done since I only found code in which the palette was skipped. BTW, do you know of a way how to use a canvas for drawing on a palettized bitmap? All the canvas methods which are more advanced than setting pixel colors use a TFPColor (fp-image) or TColor (LCL), but never a palette index to define a color.
There is a function that creates a palette from an existing image. I would have to experiment with that (unless you beat me to it  :D ). Based on that my first idea is/was to create a bitmap + canvas. Draw to it with a set of default pens/colors (in order to stay in range of the number of pens you actually want in the final image), then create the palette from the image and then save it. But please feel free to share/add your input.

Basically I do a similar thing (using fpimage) when creating IFF images with a set number of (argb) colors which correspond to the actual bit-depth that I want the image to have (can be less ofc). When saving the image, I use the predefined fpcolor table as an index for writing the actual pixels (as they are merely indices to the palette/colortable that also needs to be written to disk).
« Last Edit: April 27, 2023, 05:01:03 pm by TRon »
Today is tomorrow's yesterday.

wp

  • Hero Member
  • *****
  • Posts: 12683
Re: About the method of generating 8-bit indexed bitmaps.
« Reply #6 on: April 27, 2023, 05:12:38 pm »
Found it:

TFPCustomImage.SetInternalColor(x,y: Integer; const Value: TFPColor) is called whenever a pixel is set to its FPColor (r,g,b value as Word):
Code: Pascal  [Select][+][-]
  1. procedure TFPCustomImage.SetInternalColor (x,y:integer; const Value:TFPColor);
  2. var i : integer;
  3. begin
  4.   i := FPalette.IndexOf (Value);
  5.   SetInternalPixel (x,y,i);
  6. end;
  7.  
  8. procedure TFPMemoryImage.SetInternalColor (x,y:integer; const Value:TFPColor);
  9.   begin
  10.     if Assigned(FPalette)
  11.     then
  12.       inherited SetInternalColor(x,y,Value)
  13.     else
  14.       PFPColorArray(FData)^[y*FWidth+x]:=Value;
  15.   end;
  16.  
This means that when FPMemoryImages has a palette it calles the inherited SetInternalColor procedure which searches for the palette index of the specific color and uses this palette index (the Set/GetPixel routines refer to the palette index, while the Set/GetColor routines refer to the FPColor). And when the color is not contained in the palette?
Code: Pascal  [Select][+][-]
  1. function TFPPalette.IndexOf (const AColor:TFPColor) : integer;
  2. begin
  3.   result := FCount;
  4.   repeat
  5.     dec (result);
  6.   until (result < 0) or (FData^[result]=AColor);
  7.   if result < 0 then
  8.     result := Add (AColor);
  9. end;
It adds the color to the palette.

Here is a modified version of your sample in which some rectangles are painted onto the canvas of a 8-bit palette image:
Code: Pascal  [Select][+][-]
  1. function RGBtoFPColor(r,g,b: byte): TFPColor;
  2. begin
  3.   Result:= FPColor(r*$101,g*$101,b*$101);
  4. end;
  5.  
  6. procedure stuffing;
  7. var
  8.   img: TFPMemoryImage;
  9.   cnv: TFPImageCanvas;
  10.   writer: TFPCustomimageWriter;
  11.   x,y,c: integer;
  12. begin
  13.   try
  14.     // create a "custom" writer...
  15.     writer := TFPWriterBMP.Create;
  16.     // ... in order to be able to set the bitmap depth
  17.     TFPWriterBMP(writer).BitsPerPixel:= 8;
  18.  
  19.     // create memory image
  20.     img:= TFPMemoryImage.Create(128, 128);
  21.     try
  22.       img.UsePalette:= true;
  23.  
  24.       // Add image palette colors
  25.       // seems like the first palette entry is already set to rgb(0,0,0)
  26.       // img.Palette.Add(RGBtoFPColor(  0,   0,   0));  // color00
  27.       img.Palette.Add(RGBtoFPColor( 99, 207,  99));  // color01
  28.       img.Palette.Add(RGBtoFPColor( 57,  51, 255));  // color02
  29.       img.Palette.Add(RGBtoFPColor(220, 255, 255));  // color03
  30.  
  31.       cnv := TFPImageCanvas.Create(img);
  32.       cnv.Brush.FPColor := RGBtoFPColor( 99, 207, 99);
  33.       cnv.Rectangle(10, 10, 60, 64);
  34.  
  35.       cnv.Brush.FPColor := RGBtoFPColor( 57, 51, 255);
  36.       cnv.Rectangle(70, 10, 118, 64);
  37.  
  38.       cnv.Brush.FPColor := RGBtoFPColor(220, 255, 255);
  39.       cnv.Rectangle(10, 70, 60, 118);
  40.  
  41.       cnv.Brush.FPColor := RGBtoFPColor(225, 0, 0);
  42.       cnv.Rectangle(70, 70, 118, 118);
  43.       cnv.Free;
  44.  
  45.                                                 (*
  46.       // draw some imagery
  47.       for y:= 0 to pred(img.height) do
  48.       begin
  49.         // color cycle through available palette entries.
  50.         c:= y shr 2 mod 4;
  51.         // assign color to pixels
  52.         for x:= 0 to pred(img.width) do img.Pixels[x,y]:= c;
  53.       end;
  54.                                                   *)
  55.       img.SaveToFile ('filename.bmp', writer);
  56.     finally
  57.       img.Free;
  58.     end;
  59.   finally
  60.     writer.Free;
  61.   end;
  62. end;              
« Last Edit: April 27, 2023, 05:29:26 pm by wp »

TRon

  • Hero Member
  • *****
  • Posts: 4148
Re: About the method of generating 8-bit indexed bitmaps.
« Reply #7 on: April 27, 2023, 05:23:31 pm »
Yes, great find wp. Thank you for that

I just figured out myself that I can simply use the palette index to use as 'existing' color. That way you can be certain you do not create more colors then is actually available in the palette. It goes without saying (although no experience) that you can get yourself into problems with going over the color limit when applying effects such as dithering (and others). I am assuming that these effects that can be applied to images do not take the bitcount of the writer into account (*)

(*) ofc you can always use the quantizer.



excerpt that stays in line with one of the other examples:
Code: Pascal  [Select][+][-]
  1. ...
  2.       canv := TFPImageCanvas.Create(img);
  3.  
  4.       // draw some imagery
  5.       with canv do
  6.       begin
  7.         pen.mode := pmCopy;
  8.         pen.Style := psSolid;
  9.         pen.width := 1;
  10.         pen.FPColor := img.Palette[1];
  11.       end;
  12.       canv.Ellipse (20,20, 180,180);
  13.  
  14.       canv.pen.FPColor := img.Palette[2];
  15.       canv.Ellipse (40,40, 160,160);
  16.  
  17.       canv.pen.FPColor := img.Palette[3];
  18.       canv.Ellipse (60,60, 140,140);
  19. ...
  20.  
« Last Edit: April 27, 2023, 05:35:16 pm by TRon »
Today is tomorrow's yesterday.

wp

  • Hero Member
  • *****
  • Posts: 12683
Re: About the method of generating 8-bit indexed bitmaps.
« Reply #8 on: April 27, 2023, 05:54:10 pm »
Ah, I knew there must be a way to refer to the Palette itself.

This is the chapter in the wiki now: https://wiki.freepascal.org/fcl-image#Writing_an_8-bit_paletted_bitmap_file

Do you have an example how to use the quantizer?

TRon

  • Hero Member
  • *****
  • Posts: 4148
Re: About the method of generating 8-bit indexed bitmaps.
« Reply #9 on: April 27, 2023, 05:59:05 pm »
This is the chapter in the wiki now: https://wiki.freepascal.org/fcl-image#Writing_an_8-bit_paletted_bitmap_file
Thank you very much for that wp.

Quote
Do you have an example how to use the quantizer?
I have used the quantizer in one of my projects but would have to dig that up (it was written before I used vcs so it is located somewhere on some disc  :) ). I'll try and find that, or perhaps just write an example. It is not so difficult to do (famous last words). I'll get back to you on that.
Today is tomorrow's yesterday.

wp

  • Hero Member
  • *****
  • Posts: 12683
Re: About the method of generating 8-bit indexed bitmaps.
« Reply #10 on: April 27, 2023, 06:19:55 pm »
I thought there is one in the fcl-image folder (yes: unit fpquantizer), this would be better for the wiki. Looking at the code, I would say it's the sequence TFPColorQuantizer.Create, Add(image), Quantize and assign the result of Quantize to the image palette. Just guessing - must try...

wp

  • Hero Member
  • *****
  • Posts: 12683
Re: About the method of generating 8-bit indexed bitmaps.
« Reply #11 on: April 27, 2023, 07:42:59 pm »
Color quantization and dithering is in this old forum post: https://forum.lazarus.freepascal.org/index.php/topic,13468.msg70495.

Adapted the code in the attached small demo which converts the famous Lenna test image (24bpp png) to a paletted 8bpp bmp.
« Last Edit: April 27, 2023, 07:45:25 pm by wp »

TRon

  • Hero Member
  • *****
  • Posts: 4148
Re: About the method of generating 8-bit indexed bitmaps.
« Reply #12 on: April 27, 2023, 07:48:20 pm »
5 minutes too late. Story of my life  :'(  :D

Attached is an example with comments. thank you for having found that entry wp. also thank you for the example.

edit: updated the attachment as the initial upload had some leaks because I forgot to free some classes  :-X
« Last Edit: April 27, 2023, 08:01:13 pm by TRon »
Today is tomorrow's yesterday.

TRon

  • Hero Member
  • *****
  • Posts: 4148
Re: About the method of generating 8-bit indexed bitmaps.
« Reply #13 on: April 27, 2023, 10:26:36 pm »
Another example attached,

This example accepts multiple png image files as command line parameters and create one single palette to be used for all the images (at once). Code is pretty rough and only there to show how it can be accomplished. Feel free to use it.

Thank you for the BW example wp.

ps: in case wondering how that can be useful. There once was a time when tiled maps existed and you were restricted in the amount of colors displayed (at once) on the screen. It can also help when creating an iconset using the same (reduced) color-scheme for all icons. Or for creating (not so memory hungry) preview images. In the old days you had to use quite some trickery with restricted hardware  :D
« Last Edit: April 27, 2023, 10:44:50 pm by TRon »
Today is tomorrow's yesterday.

wp

  • Hero Member
  • *****
  • Posts: 12683
Re: About the method of generating 8-bit indexed bitmaps.
« Reply #14 on: April 27, 2023, 10:31:59 pm »
Thank you, too. Amazing how powerful the fcl-image library is. And almost nobody knows about it...

 

TinyPortal © 2005-2018