How to draw the sharpest possible image? - c#

I know most people are always trying to get smooth settings but this time, since I am printing a barcode, I need to find out how to tell e.Graphics to print my image with the sharpest possible settings. Keep in mind that my current settings produce the best I was able to test so far but, once i print it to a file and zoom in 500%, you can still see a bit of smoothness.
Here's my code so far:
private void printDocument1_PrintPage_1(object sender, PrintPageEventArgs e)
{
double pdf417_widthDPI = Math.Round(((double)picpdf417.Image.Width / (double)288) * 2, 2);
double pdf417_heightDPI = Math.Round(((double)picpdf417.Image.Height / (double)288) * 2, 2);
int newWidth = (int)Math.Round(pdf417_widthDPI * 96);
int newHeight = (int)Math.Round(pdf417_heightDPI * 96);
Rectangle pdf417_location_size = new Rectangle(0, 100, newWidth, newHeight);
e.Graphics.CompositingQuality = CompositingQuality.HighSpeed;
e.Graphics.SmoothingMode = SmoothingMode.None;
e.Graphics.InterpolationMode = InterpolationMode.Low;
e.Graphics.PixelOffsetMode = PixelOffsetMode.None;
e.Graphics.DrawImage(picpdf417.Image, pdf417_location_size);
}

Related

GDI Resize Image & Guarantee Height

I'm dynamically creating isometric tiles from standard top-down tiles from another game. The problem, though, is that the the image resize often ends up with some amount of pixels "missing" on either side. I understand they're not really missing and the code is working properly but I don't know enough about GDI to know what settings/tutorials to search for.
I take this: and turn it into this: .
It goes from 32x32 to 48x24, which is the correct proportion. However, on the left and bottom, the grass is one pixel short of reaching the edge of the image. I don't want to fix this manually as I'll be doing this for hundreds of tiles so I'd like to find a way to fix this in the code. The issue, in the end, is that the tiles end up with tiny one-pixel gaps between them.
Is there anything I can do with GDI other than just checking each image for the edge colors and adding them manually if they're missing/transparent?
Here's the code I used to do this. The commented out parts are some of the various settings I've been messing with:
Bitmap bmp = RotateImage(new Bitmap(fileName), 45);
bmp = ResizeImage(bmp, bmp.Width, bmp.Height / 2);
private static Bitmap RotateImage(Bitmap rotateMe, float angle)
{
//First, re-center the image in a larger image that has a margin/frame
//to compensate for the rotated image's increased size
var bmp = new Bitmap(rotateMe.Width + (rotateMe.Width / 2), rotateMe.Height + (rotateMe.Height / 2));
using (Graphics g = Graphics.FromImage(bmp))
g.DrawImageUnscaled(rotateMe, (rotateMe.Width / 4), (rotateMe.Height / 4), bmp.Width, bmp.Height);
rotateMe = bmp;
//Now, actually rotate the image
Bitmap rotatedImage = new Bitmap(rotateMe.Width, rotateMe.Height);
using (Graphics g = Graphics.FromImage(rotatedImage))
{
g.TranslateTransform(rotateMe.Width / 2, rotateMe.Height / 2); //set the rotation point as the center into the matrix
g.RotateTransform(angle); //rotate
g.TranslateTransform(-rotateMe.Width / 2, -rotateMe.Height / 2); //restore rotation point into the matrix
g.DrawImage(rotateMe, new Point(0, 0)); //draw the image on the new bitmap
}
return rotatedImage;
}
private static Bitmap ResizeImage(System.Drawing.Image image, int width, int height)
{
var destRect = new Rectangle(0, 0, width, height);
var destImage = new Bitmap(width, height);
destImage.SetResolution(image.HorizontalResolution, image.VerticalResolution);
using (var graphics = Graphics.FromImage(destImage))
{
//graphics.CompositingMode = CompositingMode.SourceCopy;
//graphics.CompositingQuality = CompositingQuality.HighQuality;
//graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
//graphics.SmoothingMode = SmoothingMode.HighQuality;
//graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
graphics.InterpolationMode = InterpolationMode.NearestNeighbor;
graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
graphics.SmoothingMode = SmoothingMode.AntiAlias;
using (var wrapMode = new ImageAttributes())
{
wrapMode.SetWrapMode(WrapMode.TileFlipXY);
graphics.DrawImage(image, destRect, 0, 0, image.Width, image.Height, GraphicsUnit.Pixel, wrapMode);
}
}
return destImage;
}
You might want to consider calculating the Width and Height of your rotated object.
For example:
private void button1_Click(object sender, EventArgs e)
{
var width = (int) numericUpDown2.Value;
var height = (int) numericUpDown3.Value;
var angle = (float) numericUpDown1.Value;
var size = new Size(width, height);
var result = RotatedSettings(angle, size);
textBox1.Text = String.Format("{0} x {1}", result.Width, result.Height);
}
private static Size RotatedSettings(float angle, Size size)
{
// setup corner values in array
var corners = new[]
{ new PointF(0, 0),
new PointF(size.Width, 0),
new PointF(0, size.Height),
new PointF(size.Width, size.Height)};
// rotate corners
var xc = corners.Select(p => Rotate(p, (float)angle).X);
var yc = corners.Select(p => Rotate(p, (float)angle).Y);
// find the new sizes by subtracting highest from lowest result.
var widths = xc as IList<float> ?? xc.ToList();
var newWidth = (int)Math.Abs(widths.Max() - widths.Min());
var heights = yc as IList<float> ?? yc.ToList();
var newHeight = (int)Math.Abs(heights.Max() - heights.Min());
// as we rotate the mid point we need to middle midpoint section and add the outcome to size.
var midX = ((size.Width / 2) - ((double)newWidth / 2));
var midY = ((size.Height / 2) - ((double)newHeight / 2));
return new Size(newWidth + (int)midX, newHeight + (int)midY);
}
/// <summary>
/// Rotates a point around the origin (0,0)
/// </summary>
private static PointF Rotate(PointF p, float angle)
{
// convert from angle to radians
var theta = Math.PI * angle / 180;
return new PointF(
(float)(Math.Cos(theta) * (p.X) - Math.Sin(theta) * (p.Y)),
(float)(Math.Sin(theta) * (p.X) + Math.Cos(theta) * (p.Y)));
}

C# Resize Image with No Interpolation

I know this question has been asked frequently, but none of the typical answers have given me the result I need. I am attempting to zoom a grayscale bitmap much like Paint.exe. I want no interpolation so the original, individual pixels can be observed. I have tried the oft-suggested NearestNeighbor approach which gets close, but not exactly what I want.
This is what I want:
This is what I get:
This is the code I am using to zoom and redraw the image.
protected override void OnPaint(PaintEventArgs e)
{
e.Graphics.PixelOffsetMode = PixelOffsetMode.Half;
e.Graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor;
e.Graphics.SmoothingMode = SmoothingMode.None;
Matrix m = new Matrix();
m.Scale(mScale, mScale, MatrixOrder.Append);
e.Graphics.Transform = m;
e.Graphics.TranslateTransform(this.AutoScrollPosition.X / mScale,this.AutoScrollPosition.Y / mScale);
if (mImage != null)
e.Graphics.DrawImage(mImage, 0, 0);
base.OnPaint(e);
}
The code does have an affect on the image as the zoom works and changing the InterpolationMode does change the image. However, no combination of settings gets the result I need.
Any ideas?
I'm trying to display 16-bit images with C#. I came across the same trouble that the colors in the totally same pixel is not the same. Finally I solved this trouble with the sample code below:
protected override void OnPaint(PaintEventArgs e)
{
e.Graphics.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
e.Graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor;
e.Graphics.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.HighSpeed;
e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.None;
e.Graphics.Clear(Color.Black); //Clear the background with the black color
if(m_bmp != null) //if m_bmp == null, then do nothing.
{
//To calculate the proper display area's width and height that fit the window.
if (this.Width / (double)this.Height > m_bmp.Width / (double)m_bmp.Height)
{
m_draw_height = (int)(this.Height * m_roomRatio);
m_draw_width = (int)(m_bmp.Width / (double)m_bmp.Height * m_draw_height);
}
else
{
m_draw_width = (int)(this.Width * m_roomRatio);
m_draw_height = (int)(m_bmp.Height / (double)m_bmp.Width * m_draw_width);
}
//To calculate the starting point.
m_draw_x = (int)((this.Width - m_draw_width) / 2.0 + m_offsetX / 2.0);
m_draw_y = (int)((this.Height - m_draw_height) / 2.0 + m_offsetY / 2.0);
e.Graphics.DrawImage(m_bmp, m_draw_x, m_draw_y, m_draw_width, m_draw_height);
//draw some useful information
string window_info = "m_draw_x" + m_draw_x.ToString() + "m_draw_width" + m_draw_width.ToString();
e.Graphics.DrawString(window_info, this.Font, new SolidBrush(Color.Yellow), 0, 20);
}
BTW, why don't you try to use double buffer to increase the performance of drawing images?
Here is the effect:
Hope that will help.

Print High Resolution Image in C#

I am printing image 2349 x 3600 pixels. I have resized image but printing is blurred not clean. Please looke at code -
using System.Drawing.Drawing2D;
public Bitmap resizeimage(Bitmap bitmap)
{
Bitmap result = new Bitmap(850, 1101);
using (Graphics grap = Graphics.FromImage(result))
{
grap.CompositingQuality = CompositingQuality.HighQuality;
grap.InterpolationMode = InterpolationMode.Bicubic;
grap.SmoothingMode = SmoothingMode.HighQuality;
grap.CompositingQuality = CompositingQuality.HighQuality;
grap.DrawImage(bitmap, 0, 0, 850, 1101);
}
return result;
}
I tried everything from changing bitmap size, quality of graphics but still image blurred.
I used microsoft office 2007 and resized image and printed it , it was so clear.
How I can get exact printing quality as I got in microsoft office 2007.
Please help.
Here is code before drawing -
PrintPreviewDialog printpreview = new PrintPreviewDialog();
PrintDocument printdocument = new PrintDocument();
printdocument.PrinterSettings.PrinterName = "EPSON L100 Series";
int horizantal_dpi = printdocument.PrinterSettings.DefaultPageSettings.PrinterResolution.X;
int vertical_dpi = printdocument.PrinterSettings.DefaultPageSettings.PrinterResolution.Y;
decimal final_width_dpi = (((int)printdocument.DefaultPageSettings.PrintableArea.Width * horizantal_dpi) / 100);
decimal final_height_dpi = (((int)printdocument.DefaultPageSettings.PrintableArea.Height * vertical_dpi ) / 100);
printimagaprint = new Bitmap((int)final_width_dpi, (int)final_height_dpi);
//set resoultion
printimagaprint.SetResolution(horizantal_dpi, vertical_dpi);
Graphics g = System.Drawing.Graphics.FromImage(printimagaprint);
g.DrawImage(bitmap, 0, 0, printimagaprint.Width, printimagaprint.Height);
printdocument.PrintPage +=new PrintPageEventHandler(printdocument_PrintPage);
//printdocument.Print();
printdocument.DocumentName = textBox1.Text;
printpreview.Document = printdocument;
printpreview.ShowDialog();
Try matching the printer resolution before printing.
printDialog.PrinterSettings.PrinterName = GetTargetPrinter();
int horizontal_dpi = printDialog.PrinterSettings.DefaultPageSettings.PrinterResolution.X;
int vertical_dpi = printDialog.PrinterSettings.DefaultPageSettings.PrinterResolution.Y;
Decimal final_width_dpi = (((int)printDialog.PrinterSettings.DefaultPageSettings.PrintableArea.Width * horizontal_dpi) / 100);
Decimal final_height_dpi = (((int)printDialog.PrinterSettings.DefaultPageSettings.PrintableArea.Height * vertical_dpi) / 100);
printImage = new Bitmap((int)final_width_dpi, (int)final_height_dpi);
// Set Resolution
printImage.SetResolution(horizontal_dpi, vertical_dpi);
Graphics g = System.Drawing.Graphics.FromImage(printImage);
And please try to provide more descriptive code. I am just making assumption for now.

Asp.Net: Dynamic image resize

I want to create an image resize mechanism for my Asp.Net web site project like timthumb. I want to do this:
Upload image
Set a size
If I need another size of this image I can give "only" size without upload again.
How can I do this, do you have any suggestion?
Here is my resizing function:
public Bitmap Resize(Bitmap image, int newWidth, int newHeight, string message)
{
try
{
Bitmap newImage = new Bitmap(newWidth, Calculations(image.Width, image.Height, newWidth));
using (Graphics gr = Graphics.FromImage(newImage))
{
gr.SmoothingMode = SmoothingMode.AntiAlias;
gr.InterpolationMode = InterpolationMode.HighQualityBicubic;
gr.PixelOffsetMode = PixelOffsetMode.HighQuality;
gr.DrawImage(image, new Rectangle(0, 0, newImage.Width, newImage.Height));
var myBrush = new SolidBrush(Color.FromArgb(64, 205, 205, 205));
double diagonal = Math.Sqrt(newImage.Width * newImage.Width + newImage.Height * newImage.Height);
var containerBox = new Rectangle();
containerBox.X = (int)(diagonal / 10);
var messageLength = (float)(diagonal / message.Length * 1);
containerBox.Y = -(int)(messageLength / 1.6);
var stringFont = new Font("verdana", messageLength);
var sf = new StringFormat();
var slope = (float)(Math.Atan2(newImage.Height, newImage.Width) * 180 / Math.PI);
gr.RotateTransform(slope);
gr.DrawString(message, stringFont, myBrush, containerBox, sf);
return newImage;
}
}
catch (Exception exc)
{
throw exc;
}
}
public int Calculations(decimal orjWidth, decimal orjHeight, int newWidth)
{
decimal height = 0;
decimal ratio = 0;
if (newWidth < orjWidth)
{
ratio = orjWidth / newWidth;
height = orjHeight / ratio;
return height.To<int>();
}
if (orjWidth <= newWidth)
{
ratio = newWidth / orjWidth;
height = orjHeight * ratio;
return height.To<int>();
}
return height.To<int>();
}
That’s done with jQuery scripting.
You can achieve the same background image dynamic resize effect by using some of available jQuery plugins. Eg.: http://srobbin.com/jquery-plugins/backstretch/
Also, that can be done by using plain CSS3:
https://css-tricks.com/perfect-full-page-background-image/
Best regards, templateMonster Affiliate Team!
You're looking for the ImageResizer library & httpmodule
If you use NuGet, you can Install-Package ImageResizer.MvcWebConfig

Make square image

How to resample an image to square, padding with white background in c# preferable without using any 3rd party libraries (.Net framework only)?
Thanks!
This can actually be done pretty easily.
public static Image PadImage(Image originalImage)
{
int largestDimension = Math.Max(originalImage.Height, originalImage.Width);
Size squareSize = new Size(largestDimension, largestDimension);
Bitmap squareImage = new Bitmap(squareSize.Width, squareSize.Height);
using (Graphics graphics = Graphics.FromImage(squareImage))
{
graphics.FillRectangle(Brushes.White, 0, 0, squareSize.Width, squareSize.Height);
graphics.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
graphics.DrawImage(originalImage, (squareSize.Width / 2) - (originalImage.Width / 2), (squareSize.Height / 2) - (originalImage.Height / 2), originalImage.Width, originalImage.Height);
}
return squareImage;
}
Try using this method. The last argument is a switch for whether you want to stretch the image to fit. If false, the image is centered inside the new white canvas. You can pass a square or non-square size to it as needed.
public static Bitmap ResizeBitmapOnWhiteCanvas(Bitmap bmpOriginal, Size szTarget, bool Stretch)
{
Bitmap result = new Bitmap(szTarget.Width, szTarget.Height);
using (Graphics g = Graphics.FromImage((Image)result))
{
g.InterpolationMode = InterpolationMode.NearestNeighbor;
g.FillRectangle(Brushes.White, new Rectangle(0, 0, szTarget.Width, szTarget.Height));
if (Stretch)
{
g.DrawImage(bmpOriginal, 0, 0, szTarget.Width, szTarget.Height); // fills the square (stretch)
}
else
{
float OriginalAR = bmpOriginal.Width / bmpOriginal.Height;
float TargetAR = szTarget.Width / szTarget.Height;
if (OriginalAR >= TargetAR)
{
// Original is wider than target
float X = 0F;
float Y = ((float)szTarget.Height / 2F) - ((float)szTarget.Width / (float)bmpOriginal.Width * (float)bmpOriginal.Height) / 2F;
float Width = szTarget.Width;
float Height = (float)szTarget.Width / (float)bmpOriginal.Width * (float)bmpOriginal.Height;
g.DrawImage(bmpOriginal, X, Y, Width, Height);
}
else
{
// Original is narrower than target
float X = ((float)szTarget.Width / 2F) - ((float)szTarget.Height / (float)bmpOriginal.Height * (float)bmpOriginal.Width) / 2F;
float Y = 0F;
float Width = (float)szTarget.Height / (float)bmpOriginal.Height * (float)bmpOriginal.Width;
float Height = szTarget.Height;
g.DrawImage(bmpOriginal, X, Y, Width, Height);
}
}
}
return result;
}
You don't say how you want it padded. Assuming you want the image centered, with the image file name in imageFileName and the desired output file name in newFileName:
Bitmap orig = new Bitmap(imageFileName);
int dim = Math.Max(orig.Width, orig.Height);
Bitmap dest;
using (Graphics origG = Graphics.FromImage(orig))
{
dest = new Bitmap(dim, dim, origG);
}
using (Graphics g = Graphics.FromImage(dest))
{
Pen white = new Pen(Color.White, 22);
g.FillRectangle(new SolidBrush(Color.White), 0, 0, dim, dim);
g.DrawImage(orig, new Point((dim - orig.Width) / 2, (dim - orig.Height) / 2));
}
dest.Save(newFileName);

Categories