For the sake of a minimal complete question, I have a WMF file loaded into a TImage
control on a form. This control contains the property Picture, which is a TPicture
type. I am trying to "rasterize" the WMF file that I loaded into the TImage, and store that into a TSpeedButton.Glyph
.
What is interesting about this process is I am able to use this technique to create a resolution independent custom control (a button in my case) that will redraw its glyph for any resolution you like.
In real world usage, I would not have a TImage or a TSpeedButton, but this question is fundamentally about the process of moving content from TPicture
to a TBitmap
.
Here is the relevant semi-working code:
procedure CopyBitmap( Source:TImage; DestSpeedButton:TSpeedButton );
var
bmp: TBitmap;
begin
bmp:=TBitmap.Create;
try
// note: with WMF loaded, Source.Picture.Bitmap.Width and Height are 0.
bmp.Width := Source.Width; // originally I had Source.Picture.Bitmap.Width, which didn't work.
bmp.Height := Source.Height; //because Source.Picture.Bitmap.Height, doesn't work.
bmp.Canvas.Draw(0,0, Source.Picture.Graphic );
DestSpeedButton.Glyph:=bmp;
finally
bmp.Free;
end;
end;
Is this the correct approach? Why does the image invert during copy?
A sample WMF file, the exact file I'm using, is found here.
Thanks David, for suggesting that I draw the background. This works.
Note that in production I would change the code below to use Vcl.GraphUtils
helper called ScaleImage
as the results are much prettier. See the second code sample.
// Quick and Dirty : No sub-pixel anti-aliasing.
// Also does not modifies Source, so set Source's size before you
// call this.
procedure CopyBitmap( Source:TImage; DestSpeedButton:TSpeedButton );
var
bmp: TBitmap;
begin
bmp:=TBitmap.Create;
try
bmp.SetSize( Source.Width, Source.Height);
bmp.Canvas.Pen.Style := psClear;
bmp.Canvas.Brush.Style := bsSolid;
bmp.Canvas.Brush.Color := clFuchsia;
bmp.Canvas.Rectangle(0,0, Source.Width+1,Source.Height+1 );
bmp.Canvas.Draw(0,0, Source.Picture.Graphic );
bmp.TransparentColor := clFuchsia;
DestSpeedButton.Glyph:=bmp;
finally
bmp.Free;
end;
end;
Alternative that uses more memory, and is using the TPicture
type instead of TImage
because in real use I don't even have a TImage
just a TPicture
, also this looks nicer. Note that it is written around some custom control of my own design (or yours) that has some property type TBitmap. You have to substitute your own controls, or change TMyControlWithAGlyph to TSpeedButton if that's what you want to do:
// A Bit Better Looking. Uses Vcl.GraphUtils function ScaleImage
procedure CopyBitmap( Source:TPicture;
Dest:TMyControlWithAGlyph;
DestType:TCopyDestTypeEnum;
AWidth,AHeight:Integer;
DoInvert:Boolean;
TransparentColor:TColor=clFuchsia );
var
bmp,bmpFullSize: TBitmap;
ARect:TRect;
ScaleAmount:Double;
begin
if not Assigned(Source) then
exit;
if not Assigned(Dest) then
exit;
if not Assigned(Source.Graphic) then
exit;
bmp:=TBitmap.Create;
bmpFullSize := TBitmap.Create;
try
bmpFullSize.SetSize( Source.Width, Source.Height );
bmpFullSize.PixelFormat := pf24bit;
bmpFullSize.Canvas.Pen.Style := psClear;
bmpFullSize.Canvas.Brush.Style := bsSolid;
bmpFullSize.Canvas.Brush.Color := TransparentColor;
bmpFullSize.Canvas.Rectangle(0,0, Source.Width+1,Source.Height+1 );
bmpFullSize.Canvas.Draw(0,0, Source.Graphic );
bmp.SetSize( AWidth, AHeight);
bmp.PixelFormat := pf24bit;
// Vcl.GraphiUtil version needs a floating point scale.
ScaleAmount := AWidth / Source.Width;
ScaleImage(bmpFullSize,bmp,ScaleAmount );
// This lets me have a white icon and turn it black if I want to
// or vice versa
if DoInvert then
InvertBitmap(bmp);
if DestType=DestLargeGlyph then
begin
Dest.LargeGlyph := bmp;
end
else
begin
Dest.Glyph:=bmp;
end;
finally
bmp.Free;
bmpFullSize.Free;
end;
end;
The above code also calls this little helper:
function InvertBitmap(ABitmap: TBitmap): TBitmap;
var
x, y: Integer;
ByteArray: PByteArray;
begin
ABitmap.PixelFormat := pf24Bit;
for y := 0 to ABitmap.Height - 1 do
begin
ByteArray := ABitmap.ScanLine[y];
for x := 0 to ABitmap.Width * 3 - 1 do
begin
ByteArray[x] := 255 - ByteArray[x];
end;
end;
Result := ABitmap;
end;
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句