How do I overlay an image in .NET - c#

I have a .png image i wish to overlay on a base image.
My overlay image contains just a red slant line. I need to get the red line overlayed on the base image at the same co-ordinate as it is in overlay image.
The problem is I do not have the co-ordinates location.
I need to find it programmatically with C#. The overlay image will always be transparent or of white background. What code to find the line co-ordinates from overlay image?

You can create new image, render background image first and then render overlay image over it. Since overlay has alpha channel and line is placed where it should be (i mean there is opaque space on top and left side of line) you do not need coordinates. Illustration code:
Image imageBackground = Image.FromFile("bitmap1.png");
Image imageOverlay = Image.FromFile("bitmap2.png");
Image img = new Bitmap(imageBackground.Width, imageBackground.Height);
using (Graphics gr = Graphics.FromImage(img))
{
gr.DrawImage(imageBackground, new Point(0, 0));
gr.DrawImage(imageOverlay, new Point(0, 0));
}
img.Save("output.png", ImageFormat.Png);

If you are using WPF, why not use a path for your overlay instead of an image if it is a simple line? This would allow it to scale to any size, and has methods for manipulating its dimensions.
If you are using Winforms, there are some similar graphics drawing capabilities you might leverage. Getting the dimensions of the image should be easy, assuming you're using a PictureBox, the following properties should suffice:
myPictureBox.Top
myPictureBox.Bottom
myPictureBox.Left
myPictureBox.Right
Similarly, for a WPF Image:
myImage.Margin

I already needed to create a blank space around an image and I used the ImageFactory library to do that.
Here is the code. I guess you are capable to figure out how to adjust to your needs.
public static Image ResizedImage(Image image, int desiredWidth, int desiredHeight)
{
Image res = (Bitmap)image.Clone();
Image resizedImage;
ImageLayer imageLayer = new ImageLayer();
try
{
if (res != null)
{
//white background
res = new Bitmap(desiredWidth, desiredHeight, res.PixelFormat);
//image to handle
using (var imgf = new ImageFactory(true))
{
imgf
.Load(image)
.Resize(new ResizeLayer(new Size(desiredWidth, desiredHeight),
ResizeMode.Max,
AnchorPosition.Center,
false));
resizedImage = (Bitmap)imgf.Image.Clone();
}
//final image
if (resizedImage != null)
{
imageLayer.Image = resizedImage;
imageLayer.Size = new Size(resizedImage.Width, resizedImage.Height);
imageLayer.Opacity = 100;
using (var imgf = new ImageFactory(true))
{
imgf
.Load(res)
.BackgroundColor(Color.White)
.Overlay(imageLayer);
res = (Bitmap)imgf.Image.Clone();
}
}
}
}
catch (Exception ex)
{
ex.Message;
}
return res;
}

Related

how to crop image with polygon in c#

I'm making a labeling tool.
Goal :By drawing a polygon on the picture, you have to export the image ​​inside the polygon to the outside.
example
extract
This is what I drew in the my program.
But I don't know how to extract this region. I want to know how to extract this area.
I have saved the vertices of the picture above in an object. But I don't know how to extract data from the image through these vertices
========================================
So I found this.
https://www.codeproject.com/Articles/703519/Cropping-Particular-Region-In-Image-Using-Csharp
but it is not work
Can't convert Bitmap to IplImage
It doesn't work for the same reason.
In the post, I am going to use opencvsharp 4.x, but the program I am fixing now is .netframework 3.5, so it does not support opencvsharp 4.x.
What should I do?
============================
I made a function referring to the answer, but it doesn't work...
I want to know why.
void CropImage(Bitmap bitmap, Point[] points)
{
Rectangle rect = PaddingImage(points, bitmap);
TextureBrush textureBrush = new TextureBrush(bitmap);
Bitmap bmp1 = new Bitmap(rect.Width, rect.Height);
using (Graphics g = Graphics.FromImage(bmp1))
{
g.FillPolygon(textureBrush, points);
}
string ima_path = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
bmp1.Save(ima_path + "\\Image.png", ImageFormat.Png);
}
extract Image
original
If you use a small polygon, there is no output at all.
You will notice that the two images are slightly different.
It seems to me that the part where the center point is cut and extracted is different. I don't know if what I was thinking is correct.
You would create a new bitmap, at least as large as the bounding box of your polygon. Create a graphics object from this new bitmap. You can then draw the polygon to this bitmap, using the original image as a texture brush. Note that you might need to apply transform matrix to translate from the full image coordinates to the cropped image coordinates.
Note that it looks like you have radiological images. These are typically 16 bit images, so they will need to be converted to 8bit mono, or 24bit RGB before they can be used. This should already be done in the drawing code if you have access to the source. Or you can do it yourself.
this works for me
private Bitmap CropImage(Bitmap bitmap, List<Point> points)
{
int pminx = 9999, pminy = 9999, pmaxx = 0, pmaxy = 0; System.Drawing.Point[] pcol = new System.Drawing.Point[points.Count]; int i = 0;
foreach (Point pc in points)
{
if (pc.X > pmaxx) pmaxx = (int)pc.X;
if (pc.Y > pmaxy) pmaxy = (int)pc.Y;
if (pc.X < pminx) pminx = (int)pc.X;
if (pc.Y < pminy) pminy = (int)pc.Y;
pcol[i] = new System.Drawing.Point((int)pc.X, (int)pc.Y);
i++;
}
TextureBrush textureBrush = new TextureBrush(bitmap);
Bitmap bmpWrk = new Bitmap(bitmap.Width, bitmap.Height);
using (Graphics g = Graphics.FromImage(bmpWrk))
{
g.FillPolygon(textureBrush, pcol);
}
System.Drawing.Rectangle CropRect = new System.Drawing.Rectangle(pminx, pminy, pmaxx - pminx, pmaxy - pminy);
return bmpWrk.Clone(CropRect, bmpWrk.PixelFormat);
}

Xamarin.iOS Image on Image Watermark

How can I add a png image as a watermark to a larger image using Xamarin.iOS c# and save the output to the device?
I figured out the Xamarin.Android version from another question posted here.
Thanks in Advance!!
Using an image context, you can draw the original, then the watermark at the necessary location and obtain a new image from the context.
ImageContext example:
var originalImage = UIImage.FromBundle("buymore.jpg");
var watermarkImage = UIImage.FromFile("vs.png");
UIGraphics.BeginImageContextWithOptions(originalImage.Size, true, 1.0f);
originalImage.Draw(CGPoint.Empty);
watermarkImage.Draw(new CGRect(new CGPoint(200, 200), watermarkImage.Size));
var processedImage = UIGraphics.GetImageFromCurrentImageContext();
If your original and watermark images are the same size, you can use a CIFilter (CISourceOverCompositing) to "overlay" one image on top of another (assuming your watermark has a white or alpha background. This is my preferred method due to the speed.
CISourceOverCompositing example:
UIImage processedimage;
using (var filter = new CISourceOverCompositing())
{
filter.Image = new CIImage(UIImage.FromBundle("vs.png"));
filter.BackgroundImage = new CIImage(UIImage.FromBundle("buymore.jpg"));
processedimage = UIImage.FromImage(filter.OutputImage);
}

Cannot create Drop Shadow from Image created by Screen shot (capture)

My code can make DropShadow for TextBlock but cannot create it for image if I create image from screen shot. Using normal image (Image source has been set already) problem do not occur.
I believe that problem must be in image format (somehow) I get from screen shot. Any way to convert SoftwareBitmap to other format or what to do?
(To test with TextBlock just replace Image with TextBlock in the first snippet)
Code to copy any element on the screen to image
public static async Task<Image> GetScreenShotFromElement(FrameworkElement TargetFrameworkElement)
{
Image RenderedImage = new Image();
RenderTargetBitmap renderTargetBitmap = new RenderTargetBitmap();
await renderTargetBitmap.RenderAsync(TargetFrameworkElement);
RenderedImage.Source = renderTargetBitmap;
return RenderedImage;
}
Code to make drop shadow
public static void CreateDropShadowForImage(Image SOURCE,Grid SHADOWHERE)
{
Visual SOURCE_Visual = ElementCompositionPreview.GetElementVisual(SOURCE);
Compositor SOURCE_compositor = SOURCE_Visual.Compositor;
DropShadow DROP_SHADOW = SOURCE_compositor.CreateDropShadow();
DROP_SHADOW.Mask = SOURCE.GetAlphaMask();
DROP_SHADOW.Offset = new Vector3(10, 10, 0);
SpriteVisual SPRITE_VISUAL = SOURCE_compositor.CreateSpriteVisual();
SPRITE_VISUAL.Size = SOURCE.RenderSize.ToVector2();
SPRITE_VISUAL.Shadow = DROP_SHADOW;
ElementCompositionPreview.SetElementChildVisual(SHADOWHERE, SPRITE_VISUAL);
// Make sure size of shadow host and shadow visual always stay in sync
var bindSizeAnimation = SOURCE_compositor.CreateExpressionAnimation("hostVisual.Size");
bindSizeAnimation.SetReferenceParameter("hostVisual", SOURCE_Visual);
SPRITE_VISUAL.StartAnimation("Size", bindSizeAnimation);
}

Png image processing in .NET

I have the following task. Take a base image and overlay on it another one. The base image is 8b png as well as overlay.
Here are the base (left) and overlay (right) images.
Here is a result and how it must look.
The picture in the left is a screenshot when one picture is on top of another (html and positioning) and the second is the result of programmatic merging.
As you can see in the screenshot the borders of the text is darker. Also here are the sizes of the images
Base image 14.9 KB
Overlay image 6.87 KB
Result image 34.8 KB
The size of the resulting image is also huge
Here is my code that I use to merge those pictures
/*...*/
public Stream Concatinate(Stream baseStream, params Stream[] overlayStreams) {
var #base = Image.FromStream(baseStream);
var canvas = new Bitmap(#base.Width, #base.Height);
using (var g = canvas.ToGraphics()) {
g.DrawImage(#base, 0, 0);
foreach (var item in overlayStreams) {
using (var overlayImage = Image.FromStream(item)) {
try {
Overlay(#base as Bitmap, overlayImage as Bitmap, g);
} catch {
}
}
}
}
var ms = new MemoryStream();
canvas.Save(ms, ImageFormat.Png);
canvas.Dispose();
#base.Dispose();
return ms;
}
/*...*/
/*Tograpics extension*/
public static Graphics ToGraphics(this Image image,
CompositingQuality compositingQuality = CompositingQuality.HighQuality,
SmoothingMode smoothingMode = SmoothingMode.HighQuality,
InterpolationMode interpolationMode = InterpolationMode.HighQualityBicubic) {
var g = Graphics.FromImage(image);
g.CompositingQuality = compositingQuality;
g.SmoothingMode = smoothingMode;
g.InterpolationMode = interpolationMode;
return g;
}
private void Overlay(Bitmap source, Bitmap overlay, Graphics g) {
if (source.Width != overlay.Width || source.Height != overlay.Height)
throw new Exception("Source and overlay dimensions do not match");
var area = new Rectangle(0, 0, source.Width, source.Height);
g.DrawImage(overlay, area, area, GraphicsUnit.Pixel);
}
My questions are
What should I do in order to merge images to achieve the result as in the screenshot?
How can I lower the size of the result image?
Is the System.Drawing a suitable tool for this or is there any better tool for working with png for .NET?
The answers to your questions are:
1) Just call method ToGraphics with a argument CompositingQuality.Default instead of using default argument values like in the example:
using (var g = canvas.ToGraphics(compositingQuality: CompositingQuality.Default))
The problem is with CompositingQuality.HighQuality is that it makes a composition of both images into one, but you want to make an overlay, not to make a composition of two images.
2) The size will be similar to the one you specified and that can not be changed, it is due to a image format.
3) If you are programming in c# for desktop, than System.Drawing is the best choice as far as I know.

Desktop capture in png format

I will like to get a screen capture and save it in the format of png of the entire screen. How can I do that?
Could I use the Snipping Tool library to accomplish this? There are some tutorials on the internet that show you how to do this with windows forms and the image is in the format of bitmap.
Here's a little method to capture the contents of any screen.
private static void CaptureScreen(Screen window, string file)
{
try
{
Rectangle s_rect = window.Bounds;
using (Bitmap bmp = new Bitmap(s_rect.Width, s_rect.Height))
{
using (Graphics gScreen = Graphics.FromImage(bmp))
gScreen.CopyFromScreen(s_rect.Location, Point.Empty, s_rect.Size);
bmp.Save(file, System.Drawing.Imaging.ImageFormat.Png);
}
}
catch (Exception) { /*TODO: Any exception handling.*/ }
}
Example of usage:
CaptureScreen(Screen.PrimaryScreen, #"B:\exampleScreenshot.png");
EDIT: Coming back to this later I realized it's probably more useful to return an Image object from the function so you can choose how to use the captured bitmap.
I've also made the function a bit more robust now so that it can capture multiple screens (i.e. in a multi-monitor setup). It should accommodate screens of varying heights, but I can't test this myself.
public static Image CaptureScreens(params Screen[] screens) {
if (screens == null || screens.Length == 0)
throw new ArgumentNullException("screens");
// Order them in logical left-to-right fashion.
var orderedScreens = screens.OrderBy(s => s.Bounds.Left).ToList();
// Calculate the total width needed to fit all the screen into a single image
var totalWidth = orderedScreens.Sum(s => s.Bounds.Width);
// In order to handle screens of different sizes, make sure to make the Bitmap large enough to fit the tallest screen
var maxHeight = orderedScreens.Max(s => s.Bounds.Top + s.Bounds.Height);
var bmp = new Bitmap(totalWidth, maxHeight);
int offset = 0;
// Copy each screen to the bitmap
using (var g = Graphics.FromImage(bmp)) {
foreach (var screen in orderedScreens) {
g.CopyFromScreen(screen.Bounds.Left, screen.Bounds.Top, offset, screen.Bounds.Top, screen.Bounds.Size);
offset += screen.Bounds.Width;
}
}
return bmp;
}
New example:
// Capture all monitors and save them to file
CaptureScreens(Screen.AllScreens).Save(#"C:\Users\FooBar\screens.png");

Categories