Alright , i am trying to merge two images(superimpose one image on top of another) using writeablebitmapex library's blit method. And after applying the blit all i am getting is a transparent image with no content.
I would like to superimpose the curtain image on top of the window image.
Source Code :
WriteableBitmap photoWriteableBitMap = await new WriteableBitmap(1,1).FromContent(new Uri("ms-appx:///Curtain1.jpg"));
WriteableBitmap frameWriteableBitMap = await new WriteableBitmap(1, 1).FromContent(new Uri("ms-appx:///Window1.jpg"));
var merge = new WriteableBitmap(750, 750);
merge.Blit(new Rect(0, 0, 100, 100), photoWriteableBitMap, new Rect(0, 0, photoWriteableBitMap.PixelWidth, photoWriteableBitMap.PixelHeight));
merge.Blit(new Rect(0, 0, 200, 200), frameWriteableBitMap, new Rect(0, 0, frameWriteableBitMap.PixelWidth, frameWriteableBitMap.PixelHeight));
// Assign the merged writeable bitmap to the image source.
imgMain.Source = merge;
Expected Image :
Actual Image :
Please let me know what i am doing wrong.
I have found an answer to my solution in case anyone stumbles upon here.
First thing , I was unnecessarily trying to include an extra bitmap(merge) for the desired output.
All I had to do was apply the blit on the window image and set the source and the destination rectangles appropriately.
Below is the final code which works for me ,
WriteableBitmap photoWriteableBitMap = await new WriteableBitmap(1, 1).FromContent(new Uri("ms-appx:///Curtain1.jpg"));
WriteableBitmap frameWriteableBitMap = await new WriteableBitmap(1, 1).FromContent(new Uri("ms-appx:///Window1.jpg"));
frameWriteableBitMap.Blit(new Rect(300, 100, 250, 200), photoWriteableBitMap, new Rect(0, 0, photoWriteableBitMap.PixelWidth , photoWriteableBitMap.PixelHeight));
This is how my final image looks :
Related
I'm trying to create a real grayscale image, but when my designer checks the file he is saying that the image remains RGB.
You can see the photoshop print here:
I've tried 2 methods so far:
1) Using the MakeGrayScale3 method:
public static Image MakeGrayscale3(Image original)
{
//create a blank bitmap the same size as original
Bitmap newBitmap = new Bitmap(original.Width, original.Height);
newBitmap.SetResolution(original.HorizontalResolution, original.VerticalResolution);
//get a graphics object from the new image
Graphics g = Graphics.FromImage(newBitmap);
//create the grayscale ColorMatrix
ColorMatrix colorMatrix = new ColorMatrix(
new float[][]
{
new float[] {.3f, .3f, .3f, 0, 0},
new float[] {.59f, .59f, .59f, 0, 0},
new float[] {.11f, .11f, .11f, 0, 0},
new float[] {0, 0, 0, 1, 0},
new float[] {0, 0, 0, 0, 1}
});
//create some image attributes
ImageAttributes attributes = new ImageAttributes();
//set the color matrix attribute
attributes.SetColorMatrix(colorMatrix);
//draw the original image on the new image
//using the grayscale color matrix
g.DrawImage(original, new Rectangle(0, 0, original.Width, original.Height),
0, 0, original.Width, original.Height, GraphicsUnit.Pixel, attributes);
//dispose the Graphics object
g.Dispose();
return newBitmap;
}
2) Using the ImageMagick.Net library with this code:
using (MagickImage image = new MagickImage(file))
{
image.ColorSpace = ColorSpace.GRAY;
image.Write(originalFile);
}
If anyone had this problem before or have a clue of what to do to change that..
Thanks!
Original Image:
Result Image (ImageMagick):
Result Image (MakeGrayscale3):
The grayscale format used by jpeg isn't available in the classic System.Drawing classes. It is, however, available in System.Windows.Media. You need to add PresentationCore and WindowsBase as references for using them (this will not be portable on Linux).
public static void SaveAsGrayscaleJpeg(String loadPath, String savePath)
{
using (FileStream fs = new FileStream(savePath, FileMode.Create))
{
BitmapSource img = new BitmapImage(new Uri(new FileInfo(loadPath).FullName));
FormatConvertedBitmap convertImg = new FormatConvertedBitmap(img, PixelFormats.Gray8, null, 0);
JpegBitmapEncoder encoder = new JpegBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(convertImg));
encoder.Save(fs);
}
}
As a bonus, this does the grayscale conversion automatically.
If you're actually starting from Image/Bitmap class, there are some solutions around for converting between them.
Also you should pay attention to:
https://learn.microsoft.com/en-us/dotnet/core/compatibility/core-libraries/6.0/system-drawing-common-windows-only
Thanks for all answers but after read the topic that Hans mentioned there they talk about the FreeImageNET library that I'm using to solve my problem.
Using this code I've managed to save the image as a grayscale image:
FreeImageAPI.FreeImage.ConvertTo8Bits(newimg)
The issue is this line:
Bitmap newBitmap = new Bitmap(original.Width, original.Height);
If you look at the MSDN page it says:
This constructor creates a Bitmap with a PixelFormat enumeration value of Format32bppArgb.
So, you're just creating another color image. What you need to do is to use a different constructor to force a different format:
Bitmap newBitmap = new Bitmap( original.Width, original.Height,
PixelFormat.Format8bppIndexed );
But then that gives you another issue - you can't paint to bitmaps with that pixel format with a Graphics object. There is a PixelFormat.Format16bppGrayScale which appears to work even less.
So, my suggestion would be to to this manually. Use LockBits to get access to the raw bitmap and do the conversion yourself. It is a little bit more work (i.e. you can't use the ColorMatrix stuff, and you have to take care to check if the source bitmap is 24 bit or 32 bit), but it will work just fine.
One issue to be aware of is that it's not a "real" grayscale format, it's 8 bit indexed. So you will also have to create a palette. Simply map each of the 256 values to the same, i.e. 0 -> 0, 100 -> 100, 255 -> 255.
I am currently converting a Silverlight application into WPF. In my silverlight application I have the code
WriteableBitmap sceneBitmap = new WriteableBitmap(scene, new TranslateTransform() { Y = 10 });
WriteableBitmap newone = TimelineMainHelper.CropImage(sceneBitmap, 0, 0, sceneBitmap.PixelWidth, sceneBitmap.PixelHeight - 25);
newone.Invalidate();
img.Source = newone;
Where scene is a control.
When putting this into WPF there are no overloads for the writeablebitmap class which take UIElement and Transform as the parameters. Firstly I was wondering why this is? and secondly I was wondering if there was a way getting a control to a writeablebitmap
Instead you will want to use RenderTargetBitmap and CroppedBitmap I believe:
RenderTargetBitmap rtb = new RenderTargetBitmap((int)scene.ActualWidth, (int)scene.ActualHeight, 96, 96, System.Windows.Media.PixelFormats.Pbgra32);
rtb.Render(this.sceneBitmap);
CroppedBitmap crop = new CroppedBitmap(sceneBitmap, new Int32Rect(0, 0, (int)sceneBitmap.ActualWidth, (int)sceneBitmap.ActualHeight));
Then you can do something like:
System.Windows.Controls.Image img = new Image();
img.Source = crop;
And go from there.
Disclaimer:
You may need to use different overloads and what not to do exactly what you wish. I just took a shot guessing what parameters to pass given your snippet.
I create a WriteableBitmap object, draw a line and try to set it as the source to an Image control. For some reason, the program stops responding and then closes 5 seconds later when I try to set the Source. Anyone have any idea what's wrong? (I am also using WriteableBitmapEx)
WriteableBitmap bit = new WriteableBitmap(400, 400, 96, 96, PixelFormats.Bgr32, null);
WriteableBitmapExtensions.DrawLine(bit, 10, 10, 300, 300, Core.PrimaryColor.ColorValue);
ImageCanvas.Source = bit; // Sets the image to our bitmap, but program crashes for some reason!
When I try your code, it throws an ArgumentException saying
The input WriteableBitmap needs to have the Pbgra32 pixel format. Use
the BitmapFactory.ConvertToPbgra32Format method to automatically
convert any input BitmapSource to the right format accepted by this
class.\r\nParametername: writeableBitmap
Hence this works:
var bitmap = new WriteableBitmap(400, 400, 96, 96, PixelFormats.Pbgra32, null);
WriteableBitmapExtensions.DrawLine(bitmap, 10, 10, 300, 300, Colors.Black);
image.Source = bitmap;
UPDATE: As noted by Anders, you should perhaps use the portable bitmap factory method provided by WriteableBitmapEx to create your bitmap:
var bitmap = BitmapFactory.New(400, 400);
WriteableBitmapExtensions.DrawLine(bitmap, 10, 10, 300, 300, Colors.Black);
image.Source = bitmap;
Maybe it's a stupid question, but I have some problems with finding the proper answer:S
How to get frames as Bitmap's or Image's (or something similar) from DrawingGroup? I don't actually know how to bite it. I tried to look for it in the Internet, but had problems with finding something useful.
If you need an image to be used as the Source of an Image control, you could simply put the drawing into a DrawingImage:
var drawing = ...
var drawingImage = new DrawingImage(drawing);
image.Source = drawingImage;
If the question is about creating a BitmapSource (i.e. something that can be encoded by a BitmapEncoder via a BitmapFrame), there is no direct conversion. You have to put the image into an intermediate Image control and render that control into a RenderTargetBitmap, which is a BitmapSource:
var drawing = ...
var drawingImage = new DrawingImage(drawing);
var image = new Image { Source = drawingImage };
var bitmap = new RenderTargetBitmap(100, 100, 96, 96, PixelFormats.Pbgra32);
image.Arrange(new Rect(0, 0, bitmap.Width, bitmap.Height));
bitmap.Render(image);
Image img = new Bitmap(Image.FromFile(file.FullName));
using (Graphics g = Graphics.FromImage(img)){
g.DrawRectangle(Pens.Black, 0, 0, img.Width - 2, img.Height - 2);
}
like this
how to do in sliverlight?
Use WriteableBitmap class.
References:
Rendering XAML to a JPEG using Silverlight 3
Silverlight 3.0: WriteableBitmap
Silverlight 3's New Writeable Bitmap
Example:
With WritableBitmap, you can just draw something on a Control or Canvas and then save it to a bitmap using it's public WriteableBitmap(UIElement element,Transform transform) constructor.
You don't need to render a SL Rectangle into the WriteableBitmap. The WriteableBitmapEx open source library is perfect for this. See the project site for an example of the DrawRectangle method.
http://writeablebitmapex.codeplex.com
There are also live samples, including the Shape sample.
You can also find the code of the samples in the source code repository.
You can use a WriteableBitmap for this. Create a Canvas and draw your elements on the Canvas, load other images etc. Then once you are done rendering on the Canvase you can create the WriteableBitmap from the Canvas and then do what every you need.
In the example below I assigned the bitmap as the Source of an Image element to show that the final result.
Canvas canvas = new Canvas();
UIElement ellipse = new Ellipse()
{ Width = 100, Height = 100, Fill = new SolidColorBrush(Colors.Red) };
Canvas.SetLeft(ellipse, 100);
Canvas.SetTop(ellipse, 100);
canvas.Children.Add(ellipse);
WriteableBitmap bmp = new WriteableBitmap(canvas, null);
myImage.Source = bmp;