I want to load the Glyph of a TSpeedButton at runtime from a TImageList. In that image list I have 32bit bitmaps (RGB + Alpha), not 24bit simple RGB. I load the glyph with the following code:
SpeedButton.Glyph.Canvas.Brush.Style:= bsClear;
SpeedButton.Glyph.PixelFormat:= pf32bit;
SpeedButton.NumGlyphs:= 2;
SpeedButton.Glyph.SetSize(ImgList.Width * 2, ImgList.Height);
ImgList.Draw(SpeedButton.Glyph.Canvas, 0, 0, idxCancelRed);
ImgList.Draw(SpeedButton.Glyph.Canvas, Pics.ImgList, 0, idxCancelRedDis);
The transparency it's ok, but the edges of the drawings (where the alpha color is present) are darker as if the alpha value it's not used, and that pixels are blended with some black background... Am I missing something or the TSpeedButton does not support alpha bitmaps (in which case I have to start making my own speed button control) ?
Related
I need to render a dropshadow of bitmap A onto bitmap B using Direct2D.
More specifically, A is 32-bit with alpha-transparency, i.e. some pixels can be transparent. B (also 32-bit) contains another image, i.e. it can't be assumed empty.
Can someone provide a working example of how to do that?
Preferably as a method that takes blur amount, distance, color and opacity of the dropshadow as parameters.
The C++ code I'm trying to convert is the below from MS. But I'm not sure about converting the C++ syntax and also the D2D2 libraries in Delphi XE2 seem to be incomplete.
ComPtr<ID2D1Effect> shadowEffect;
m_d2dContext->CreateEffect(CLSID_D2D1Shadow, &shadowEffect);
shadowEffect->SetInput(0, bitmap);
// Shadow is composited on top of a white surface to show opacity.
ComPtr<ID2D1Effect> floodEffect;
m_d2dContext->CreateEffect(CLSID_D2D1Flood, &floodEffect);
floodEffect->SetValue(D2D1_FLOOD_PROP_COLOR, D2D1::Vector4F(1.0f, 1.0f, 1.0f, 1.0f));
ComPtr<ID2D1Effect> affineTransformEffect;
m_d2dContext->CreateEffect(CLSID_D2D12DAffineTransform, &affineTransformEffect);
affineTransformEffect->SetInputEffect(0, shadowEffect.Get());
D2D1_MATRIX_3X2_F matrix = D2D1::Matrix3x2F::Translation(20, 20));
affineTransformEffect->SetValue(D2D1_2DAFFINETRANSFORM_PROP_TRANSFORM_MATRIX, matrix);
ComPtr<ID2D1Effect> compositeEffect;
m_d2dContext->CreateEffect(CLSID_D2D1Composite, &compositeEffect);
compositeEffect->SetInputEffect(0, floodEffect.Get());
compositeEffect->SetInputEffect(1, affineTransformEffect.Get());
compositeEffect->SetInput(2, bitmap);
m_d2dContext->BeginDraw();
m_d2dContext->DrawImage(compositeEffect.Get());
m_d2dContext->EndDraw();
I am trying to make a row color have 74% transparency.
My code:
TDBGrid(sender).canvas.brush.color := RGB(0,176,240);
But I can't figure out where to add transparency to brush?
gdi+ can support alpha channel for color, you can use gdi+ functions in any canvas
I want to create a TImage component and fill the image with a background color. However my code is a bit longer than I have expected.
I have to set the width and height of bitmap.
I have to calculate the rectangle of the whole bitmap canvas.
If I remember correctly, in old Delphi versions, I can use FloodFill to fill the whole image with particular color. So I think I have definitively missed something.
Can someone figure out how to fill background color with simpler code?
Image := TImage.Create(nil);
Image.Position.X := 100;
Image.Position.Y := 100;
Image.Width := 500;
Image.Height := 500;
Image.Bitmap.Width := Trunc(Image.Width);
Image.Bitmap.Height := Trunc(Image.Height);
with Image.Bitmap.Canvas do
begin
BeginScene;
try
Fill.Color := TAlphaColors.Black;
FillRect(RectF(0, 0, Image.Bitmap.Width, Image.Bitmap.Height), 0, 0, [], 1.0);
finally
EndScene;
end;
end;
There is no FloodFill in FMX. But you can use Clear(TAlphaColors.Black); in order to fill the entire bitmap with a color.
The reason why you have to set the Bitmap dimensions is becouse the Bitmap size is not necessary the same size as TImage. You can have smaller or larger Bitmap than TImage and then use one of WrapModes to determine how will that image be rendered to TImage:
The WrapMode property should be one of the constants defined in the TImageWrapMode type:
iwOriginal: displays the image with its original dimensions.
iwFit: best fit (keeping image proportions--the ratio between the width and height) for the TImage rectangle. Default.
iwStretch: stretches the image to fill the entire rectangle of this TImage component.
iwTile: tiles the TImage image to cover the entire rectangle of the TImage component.
As for calculating rectangle for the whole bitmap. If you want your bitmap to have the same size as TImage then you can easily read TImage.ClipRect.
ClipRect is generally the rectangle which represents the inner part of the control that you are able to render on. On controls that have borders like TPanel for instance ClipRect dimensions are smaller than the whole control dimensions.
And as it was already stated by Sebastian you can quickly fill the entire Bitmap surface background with a single color by using TBitmap.Clear method.
I have been experimenting with the Change HUE/Saturation example found on the EFG website: http://www.efg2.com/Lab/Library/Delphi/Graphics/Color.htm
I want to use the techniques found in that example to change the color values of some bitmaps (to be used on a TImage). There is one problem I am facing, and that is with TImages that have transparent bitmaps; I don't want the background color to change its HUE but rather just the actual image data.
Take this sample image we can work with (though any image with transparency can be used):
Download the Change HUE/Saturation demo from the link at the top.
Now Load the button image above into the ImageOriginal.
Set the Delta Saturation to 1.
Run the Project.
Some output results:
What I would like to happen here is keep the original background color (defined by the bottom left most pixel) and only adjust the hue for the rest of the image. So, the output results would actually look like this (edited in Paint.NET):
Allow me to use another sample image to test with that contains more image data:
As before with the first image sample, the results could be something like:
When the results I desire should be like so:
One idea I had was after the HUE change, replace the bottom left most color with the color from the original, but I am not sure if this is the correct approach or not, and even if it is I am not sure how to replace color X for another color. (Graphics and Math is beyond me).
For example, if I drew two blue color circles on Mickey's ear (the blue been the original transparent color from bottom left most pixel) and also colored his eyes:
Changing the HUE again may look like:
when in fact it should like this:
Simply put I would like to change the HUE of an image whether it be by the methods used from the EFG demo or another solution. The transparent color as defined by the bottom most left pixel should not be changed when the HUE is changed, this should remain the same as demonstrated in the sample images.
How can I change the HUE of a bitmap whilst retaining the background color?
The code you refer walks all pixels on the image to change hue/saturation. You can modify the code so that it does not interfere if a pixel has a specific color:
PROCEDURE TFormChangeHS.UpdateBitmap;
..
S : TReal;
V : TReal;
FixColor: TRGBTriple; // New variable
BEGIN
DeltaSaturation := SpinEditDeltaSaturation.Value;
NewHue := TrackBarHue.Position;
Bitmap := TBitmap.Create;
TRY
Bitmap.Width := ImageOriginal.Width;
Bitmap.Height := ImageOriginal.Height;
Bitmap.PixelFormat := ImageOriginal.Picture.Bitmap.PixelFormat;
ASSERT(Bitmap.PixelFormat = pf24bit);
// save bottom left color
FixColor := PRGBTripleArray(
ImageOriginal.Picture.Bitmap.ScanLine[Bitmap.Height - 1])^[0];
//--
FOR j := 0 TO Bitmap.Height-1 DO
BEGIN
RowIn := ImageOriginal.Picture.Bitmap.Scanline[j];
RowOut := Bitmap.Scanline[j];
FOR i := 0 TO Bitmap.Width-1 DO
BEGIN
WITH RowIn[i] DO
BEGIN
// copy the color to target and continue with next iteration
if (RowIn[i].rgbtBlue = FixColor.rgbtBlue) and
(RowIn[i].rgbtGreen = FixColor.rgbtGreen) and
(RowIn[i].rgbtRed = FixColor.rgbtRed) then begin
RowOut[i] := FixColor;
Continue;
end;
//--
// convert pixel coordinates to HSV
RGBtoHSV(rgbtRed, rgbtGreen, rgbtBlue, H, S, V);
END;
..
..
Output:
In theory, you can for example:
First, you have to determine what is the background... (probably picking the color of a specific pixel like delphi does...)
Then, with this background color, you can create a mask based on this color...
You duplicate the image... apply the hue...
You merge your 2 bitmaps using the mask...
I am using Stretched=True on a TImage with a 256x256 bitmap. This gets scaled down by 1,2,4 or 8. As expected, text on the bitmap gets more horrible the more I depart from '1'.
I notice though that Windows 7 explorer renders a scaled down version of the bitmap 'softer' and more pleasing. Is it possible to 'blur' a TBitmap in this way?
I suppose you mean Stretched = True on a TImage, not on A TBitmap.
Unfortunately TImage has no resamplers built in, when it comes to resizing images in it.
My recommendation would be to use Graphics32 as it supports a variety of resamplers (some are better for increasing size others for reducing size)
By using the HALFTONE StretchBltMode, you will get smoother results than the normal stretchdraw.
This will only work in windows 2000 and later
procedure SmoothResize();
var pt:TPoint;
h: HDC;
begin
h := imgMainPicture.Canvas.Handle;
// Previous call to StretchDraw
// imgMainPicture.Canvas.StretchDraw(Rect(0, 0, imgMainPicture.Width - 1,
// imgMainPicture.Height - 1), curPicture.AnnotatedBitmap);
// Normal StretchDraw uses STRETCH_DELETESCANS as StretchBltMode , HALFTONE should give better results
GetBrushOrgEx(h, pt);
SetStretchBltMode(h, HALFTONE);
SetBrushOrgEx(h, pt.x, pt.y, #pt);
StretchBlt(h, 0, 0, imgMainPicture.Width - 1,
imgMainPicture.Height - 1, curPicture.AnnotatedBitmap.Canvas.Handle,
0, 0, curPicture.Width,curPicture.Height,SRCCOPY);
end;