C# Image Edge Feathering - c#

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.

Related

Converting Bitmap to GDK# PixBuff

How can I convert a System.Drawing.Bitmap to GDK# Image so that I can set to the image widget.
I have tried this...
System.Drawing.Bitmap b = new Bitmap (1, 1);
Gdk.Image bmp = new Gdk.Image (b);
UPDATE:
Bitmap bmp=new Bitmap(50,50);
Graphics g=Graphics.FromImage(bmp);
System.Drawing.Font ff= new System.Drawing.Font (System.Drawing.FontFamily.GenericMonospace, 12.0F, FontStyle.Italic, GraphicsUnit.Pixel);
g.DrawString("hello world",ff,Brushes.Red,new PointF(0,0));
MemoryStream ms = new MemoryStream ();
bmp.Save (ms, ImageFormat.Png);
Gdk.Pixbuf pb= new Gdk.Pixbuf (ms);
image1.Pixbuf=pb;
Exception:
System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> GLib.GException: Unrecognized image file format
at Gdk.PixbufLoader.Close()
at Gdk.PixbufLoader.InitFromStream(Stream stream)
at Gdk.PixbufLoader..ctor(Stream stream)
at Gdk.Pixbuf..ctor(Stream stream)
One ugly, but working, way is to store the bitmap as a PNG in a MemoryStream.
To save the Bitmap, you can use the Save method:
b.Save(myMemoryStream, ImageFormat.Png);
That was easy enough. Loading the PNG data into the Gdk# Pixbuf is also rather easy; you can use the appropriate constructor:
Pixbuf pb = new Gdk.Pixbuf(myMemoryStream);
You may need to reset the memory stream so the reading position is at the start of the stream before creating the Pixbuf.
A word of caution: I do not consider this the best, or even a "good" solution. Transferring data between two object-oriented data structures by serializing and deserializing the data has a certain code smell to it. I genuinely hope someone else can come up with a better solution.
EDIT: As for the used libraries: This answer uses only plain GDI+ (System.Drawing.Bitmap) and Gdk# (Gdk.Pixbuf). Note that a Gtk.Image is a widget that displays a Gdk.Pixbuf. As such, Gtk.Image is the equivalent of Windows Forms' PictureBox, whereas Gdk.Pixbuf is roughly equivalent to Windows Forms' System.Drawing.Bitmap.
EDIT2: After testing your code, I have found that there are three additional preconditions to ensure before you can run your minimum example:
As suspected above, you must reset the stream position to the beginning of the after saving your Bitmap and before loading your Pixbuf: ms.Position = 0;
You must compile the application for x86 CPUs.
You must invoke Gtk.Application.Init(); before you do anything with Pixbuf.
You may draw in Gtk# like in Winforms. For this you must obtain System.Drawing.Graphics object and then you may draw lines, images and text on it. You may do it like this: 1. Create new Widget. 2. Subscribe on ExposeEvent. 3. On event handler write some code:
protected void OnExposeEvent(object o, ExposeEventArgs e)
{
Gdk.Window window = e.Event.Window;
using (System.Drawing.Graphics graphics =
Gtk.DotNet.Graphics.FromDrawable(window))
{
// draw your stuff here...
graphics.DrawLine(new System.Drawing.Pen(System.Drawing.Brushes.Black), 0, 0, 30, 40);
}
}
Also you need to add reference on gtk-dotnet.dll.
try this ....
Gdk.Pixbuf pixbufImage = mew Gdk.Pixbuf(#"images/test.png");
Gtk.Image gtkImage = new Gtk.Image(pixbufImage);
Gdk.Image gdkImage = gtkImage.ImageProp;

Image manipulation

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");
}

Extrating image information about a PNG in .NET

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

Mono Ignores Graphics.InterpolationMode?

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

C# Convert indexed pixel to new file bit32

Does anybody have a sample code on how i could open a tif file, copy it out to a new locate from indexed pixel to new bitmap 32?
I found this http://fci-h.blogspot.com/2008/02/c-indexed-pixel-problem.html But i'm to new to piece it together. Is there a possible way to just read this all in memory without actually creating a new file?
What I mean is this. I have to find the original file (which i already got). Copy the file to a temp location (which I got). What I don't understand is how when I copy that new file I need to keep the original size and give the new file a bitmap of 32.
I can't draw an image over the picturebox because C# doesnt really support indexed pixels.
Bitmap newImage = new Bitmap(original);
This will make your newImage start with the contents of original. The difference will be that you will end up with newImage.PixelFormat == PixelFormat.Format32bppArgb, regardless of original.PixelFormat.
This does what you want I think...
If you dont need to save it, just work with 'bm' after you do the DrawImage, that is your image as a Bitmap...
Bitmap bm = (Bitmap)System.Drawing.Image.FromFile("TifFilePath.tif", true);
Bitmap tmp = new Bitmap(bm.Width, bm.Height);
Graphics grPhoto = Graphics.FromImage(tmp);
grPhoto.DrawImage(bm, new Rectangle(0, 0, tmp.Width, tmp.Height), 0, 0, tmp.Width, tmp.Height, GraphicsUnit.Pixel);
bm.Save("JPGFilePath.jpg", System.Drawing.Imaging.ImageFormat.Jpeg);
grPhoto.Dispose();

Categories

Resources