WinForms .NET 2.0: How to paint the proper sized icon? - winforms

i have an ico file that contains a 48x48 and a 256x256 Vista PNG version (as well as the 32x32 and 16x16 versions). i want to draw the icon using the appropriate internal size version.
i've tried:
Icon ico = Properties.Resources.TestIcon;
e.Graphics.DrawIcon(ico, new Rectangle(0, 0, 48, 48));
e.Graphics.DrawIcon(ico, new Rectangle(48, 0, 256, 256));
But they draw the 32x32 version blown up to 48x48 and 256x256 respectively.
i've tried:
Icon ico = Properties.Resources.TestIcon;
e.Graphics.DrawIconUnstretched(ico, new Rectangle(0, 0, 48, 48));
e.Graphics.DrawIconUnstretched(ico, new Rectangle(48 0, 256, 256));
But those draw the 32x32 version unstretched.
i've tried:
Icon ico = Properties.Resources.TestIcon;
e.Graphics.DrawImage(ico.ToBitmap(), new Rectangle(0, 0, 48, 48));
e.Graphics.DrawImage(ico.ToBitmap(), new Rectangle(48, 0, 256, 256));
But those draw a stretched version of the 32x32 icon.
How do i make the icon draw itself using the appropriate size?
Additionally, i want to draw using the 16x16 version. i've tried:
Icon ico = Properties.Resources.TestIcon;
e.Graphics.DrawIcon(ico, new Rectangle(0, 0, 16, 16));
e.Graphics.DrawIconUnstretched(ico, new Rectangle(24, 0, 16, 16));
e.Graphics.DrawImage(ico.ToBitmap(), new Rectangle(48, 0, 16, 16));
But all those use the 32x32 version scaled down, except for the Unstretched call, which crops it to 16x16.
How do i make the icon draw itself using the appropriate size?
Following schnaader's suggestion of constructing a copy of the icon with the size you need doesn't work for 256x256 size. i.e. the following does not work (it uses a scaled version of the 48x48 icon):
e.Graphics.DrawIcon(
new Icon(ico, new Size(256, 256)),
new Rectangle(0, 0, 256, 256));
While the following two do work:
e.Graphics.DrawIcon(
new Icon(ico, new Size(16, 16)),
new Rectangle(0, 0, 16, 16));
e.Graphics.DrawIcon(
new Icon(ico, new Size(48, 48)),
new Rectangle(0, 0, 48, 48));

Today, I made a very nice function for extracting the 256x256 Bitmaps from Vista icons.
I use it to display the large icon ( 256x256 ) as a Bitmap in "About" box. For example, this code gets Vista icon as PNG image, and displays it in a 256x256 PictureBox:
picboxAppLogo.Image = ExtractVistaIcon(Icon.ExtractAssociatedIcon(myIcon));
This function takes Icon object as a parameter. So, you can use it with any icons - from resources, from files, from streams, and so on. (Read below about extracting EXE icon).
It runs on any OS, because it does not use any Win32 API, it is 100% managed code :-)
// Based on: http://www.codeproject.com/KB/cs/IconExtractor.aspx
// And a hint from: http://www.codeproject.com/KB/cs/IconLib.aspx
Bitmap ExtractVistaIcon(Icon icoIcon)
{
Bitmap bmpPngExtracted = null;
try
{
byte[] srcBuf = null;
using (System.IO.MemoryStream stream = new System.IO.MemoryStream())
{ icoIcon.Save(stream); srcBuf = stream.ToArray(); }
const int SizeICONDIR = 6;
const int SizeICONDIRENTRY = 16;
int iCount = BitConverter.ToInt16(srcBuf, 4);
for (int iIndex=0; iIndex<iCount; iIndex++)
{
int iWidth = srcBuf[SizeICONDIR + SizeICONDIRENTRY * iIndex];
int iHeight = srcBuf[SizeICONDIR + SizeICONDIRENTRY * iIndex + 1];
int iBitCount = BitConverter.ToInt16(srcBuf, SizeICONDIR + SizeICONDIRENTRY * iIndex + 6);
if (iWidth == 0 && iHeight == 0 && iBitCount == 32)
{
int iImageSize = BitConverter.ToInt32(srcBuf, SizeICONDIR + SizeICONDIRENTRY * iIndex + 8);
int iImageOffset = BitConverter.ToInt32(srcBuf, SizeICONDIR + SizeICONDIRENTRY * iIndex + 12);
System.IO.MemoryStream destStream = new System.IO.MemoryStream();
System.IO.BinaryWriter writer = new System.IO.BinaryWriter(destStream);
writer.Write(srcBuf, iImageOffset, iImageSize);
destStream.Seek(0, System.IO.SeekOrigin.Begin);
bmpPngExtracted = new Bitmap(destStream); // This is PNG! :)
break;
}
}
}
catch { return null; }
return bmpPngExtracted;
}
IMPORTANT! If you want to load this icon directly from EXE file, then you CAN'T use Icon.ExtractAssociatedIcon(Application.ExecutablePath) as a parameter, because .NET function ExtractAssociatedIcon() is so stupid, it extracts ONLY 32x32 icon!
Instead, you better use the whole IconExtractor class, created by Tsuda Kageyu (http://www.codeproject.com/KB/cs/IconExtractor.aspx). You can slightly simplify this class, to make it smaller. Use IconExtractor this way:
// Getting FILL icon set from EXE, and extracting 256x256 version for logo...
using (TKageyu.Utils.IconExtractor IconEx = new TKageyu.Utils.IconExtractor(Application.ExecutablePath))
{
Icon icoAppIcon = IconEx.GetIcon(0); // Because standard System.Drawing.Icon.ExtractAssociatedIcon() returns ONLY 32x32.
picboxAppLogo.Image = ExtractVistaIcon(icoAppIcon);
}
Note: I'm still using my ExtractVistaIcon() function here, because I don't like how IconExtractor handles this job - first, it extracts all icon formats by using IconExtractor.SplitIcon(icoAppIcon), and then you have to know the exact 256x256 icon index to get the desired vista-icon. So, using my ExtractVistaIcon() here is much faster and simplier way :)

Related

Form design via Region property in winform getting removed

I have customized winform-design using region property as follows,
Region = System.Drawing.Region.FromHrgn(CreateRoundRectRgn(0, 0, varPassedInConstructor * 9, Height, 10, 10));
And here calling winform through following code in a new thread
new Thread(new ThreadStart(() => {
toast toast = new toast(message);
toast.Show(nativeWindow);
toast.Refresh();
Thread.Sleep(3000);
while (toast.Opacity > 0)
{
toast.Opacity -= 0.04;
Thread.Sleep(100);
}
toast.Close();
toast.Dispose();
})).Start();
Everything goes well, form is displayed properly initially, but before closing all of sudden, changes applied via Region gets disappeared and form appears like the one that is at design time.
Image one, When initially form displayed,
Image two, just before form is getting closed,
I tried lots of diff thing, I am not getting what exactly problem is, so all help will be appreciated.
Finally, I got the fix, instead of using CreateRoundRectRgn from GDI32 used a GraphicsPath approach as follows,
private void SetRegion()
{
var GP = RoundedRect(this.ClientRectangle, 5);
this.Region = new Region(GP);
}
And here is code for RoundRect function (Credit goes to https://stackoverflow.com/a/33853557/3531672),
public static GraphicsPath RoundedRect(Rectangle bounds, int radius)
{
int diameter = radius * 2;
Size size = new Size(diameter, diameter);
Rectangle arc = new Rectangle(bounds.Location, size);
GraphicsPath path = new GraphicsPath();
if (radius == 0)
{
path.AddRectangle(bounds);
return path;
}
// top left arc
path.AddArc(arc, 180, 90);
// top right arc
arc.X = bounds.Right - diameter;
path.AddArc(arc, 270, 90);
// bottom right arc
arc.Y = bounds.Bottom - diameter;
path.AddArc(arc, 0, 90);
// bottom left arc
arc.X = bounds.Left;
path.AddArc(arc, 90, 90);
path.CloseFigure();
return path;
}
then in constructor simply had set size of form itself and called SetRegion defined above,
this.Width = toastMessage.Length * 9;
SetRegion();
Please note additionally, I would recommend to override OnSizeChanged and simply call SetRegion in it.

How to set width of line in 3D

Am using SharpDX on DirectX 9 to draw a line.
Line is drawn correctly with the following code.
Vector3 startPoint= ...
Vector3 endPoint = ...
Vector3[] data = new Vector3[] { startPoint, endPoint };
device.DrawUserPrimitives<Vector3>(PrimitiveType.LineList, 1, data);
Question 1: How do we set the width of line?
Question 2: If a graphics card is used, then line width is less.
if there is no graphics card, a thicker line has been drawn.
Answer to Question 1
Using Line class, we can set the width of line.
Matrix worldViewProjection = worldMatrix * viewMatrix * projectionMatrix;
Line line = new Line(device);
line.Width = 2;
ColorBGRA lineColor = new ColorBGRA(255, 0, 0, 255);
line.Begin();
line.DrawTransform(new Vector3[] { anchorPoint, cursorPoint }, worldViewProjection, lineColor);
line.End();
Question 2 is still unanswered.

Saving PNG with alpha channel

I'm trying to save a WriteableBitmap to png but always end up with a 24 bit image (no alpha channel).
WriteableBitmap image = new WriteableBitmap(100, 100, 600, 600, PixelFormats.Bgra32, null);
int stride = image.PixelWidth * image.Format.BitsPerPixel / 8;
image.WritePixels(new System.Windows.Int32Rect(0, 0, image.PixelWidth, image.PixelHeight), emptyArray, stride, 0);
FileStream filestream = new FileStream(imageSrc, FileMode.Create);
PngBitmapEncoder encoder = new PngBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create((image)));
encoder.Save(filestream);
emptyArray is an array with all pixels being (255, 0, 0, 0) so I can test if the saving has worked.
Any ideas?
I managed to find the problem: the file was altered some place else and overwrote the intial image. So the initial saving of the image worked fine. Sorry for the hassle!

Workaround for PictureBox Zoom antialiasing bug?

A PictureBox which has SizeMode.Zoom and enlarges the source image adds white at the bottom and right edges. Anyone have a simple proven workaround? I beleive the bug is in GDI+ so the obvious custom repaint will not fix it. Currently I'm using WPF which I want to avoid.
I'll even settle for a kluge that replaces the bad white with black :)
Example: from a source having single central white pixel, instead of this:
it gives this:
The code is:
private void PictureBoxZoomBug()
{
BitmapSource bitmapSource =
BitmapSource.Create(3, 3, 96, 96, System.Windows.Media.PixelFormats.Gray8, null,
new byte[] { 0, 0, 0, 0, 0xFF, 0, 0, 0, 0 }, 3);
TestDiscamImage.Source = bitmapSource; // OK
Bitmap bitmap;
using (MemoryStream stream = new MemoryStream())
{
PngBitmapEncoder enc = new PngBitmapEncoder();
enc.Frames.Add(BitmapFrame.Create(bitmapSource));
enc.Save(stream);
bitmap = new System.Drawing.Bitmap(stream);
}
TestDiscamCapture_pictureBox.Image = bitmap; // Extra white at bottom and right
}
Thanks

Problems with rendering text as bitmaps using WPF

I am developing an application using WPF to dynamically render content, including text and images from WPF into jpg files. I am currently using the RenderTargetBitmap class to do the job. Everything works as expected but the quality of the rendered fonts is terrible. I understand that the RenderTargetBitmap doesn’t use the ClearType but a GrayScale antialias, which is kind of blury with small fonts. But I am using large fonts, larger than 30 pts, and the results are totally unacceptable. Is there some kind of workaround for this issue?
[Update]
The Code I am using is listed below. As expected it is called on each Rendering event of the CompositionTarget.
void CompositionTarget_Rendering(object sender, EventArgs e)
{
prefix = "";
if (counter < 10)
{
prefix = "000";
}
else if (counter < 100)
{
prefix = "00";
}
else if (counter < 1000)
{
prefix = "0";
}
Size size = new Size(MainCanvas.Width, MainCanvas.Height);
MainCanvas.Measure(size);
MainCanvas.Arrange(new Rect(size));
RenderTargetBitmap bmp = new RenderTargetBitmap(imgWidth, imgHeight, 96d, 96d, PixelFormats.Default);
bmp.Render(MainCanvas);
JpegBitmapEncoder encoder = new JpegBitmapEncoder();
encoder.QualityLevel = 90;
encoder.Frames.Add(BitmapFrame.Create(bmp));
string file = basePath + prefix + counter.ToString() + "_testpic.jpg";
using (Stream stm = File.Create(file))
{
encoder.Save(stm);
}
counter++;
}
Here are some examples of the resulting images:
alt text http://www.randomnoise.org/temp/testpic_v1.jpg
alt text http://www.randomnoise.org/temp/testpic_v2.jpg
Thanks in advance.
Try this:
int height = (int)border.ActualHeight;
int width = (int)border.ActualWidth;
RenderTargetBitmap bmp = new RenderTargetBitmap(width, height, 96, 96, PixelFormats.Pbgra32);
bmp.Render(border);
border being what you're trying to save as bitmap.
Ok, I finally found a solution. Gustavo you were on the right track. The problem was that the main container that I was trying to render as bitmap was being distorted by its parent container. The solution was to add the main container to a canvas, that doesn't have a layout engine that distorts its children. I still need to do some more experimenting but it looks very promising. Apparently RenderTargetBitmap doesn't like distorted fonts at all.

Resources