I have a program that draws some vector graphics using System.Drawing and the Graphics class. The anti-aliasing works, kindof okay, but for my need I neede oversampling, so I create the starting image to be n times larger and then scale back the final image by n. On Window and .NET the resulting image looks great! However, on Mono 2.4.2.3 (Ubuntu 9.10 stock install), the intropolation is horrible. Here's how I'm scaling my images:
Bitmap bmp = new Bitmap(Bmp.Width / OverSampling, Bmp.Height / OverSampling);
Graphics g = Graphics.FromImage(bmp);
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.DrawImage(Bmp, 0, 0, bmp.Width, bmp.Height);
g.Dispose();
From what I can tell there is no interpolation happening at all. Any ideas?
Well I found this: http://www.mail-archive.com/mono-devel-list#lists.ximian.com/msg18099.html
I guess the underlying code of Mono's drawing routines are at fault. YAY! Now I get to write my own downscaler.
See:
High quality image re-sampling in Mono/C#/ASP.NET
http://www.toptensoftware.com/blog/posts/17/high-quality-image-resampling-in-monolinux
Related
I'm doing some simple image resizing and rotation in an ASP.NET MVC 4 project, using the ImageResizer library. The problem is that when I use it to process 32-bpp CMYK JPEG files, it fails with an ArgumentException, but only on my (Windows Server 2008 R2) server - it works fine on my (Windows Vista) laptop.
The JPEG files in question aren't too large (700x500) or otherwise non-standard - all web browsers and Paint can open them just fine, even on the server in question itself. The JPEGs have been generated using ImageMagick, and everything works fine if I ask ImageMagick to use an RGB colorspace (-colorspace sRGB.)
The weird thing is, just resizing the image works fine in all cases, but it fails if I try to resize and rotate the image on the server.
It looks like some lower-level Win32 or GDI+ function call is what's failing here - here's the relevant part of the stack trace:
[ArgumentException: Parameter is not valid.]
System.Drawing.Graphics.CheckErrorStatus(Int32 status) +1621285
System.Drawing.Graphics.DrawImage(Image image, PointF[] destPoints, RectangleF srcRect, GraphicsUnit srcUnit, ImageAttributes imageAttr, DrawImageAbort callback, Int32 callbackData) +727
System.Drawing.Graphics.DrawImage(Image image, PointF[] destPoints, RectangleF srcRect, GraphicsUnit srcUnit, ImageAttributes imageAttr) +73
ImageResizer.ImageBuilder.RenderImage(ImageState s) +763
ImageResizer.ImageBuilder.Render(ImageState s) +174
ImageResizer.ImageBuilder.Process(ImageState s) +105
ImageResizer.ImageBuilder.buildToBitmap(Bitmap source, ResizeSettings settings, Boolean transparencySupported) +276
ImageResizer.ImageBuilder.buildToStream(Bitmap source, Stream dest, ResizeSettings settings) +149
ImageResizer.ImageBuilder.BuildJob(ImageJob job) +940
ImageResizer.ImageBuilder.Build(ImageJob job) +223
Any ideas?
After some more research and testing, I've found that the problem occurs only if the Bitmap.RotateFlip method has been called on the source bitmap, before it is drawn onto a target bitmap for cropping and resizing.
I ended up having to re-write the code using plain old System.Drawing myself, because there is no way to change the behavior of the ImageResizer library. Specifically, I wrote my own rotation function, which uses a transformation matrix to do the same thing.
private Bitmap RotateImage(Bitmap source, float angle)
{
if (angle == 0) return (Bitmap)source.Clone();
Bitmap target;
using (GraphicsPath path = new GraphicsPath())
using (Matrix matrix = new Matrix())
{
path.AddRectangle(new RectangleF(0.0f, 0.0f, source.Width, source.Height));
matrix.Rotate(angle);
RectangleF rect = path.GetBounds(matrix);
target = new Bitmap((int)Math.Round(rect.Width), (int)Math.Round(rect.Height));
target.SetResolution(source.HorizontalResolution, source.VerticalResolution);
using (Graphics g = Graphics.FromImage(target))
{
g.TranslateTransform(-rect.X, -rect.Y);
g.RotateTransform(angle);
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.DrawImageUnscaled(source, 0, 0);
}
}
return target;
}
I would have wanted to set the PixelFormat of the new Bitmap to the one from the source - but doing so throws weird GDI+ "Out of memory" errors on encountering the CMYK JPEG files in question. This makes me wonder if this odd behavior is linked to this GDI+ bug/quirk that returns different ImageFlags and PixelFormat values on Windows 7/Server 2008 R2 and Windows Vista/Server 2008.
DISCLAIMER: This code is terrible and should not be used in production. It's testing a proof of concept.
I want to create an image like below using C# the key points are the feathered edges and the transparency of the whole image.
Here is my result so far
As you can see the edges are feathered. My question is, does anyone know how to feather the edges using pure C# and maintain transparency, currently I am using a 3rd party library with some pretty nasty looking code?
Would be interested if there is a better approach to this full stop.
Here is some of the code I have been using.
Bitmap bitmap = new Bitmap(width, height);
Graphics graphics = Graphics.FromImage(bitmap);
// Transparent Background
SolidBrush semiTransparentPen = new SolidBrush(Color.FromArgb(60, 31, 31, 31));
graphics.FillRectangle(semiTransparentPen, 0f, 0f, bitmap.Width, bitmap.Height);
// Feather edges
Bitmap bitmap1 = new Bitmap(bitmap);
Bitmap bitmap2 = new Bitmap(bitmap);
fipbmp.makeEdgesTransparentHorzSigma(bitmap1, 4, 4);
fipbmp.makeEdgesTransparentVertSigma(bitmap2, 4, 4);
fipbmp.MergeBmp(bitmap, bitmap1, bitmap2);
MemoryStream memoryStream = new MemoryStream();
bitmap.Save(memoryStream, ImageFormat.Png);
byte[] buffer = memoryStream.ToArray();
You may find this blog post which I once wrote useful: Soft Edged Images in GDI+. That will show you a lot of what you need to know. In order to create smooth edges on an arbitrary shape you will also need a smoothing filter (which you'll then need to apply to the alpha channel), which you can read about here.
I need the easy to learn & fast method for generating image from background image, texts and after that saving as JPEG format.
What you can suggest? Any library or tutorial on this? Important criteria is simpleness.
in .Net 3.5/4 you can also use WPF/Media.Imaging as an alternative to GDI+
First create a DrawingVisual and a DrawingContext:
DrawingVisual visual = new DrawingVisual();
DrawingContext dc = visual.RenderOpen();
Then draw stuff on it:
dc.DrawRectangle(...);
dc.DrawText(...);
etc...
Make sure you close it:
dc.Close();
The great thing about WPF is everything in the GUI is actually a visual too, so if you prefer you don't have to use the code above to draw programatically, you can actually build up your visual in xaml on a window and then just render that straight to the RenderTargetBitmap.
Once you have built your visual you can render it to a file using an encoder (.Net has encoders for Jpeg, Png, Bmp, Gif, Tiff and Wmp).
// Create a render target to render your visual onto. The '96' values are the dpi's, you can set this as required.
RenderTargetBitmap frame = new RenderTargetBitmap((int)visual.ContentBounds.Width, (int)visual.ContentBounds.Height, 96, 96, PixelFormats.Pbgra32);
frame.Render(visual);
// Now encode the rendered target into Jpeg and output to a file.
JpegBitmapEncoder jpeg = new JpegBitmapEncoder();
jpeg.Frames.Add(BitmapFrame.Create(frame));
using (Stream fs = File.Create(#"c:\filename.jpg"))
{
jpeg.Save(fs);
}
There are some good MS Tutorials on Drawing Objects and WPF Graphics Rendering.
I usually do this using GDI+. There are lots of tutorials on this on the net, but basically what you need to do is something like this:
using(Image image = new Bitmap(Width, Height))
using (Graphics g = Graphics.FromImage(image)) {
g.Draw....
g.Draw....
image.Save(filename, ImageFormat.Jpeg);
}
The calls to Draw.... you can draw primitives, images, text and so forth.
Also remember that is text looks jagged, you have methods on the Graphics object to smooth this out. In this case g.TextRenderingHint = TextRenderingHint.AntiAlias;
There are also other options to make it look better, if you feel it is jagged. The default settings is geared more towards performance than quality, so if you want high quality you need to set this yourself. g.SmoothingMode set to for example HighQuality will make your round primitives look much smoother than the default configuration.
It's really easy to use, and to make the final image look like you want it to, so give it a try!
Instead of good old GDI+ you can use the more modern (and often faster) System.Windows.Media.Imaging APIs.
GDI+ and the System.Drawing namespace are what is required to do what you want. A basic example is below but there are many resources on the net detailing more advanced features:
using(Bitmap myBitmap = new Bitmap("C:\\backgroundImage.jpg"))
using(Graphics g = Graphics.FromImage(myBitmap))
{
g.DrawString("Text", new Font("Arial", 10), Brushes.White, new PointF(0, 0));
myBitmap.Save("C:\\newImage.jpg");
}
I'm trying to get information about a PNG file but I've yet to discover a comprehensive site to help me.
These are some of the semi useful code snippets I have:
Bitmap bmp = new Bitmap(pngFileName);
BitmapData bd = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadOnly,PixelFormat.Format48bppRgb);
and
Stream imageStreamSource = new FileStream(pngFileName, FileMode.Open, FileAccess.Read, FileShare.Read);
var decoder = new PngBitmapDecoder(imageStreamSource, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default);
BitmapSource bitmapSource = decoder.Frames[0];
With these I've been able to to get the image height and width. However I still need to discover the following information:
Is it RLE encoded?
Is it in native video format?
Is it rotated?
Does it use a grayscale palette?
Does it have a transparency?
Is it RGB or BGR?
I'd really appreciate some pointers on how to acheive this or links to good articles dealing with this. We're working with .NET 4.0
I'm not sure if that helps you, but the best I've seen so far, is to walk the image pixel by pixel in a loop and accomplish your different tasks.
See these answers for examples:
Detecting if a PNG image file is a Transparent image?
Detecting grayscale images with .Net
I am writing a program that resizes pictures like this:
Image originalImage = Image.FromFile(pathToOriginalPicture);
Bitmap b = new Bitmap(newWidth, newHeight);
Graphics g = Graphics.FromImage(b);
g.DrawImage(originalImage, 0, 0, newWidth, newHeight);
g.Dispose();
b.Save(pathToOutputPicture, ImageFormat.Jpeg);
I tried to set:
newWidth = originalImage.Width;
newHeight = originalImage.Height;
The result was that the rezised picture file became ~900K while the original file was ~4M.
Why this is happening ?
Is the quality of the original picture better than the resized one ? How?
I opened both pictures in Photoshop and I see that the original picture was 72ppi, while the resized one became 96ppi. Why is that ? Can I control this ?
Thanks a lot for your time !
You're not telling us the original format of your picture but you're saving as a JPEG:
b.Save(pathToOutputPicture, ImageFormat.Jpeg);
JPEG is a lossy compression format.
In addition to being lossy, JPEG also can output different quality (which is configurable).
This is what is happening to your file size: it is shrinking because you went, say, from a lossless format to the lossy JPEG or because you went from JPEG to JPEG-with-a-lower-quality.
Hence the size reduction.
Besides the format you need to set DPI, compression level settings etc. Check your Save function for overloads that will accept this type of input. See this documentation.