Recent

Author Topic: Custom Drawn Controls advances  (Read 119916 times)

felipemdc

  • Administrator
  • Hero Member
  • *
  • Posts: 3537
Re: Custom Drawn Controls advances
« Reply #30 on: November 30, 2011, 04:14:10 pm »
Are you using the very latest Lazarus source code from SVN?

Johan

  • New member
  • *
  • Posts: 10
Re: Custom Drawn Controls advances
« Reply #31 on: November 30, 2011, 08:17:10 pm »
Yes, checked it out today.

felipemdc

  • Administrator
  • Hero Member
  • *
  • Posts: 3537
Re: Custom Drawn Controls advances
« Reply #32 on: November 30, 2011, 09:00:39 pm »
Ok, I found a problem with the defines, it should work now if you svn update.
« Last Edit: November 30, 2011, 09:44:51 pm by felipemdc »

felipemdc

  • Administrator
  • Hero Member
  • *
  • Posts: 3537
Re: Custom Drawn Controls advances
« Reply #33 on: December 03, 2011, 03:57:04 pm »
We can use alpha in Canvas?

Not yet in TCanvas but in the future it will also support it, at least in LCL-CustomDrawn. Although it is not a priority for me.

In TLazCanvas I so far added only this 1 routine with alpha blending. It copies a piece of another Canvas while executing alpha blending. It will only work if the rawimage attached to the source canvas has an alpha channel, which is always the case in LCL-CustomDrawn except for a Canvas attached to the computer screen, such as a Canvas obtained from a Form or a visual control. In this case it uses the native format and only the Android native format has Alpha from what I know. I added it for font support, because I wanted to make a transparent bitmap, draw the text to it and then alpha blend it to the destination canvas. But now I found out that Cocoa does not support drawing text to a bitmap with non-premultiplied alpha =( In Android it should work fine. But in general I am getting annoyed by those native fonts drawing routines and I'm considering checking how much work it would be to shappen up pasfreetype into being useful here.

All other existing drawing routines like polygon, line, rectangle don't execute alpha blending in TLazCanvas AFAIK, but we could add alpha blend versions of them in TLazCanvas.

PS: Strange, the message from Lainz disappeared...
« Last Edit: December 03, 2011, 03:59:10 pm by felipemdc »

lainz

  • Guest
Re: Custom Drawn Controls advances
« Reply #34 on: December 03, 2011, 08:08:17 pm »
We can use alpha in Canvas?

Not yet in TCanvas but in the future it will also support it, at least in LCL-CustomDrawn. Although it is not a priority for me.

In TLazCanvas I so far added only this 1 routine with alpha blending. It copies a piece of another Canvas while executing alpha blending. It will only work if the rawimage attached to the source canvas has an alpha channel, which is always the case in LCL-CustomDrawn except for a Canvas attached to the computer screen, such as a Canvas obtained from a Form or a visual control. In this case it uses the native format and only the Android native format has Alpha from what I know. I added it for font support, because I wanted to make a transparent bitmap, draw the text to it and then alpha blend it to the destination canvas. But now I found out that Cocoa does not support drawing text to a bitmap with non-premultiplied alpha =( In Android it should work fine. But in general I am getting annoyed by those native fonts drawing routines and I'm considering checking how much work it would be to shappen up pasfreetype into being useful here.

All other existing drawing routines like polygon, line, rectangle don't execute alpha blending in TLazCanvas AFAIK, but we could add alpha blend versions of them in TLazCanvas.

PS: Strange, the message from Lainz disappeared...

Ok. Sorry I've deleted the message I thought I had made a silly question  ::) (perhaps in the very moment you were responding)

Nice to hear this, specially can be usefull for loading bitmaps with alpha to theme all the controls from bitmaps.

I've updated TBGRAImageButton now it works like the Windows themes, from a single image the control get each button state. Then resize image borders and image center separately, this causes the control to be resizable from bitmaps and not have to program the graphics in a complex way.

I think that code also can be used for other controls, also can be ported to work with TBitmap.

If you have some time check the code in custombgraimagebutton.inc (in BGRAControls), I will try to port it to TBitmap.

In the image attached at the top a TButton, in the bottom a TBGRAImageButton with 'BitmapOptions' border width and height set to 5.
« Last Edit: December 03, 2011, 08:10:11 pm by lainz »

lainz

  • Guest
Re: Custom Drawn Controls advances
« Reply #35 on: December 04, 2011, 12:46:43 am »
Check this the same with TBitmap.

felipemdc

  • Administrator
  • Hero Member
  • *
  • Posts: 3537
Re: Custom Drawn Controls advances
« Reply #36 on: December 04, 2011, 09:52:57 am »
Are you doing pixel-by-pixel access? If yes, then TBitmap is a terrible choice. It is ridiculously slow in LCL-Gtk2 because it is a native Bitmap and in Gtk2 native bitmaps are extraordinarely slow.

Lazarus offers 2 versions of almost everything: 1 native and 1 non-native.

The non-native equivalent of TBitmap is TLazIntfImage+TRawImage. To draw on it use TLazCanvas which is the non-native equivalent of TCanvas.

LCL-CustomDrawn implements almost all it's objects with the non-native equivalents (it will implement TBitmap with TLazIntfImage) so when it evolves we will have a very fast TBitmap in X11.

lainz

  • Guest
Re: Custom Drawn Controls advances
« Reply #37 on: December 04, 2011, 02:44:22 pm »
Quote
Are you doing pixel-by-pixel access?

this is the code:

Code: [Select]
unit bitmapthemeutils;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, Graphics, types, IntfGraphics;

type
  TBmpArray = array of TBitmap;
  TBmpArrays = array of TBmpArray;

function GetBitmap(Filename: String; Number: integer): TbmpArray;
function GetBitmapPart(Source: TBitmap; BorderWidth, BorderHeight: integer): TbmpArray;
function GetBitmapElements(Filename: String; Number, BorderWidth, BorderHeight: integer): TbmpArrays;
function DrawBitmap(Source: TBmpArray; DestWidth, DestHeight, BorderWidth, BorderHeight: integer): TBitmap;

implementation

function GetBitmap(Filename: String; Number: integer): TbmpArray;
var
  bmpArray: TbmpArray;
  temp: TBitmap;
  i: integer;
  s: TSize;
begin
  temp := TBitmap.Create;
  temp.LoadFromFile(Filename);

  s.cx := temp.Width;
  s.cy := temp.Height div Number;

  SetLength(bmpArray, Number);

  for i:= Low(bmpArray) to High(bmpArray) do
  begin
    bmpArray[i] := TBitmap.Create;
    bmpArray[i].Width := s.cx;
    bmpArray[i].Height := s.cy;
    bmpArray[i].Canvas.Draw(0, -s.cy * i, temp);
  end;

  temp.Free;

  result := bmpArray;
end;

function GetBitmapPart(Source: TBitmap; BorderWidth, BorderHeight: integer): TbmpArray;
var
  bmpArray: TbmpArray;
begin
  SetLength(bmpArray, 9);

  { Top Left }
  bmpArray[0] := TBitmap.Create;
  bmpArray[0].Width := BorderWidth;
  bmpArray[0].Height := BorderHeight;
  bmpArray[0].Canvas.Draw(0, 0, Source);

  { Top Right }
  bmpArray[1] := TBitmap.Create;
  bmpArray[1].Width := BorderWidth;
  bmpArray[1].Height := BorderHeight;
  bmpArray[1].Canvas.Draw(BorderWidth - Source.Width, 0, Source);

  { Bottom Left }
  bmpArray[2] := TBitmap.Create;
  bmpArray[2].Width := BorderWidth;
  bmpArray[2].Height := BorderHeight;
  bmpArray[2].Canvas.Draw(0, BorderHeight - Source.Height, Source);

  { Bottom Right }
  bmpArray[3] := TBitmap.Create;
  bmpArray[3].Width := BorderWidth;
  bmpArray[3].Height := BorderHeight;
  bmpArray[3].Canvas.Draw(BorderWidth - Source.Width, BorderHeight
    - Source.Height, Source);

  { Center }
  bmpArray[4] := TBitmap.Create;
  bmpArray[4].Width := Source.Width - BorderWidth * 2;
  bmpArray[4].Height := Source.Height - BorderHeight * 2;
  bmpArray[4].Canvas.Draw(-BorderWidth, -BorderHeight, Source);

  { Top }
  bmpArray[5] := TBitmap.Create;
  bmpArray[5].Width := Source.Width - BorderWidth * 2;
  bmpArray[5].Height := BorderHeight;
  bmpArray[5].Canvas.Draw(-BorderWidth, 0, Source);

  { Left }
  bmpArray[6] := TBitmap.Create;
  bmpArray[6].Width := BorderWidth;
  bmpArray[6].Height := Source.Height - BorderHeight * 2;
  bmpArray[6].Canvas.Draw(0, -BorderHeight, Source);

  { Right }
  bmpArray[7] := TBitmap.Create;
  bmpArray[7].Width := BorderWidth;
  bmpArray[7].Height := Source.Height - BorderHeight * 2;
  bmpArray[7].Canvas.Draw(BorderWidth - Source.Width, -BorderHeight, Source);

  { Bottom }
  bmpArray[8] := TBitmap.Create;
  bmpArray[8].Width := Source.Width - BorderWidth * 2;
  bmpArray[8].Height := BorderHeight;
  bmpArray[8].Canvas.Draw(-BorderWidth, BorderHeight - Source.Height, Source);

  result := bmpArray;
end;

function GetBitmapElements(Filename: String; Number, BorderWidth, BorderHeight: integer): TbmpArrays;
var
  bmpArrayStates: TBmpArray;
  bmpArrayParts: TBmpArrays;
  i: integer;
begin
  bmpArrayStates := GetBitmap(Filename, Number);

  SetLength(bmpArrayParts, Number);
  for i:=Low(bmpArrayStates) to High(bmpArrayStates) do
  begin
    bmpArrayParts[i] := GetBitmapPart(bmpArrayStates[i], BorderWidth, BorderHeight);
  end;

  result := bmpArrayParts;
end;

function DrawBitmap(Source: TBmpArray; DestWidth, DestHeight, BorderWidth, BorderHeight: integer): TBitmap;
var
  dest: TBitmap;
begin
  dest := TBitmap.Create;
  dest.Width := DestWidth;
  dest.Height := DestHeight;
  result := dest;

  //top left
  dest.Canvas.Draw(0, 0, Source[0]);
  //top right
  dest.Canvas.Draw(DestWidth - BorderWidth, 0, Source[1]);
  //bottom left
  dest.Canvas.Draw(0, DestHeight - BorderHeight, Source[2]);
  //bottom right
  dest.Canvas.Draw(DestWidth - BorderWidth, DestHeight - BorderHeight, Source[3]);
  //center
  dest.Canvas.StretchDraw(Rect(BorderWidth, BorderHeight, DestWidth - BorderWidth, DestHeight - BorderHeight), Source[4]);
  //top
  dest.Canvas.StretchDraw(Rect(BorderWidth, 0, DestWidth - BorderWidth, BorderHeight), Source[5]);
  //left
  dest.Canvas.StretchDraw(Rect(0, BorderHeight, BorderWidth, DestHeight - BorderHeight), Source[6]);
  //right
  dest.Canvas.StretchDraw(Rect(DestWidth - BorderWidth, BorderHeight, DestWidth, DestHeight - BorderHeight), Source[7]);
  //bottom
  dest.Canvas.StretchDraw(Rect(BorderWidth,DestHeight - BorderHeight, DestWidth - BorderWidth, DestHeight), Source[8]);
end;

end.                 

Quote
The non-native equivalent of TBitmap is TLazIntfImage+TRawImage. To draw on it use TLazCanvas which is the non-native equivalent of TCanvas.

LCL-CustomDrawn implements almost all it's objects with the non-native equivalents (it will implement TBitmap with TLazIntfImage) so when it evolves we will have a very fast TBitmap in X11.

I will try.

felipemdc

  • Administrator
  • Hero Member
  • *
  • Posts: 3537
Re: Custom Drawn Controls advances
« Reply #38 on: December 04, 2011, 02:47:28 pm »
this is the code:

Indeed I don't see pixel-by-pixel access in that code (usage of the property Pixels[x, y]), so what I said doesn't apply here.

But you are using something else dangerous: TCanvas.StretchDraw In my experience TCanvas.StretchDraw can cause problems because the performance and resulting image varies between platforms, and that's why I have written a non-native stretch which stretches like Windows in lazcanvas. I'll document this...

Edit: But maybe in your case TCanvas.StretchDraw will work fine. In any case I documented a lot of stuff here:

http://wiki.lazarus.freepascal.org/Developing_with_Graphics#Working_with_TLazIntfImage.2C_TRawImage_and_TLazCanvas

http://wiki.lazarus.freepascal.org/Developing_with_Graphics#Introduction_to_the_Graphics_model_of_the_LCL

http://wiki.lazarus.freepascal.org/Developing_with_Graphics#Using_the_non-native_StretchDraw_from_LazCanvas
« Last Edit: December 04, 2011, 05:07:18 pm by felipemdc »

lainz

  • Guest
Re: Custom Drawn Controls advances
« Reply #39 on: December 05, 2011, 12:55:27 am »
Your links are very usefull and easy to understand thankyou.

lainz

  • Guest
Re: Custom Drawn Controls advances
« Reply #40 on: December 06, 2011, 05:38:19 pm »
I'm doing something wrong, i want to stretch draw Source[4] (TBitmap) in dest (TBitmap)

Code: [Select]
function DrawBitmap(Source: TBmpArray; DestWidth, DestHeight, BorderWidth, BorderHeight: integer): TBitmap;
var
  dest: TBitmap;
  image, temp: TLazIntfImage;
  imagecanvas: TLazCanvas;
begin
  dest := TBitmap.Create;
  dest.Width := DestWidth;
  dest.Height := DestHeight;

  image := TLazIntfImage.Create(dest.Width, dest.Height);
  image.LoadFromBitmap(dest.Handle, 0);

  imagecanvas := TLazCanvas.Create(Image);
  imagecanvas.Interpolation := TFPSharpInterpolation.Create;

  //center
  temp := TLazIntfImage.Create(Source[4].Width, Source[4].Height);
  temp.LoadFromBitmap(Source[4].Handle, 0);
  imagecanvas.StretchDraw(BorderWidth, BorderHeight, DestWidth - BorderWidth, DestHeight - BorderHeight, temp);
  temp.Free;

  imagecanvas.Free;
  image.Free;           

...       
« Last Edit: December 06, 2011, 07:26:51 pm by lainz »

felipemdc

  • Administrator
  • Hero Member
  • *
  • Posts: 3537
Re: Custom Drawn Controls advances
« Reply #41 on: December 07, 2011, 11:23:06 am »
You are forgetting to reload the destination IntfImage back into the TBitmap:

  DestBitmap.LoadFromIntfImage(DestIntfImage);

I have rewritten the wiki example to be more complete and more clear:

http://wiki.lazarus.freepascal.org/Developing_with_Graphics#Using_the_non-native_StretchDraw_from_LazCanvas

lainz

  • Guest
Re: Custom Drawn Controls advances
« Reply #42 on: December 07, 2011, 10:34:04 pm »
With TFPSharpInterpolation I'm losing a pixel in 'top', 'left', 'right' and 'bottom' borders.
« Last Edit: December 08, 2011, 06:45:37 pm by lainz »

felipemdc

  • Administrator
  • Hero Member
  • *
  • Posts: 3537
Re: Custom Drawn Controls advances
« Reply #43 on: December 08, 2011, 09:27:30 am »
Is it fixed now in rev34037?

I do still experience a problem with the top-left pixel in LCL-CustomDrawn, and only sometimes, but no idea so far what the problem is. But for sure it is not in the sharp interpolation.

lainz

  • Guest
Re: Custom Drawn Controls advances
« Reply #44 on: December 08, 2011, 02:42:47 pm »
Is it fixed now in rev34037?

Yes now works fine.