scanline type access and frustration. lazarus / 39-Graphics ---------------------------------------------------------------------- taazz · 2013-07-07 21:14 Ok, I have spend the last 6 hours debugging a progress bar I like a lot (TVistaBarPro from rmklever) trying to convert it to lazarus and I'm at my patients end. I would like some one who knows GTK well to explain to me the following. I have a Timage control on the form and made it all top on the on resize event of that timage I have the following code. Code: [Select]procedure TForm1.Image1Resize(Sender : TObject); begin   Image1.Picture.Graphic := Nil;   Image1.Picture.Bitmap.PixelFormat := pf32bit;   Image1.Picture.Bitmap.SetSize(Image1.Width, Image1.Height);   Image1.Picture.Bitmap.Canvas.FillRect(0,0,Image1.Width -1, image1.Height-1);   FastFill(Image1.Picture.Bitmap, clRed); end; Following are the 3 Fastfill methods of the form, and the types used for testing to understand what is going on. Code: [Select]  TRGB = record     R, G, B : byte;   end;   TRGBArray = array [0..0] of TRGB;   PRGBArray = ^TRGBArray;   TRGBA = record     R, G, B, A :Byte;   end;   TRGBAArray = array [0..0] of TRGBA;   PRGBAArray = ^TRGBAArray; procedure TForm1.FastFill24(aBmp : TBitmap; aColor : TColor); var   vRI : TRawImage;   vRow: PRGBArray;   vC  : TRGB;   vX,vY : Integer;   vClr  : longint;   vSize : longword; begin   Label4.Caption := 'FastFill24';   vClr := ColorToRGB(aColor);   vC.R := Graphics.Red(vClr);   vC.G := Graphics.Green(vClr);   vC.B := Graphics.Blue(vClr); //  aBmp.Canvas.Brush.Color := clWhite; //  aBmp.Canvas.Brush.Style := bsSolid; //  aBmp.Canvas.FillRect(0,0,aBmp.Width, aBmp.Height);   aBmp.BeginUpdate(False);   try     vRI := aBmp.RawImage;     vSize := vRI.Description.BytesPerLine;     for vY := 0 to aBmp.Height -1 do begin       vRow := Pointer(PtrUInt(vRI.Data) + ( vSize * vY));       for vX := 0 to aBmp.Width -1 do         vRow^[vX] := vC;     end;   finally     aBmp.EndUpdate(False);   end; end; procedure TForm1.FastFill32(aBmp : TBitmap; aColor : TColor); var   vRI : TRawImage;   vRow: PRGBAArray;   vC  : TRGBA;   vX,vY : Integer;   vClr  : longint;   vSize : longword; begin   Label4.Caption := 'FastFill32';   vClr := ColorToRGB(aColor);   vC.R := Graphics.Red(vClr);   vC.G := Graphics.Green(vClr);   vC.B := Graphics.Blue(vClr);   vC.A := FPimage.alphaOpaque; //  aBmp.Canvas.Brush.Color := clWhite; //  aBmp.Canvas.Brush.Style := bsSolid; //  aBmp.Canvas.FillRect(0,0,aBmp.Width, aBmp.Height);   aBmp.BeginUpdate(False);   try     vRI := aBmp.RawImage;     vSize := vRI.Description.BytesPerLine;     for vY := 0 to aBmp.Height -1 do begin       vRow := Pointer(PtrUInt(vRI.Data) + ( vSize * vY));       for vX := 0 to aBmp.Width -1 do         vRow^[vX] := vC;     end;   finally     aBmp.EndUpdate(False);   end; end; procedure TForm1.FastFill(aBmp : TBitmap; aColor : TColor); begin   if Image1.Picture.Bitmap.PixelFormat = pf24bit then     FastFill24(Image1.Picture.Bitmap, aColor);   if Image1.Picture.Bitmap.PixelFormat = pf32bit then     FastFill32(Image1.Picture.Bitmap, aColor); end; Keep in mind that those are procedures for testing purposes to allow me to decode the rgb sequence, values etc. At first there was nothing painted. I added to code like abmp.canvas.brush.color := clwhite; abmp.canvas.fillrect(.....) and I started seeing white rectangles and then it started painting something on screen. I removed the calls to fillrect etc and everything kept working now I can see something on screen not red of course but I can work with it and now comes the weird part. Can any one explain to me why when the image1.width gets the value of 256 the color sudenly changes to red? on 255 is blue, on 257,258 ... is blue also but on 264 its red again. I had some instances that the color disappeared but I can't reproduce it at the moment. There are more problems that I can't reproduce at the moment so I'll scratch them as my fault at this point. ---------------------------------------------------------------------- marcov · 2013-07-08 10:43 1. Maybe you need some invalidate here and there to signal repaint? 2. Make your records packed. I don't really think it matters here (all fields are bytes), but just to be sure. 3. Your code seems to assume that bitmaps are topdown. (IOW row X is in memory after row X-1 not before) ---------------------------------------------------------------------- taazz · 2013-07-08 16:30 Thank you for answering I really appreciate it. Today after I corrected a couple of memory leaks and component life management problems everything seems to work on my little test case anyway. 1) Invalidating should be automatic I guess since all I'm doing is create a temp bmp which then is drawn on the image1.picture.graphic.canvas.draw, in a good measure I added a image1.invalidate on the resize event handler but I do not see any difference at this point. 2) I don't know if there is anything to be gained from making them packed at this point but I will try that out too 3) Yes as far as I can see all the bitmaps I created are topdown is there any way to force them to be created that way? In any case an internal function scanline(v:TRawImage; x:int);inline;  want be a problem but I'd prefer to initialize the bitmaps 32bits and top down so far I haven't come across anything that would allow me to define the topdown property. ---------------------------------------------------------------------- marcov · 2013-07-08 20:03 Quote from: taazz on July 08, 2013, 06:30:39 pmThank you for answering I really appreciate it. I work with images all day, but unfortunately with own classes, and the little *CL experience I have is on Delphi,not Lazarus. QuoteToday after I corrected a couple of memory leaks and component life management problems everything seems to work on my little test case anyway. 1) Invalidating should be automatic I guess since all I'm doing is create a temp bmp which then is drawn on the image1.picture.graphic.canvas.draw, in a good measure I added a image1.invalidate on the resize event handler but I do not see any difference at this point. Quote You do know you should only draw inside a .paint event on GTK? Quote2) I don't know if there is anything to be gained from making them packed at this point but I will try that out too if sizeof(RGB)=3 and RGBA=4 then that is not the problem. I was just brainstorming Quote3) Yes as far as I can see all the bitmaps I created are topdown is there any way to force them to be created that way? In any case an internal function scanline(v:TRawImage; x:int);inline;  want be a problem but I'd prefer to initialize the bitmaps 32bits and top down so far I haven't come across anything that would allow me to define the topdown property. On Windows one generally wants bottom-up images, since that is the GDI's native type. But in this case it was more a hint to check that the real situation (  topdown:=ptruint(lines[1]-lines[0])>0; ) is in line with what you expect. Again as brainstorming. ---------------------------------------------------------------------- User137 · 2013-07-08 22:05 I don't know about scanline, but i have used TRawImage with assumption that there can be more data per row after "last" pixel, and even possible that the data row separator is something between 1 to 7 BITS. Because that's the accuracy that RawImage supports, i went with it on nxPascal, counting channel positions in bits, not bytes. As far as i've tested for very long time, it supports all PNG and JPG formats at least. Code may look terrible without syntax highlighting, but... https://code.google.com/p/nxpascal/source/browse/trunk/src/nxGraph.pas #606 And i don't know if this helps for your problem, it's just another way to use TRawImage. ---------------------------------------------------------------------- taazz · 2013-07-08 23:23 @User137 Thanks form a quick look around you seem to use the TRawImagePosition to access pixels look like an interesting method, I"m probably going to speed test it in the future. @marcov Quote from: marcov on July 08, 2013, 10:03:44 pmYou do know you should only draw inside a .paint event on GTK? I'm aware of the GTK limitations mostly from this forums. Never tested the waters my self. Quote from: marcov on July 08, 2013, 10:03:44 pmOn Windows one generally wants bottom-up images, since that is the GDI's native type. But in this case it was more a hint to check that the real situation (  topdown:=ptruint(lines[1]-lines[0])>0; ) is in line with what you expect. Again as brainstorming. Yeah never got around getting used to the more mathematically correct screen quadrants of windows I'm more or less stack on the dos era frame of mind where the screen 0,0 was always on top left. I don't mind writing a few ifs here and there but isn't the .data a simple pointer to the beginning of the data memory regardless the image representation or is it designed to resample closely  the delphi scanline as well? ---------------------------------------------------------------------- taazz · 2013-07-11 19:48 Well the gods decided that they have something better to do than looking over my solder and today GTK reverted back to its old behavior. Keep in mind  that I haven't touched the code the past few days I was mainly working on the simplegraph port that I have going I just wend for a quick test and note down what else is needed to close the port of rkVistaProBar and nothing works. The bar is a mess the tests I posted earlier which they worked for a few days are a mess too just take a look on the screen shots. I'm convinced that there is some kind of initialization that's gone wrong. I can't think of anything else at this point and I was wandering if there is some way to force tbitmap or any kind of image for that matter to initialize on specific values eg BGRA/RGBA/RGB/BGR, 32/24bit. A few helper function I use extensively to set colors now instead of working directly with the RawImage memory Code: [Select] function ScanLine(aRI: TRawImage; aY:Integer):PByte;inline; begin   case aRI.Description.LineOrder of     riloTopToBottom : Result := aRI.Data + (aRI.Description.BytesPerLine * aY);     riloBottomToTop : Result := aRI.Data + (aRI.Description.BytesPerLine * (aRI.Description.Height - aY));   end; end; function NextScanLine(aRI:TRawImage; aLine:PByte; aAmount:Integer=1):PByte;Inline; begin   case aRI.Description.LineOrder of     riloTopToBottom : Result := aLine + (aRI.Description.BytesPerLine * aAmount);     riloBottomToTop : Result := aLine - (aRI.Description.BytesPerLine * aAmount);   end; end; function RIColor(aRI:TRawImage; const R, G, B : Byte; A:Byte = {$IFNDEF LCLGTK2}255{$ELSE}0{$ENDIF}) : DWord;inline; begin   Result := DWORD(R shl aRI.Description.Redshift)   or DWORD(B shl aRI.Description.BlueShift) or             DWORD(G shl aRI.Description.GreenShift) or DWORD(A shl aRI.Description.AlphaShift); end; function RISetAlpha(aRI:TRawImage; const aColor:LongWord; const A:Byte) : DWord;inline; begin   Result := aColor xor (Byte(aColor shr aRI.Description.AlphaShift) shl aRI.Description.AlphaShift);   Result := Result or  (A shl aRI.Description.AlphaShift); end; [code] If you spot a bug I would appreciate a kick on the head.