XAML to Bitmap with high quality - c#

I'm trying to store a XAML in a bitmap file and print it to a pdf file.
My view shows the controls/text like this:
The pdf shows the created bitmap like this:
Here's the code on how I convert my XAML to a bitmap:
MyWindow view = new MyWindow();
view.Title = "SOME TEXT";
//add the table
RenderTargetBitmap bmp = new RenderTargetBitmap((int)view.ActualWidth, (int)view.ActualHeight, 96, 96, PixelFormats.Pbgra32);
bmp.Render(view);
PngBitmapEncoder pngImage = new PngBitmapEncoder();
pngImage.Frames.Add(BitmapFrame.Create(bmp));
//System.Windows.Clipboard.SetImage(pngImage.Frames[0]); //Clipboard still shows the pngImage in high quality!
MemoryStream stream = new MemoryStream();
PngBitmapEncoder encoder = new PngBitmapEncoder();
encoder.Frames.Add(pngImage.Frames[0]);
encoder.Save(stream);
Bitmap myCreatedBitmap = new Bitmap(stream);
I'm using System.Drawing.Printing to print the pdf file. I'm assigning the bitmap in the EventHandler PrintPageEventHandler like this:
e.Graphics.DrawImage(this.bitmap, new Rectangle(e.MarginBounds.X, e.MarginBounds.Y, e.MarginBounds.Width, e.MarginBounds.Height), new Rectangle(posX, posY, e.MarginBounds.Width, e.MarginBounds.Height), GraphicsUnit.Pixel);
What's the reason for the blurry image or how can I convert my XAML to a bitmap with High Resolution and store it in a pdf?

To convert XAML to PDF with high quality, try converting XAML to XPS and XPS to PDF, using Syncfusion .NET PDF library.
Refer the below KB for converting XAML to PDF
https://www.syncfusion.com/kb/8083/how-to-convert-xaml-to-pdf-in-wpf-platform

Related

WPF: Image control of a CroppedBitmap as BitmapImage is still uncropped Image (Conversion Problem?)

I am trying to Crop a BitmapImage in my WPF application StageWindow.Stage using the CroppedBitmap class.
When saving the new cropped image to file JpegBitmapEncoder I can see the correctly cropped image. CroppedBitmap Crop
However I actually want to save the cropped image into a List\<BitmapImage\> for later use in another WPF image control. That list contains BitmapImages already so changing it to CroppedBitmaps would not suffice.
to be able to store the new croppedBitmap I use something like this:
BitmapImage xx = CroppedBitmap1 as BitmapImage;
when setting an WPF image control to the new BitmapImage (ExpectedCroppedImage) it still displays the CroppedBitmaps original source image without the crop.
I suspect the code above to delete the crop attribute from the new BitmapImage because the BitmapImage itself has no attributes for the cropped Area. But how can I save only the cropped part into a new BitmapImage?
I have been searching around but it seems CroppedBitmap should do the trick I just dont know how to convert it back in the correct manner.
Here is the Code for clarification:
//Stage is the WPF image element that im reading the source image from.
ImageSource StageWindowImageSource = StageWindow.Stage.Source;
CroppedBitmap Crop = new CroppedBitmap((BitmapSource)StageWindowImageSource, new Int32Rect(0,0,50,50));
ExpectedCroppedImage = Crop.Source as BitmapImage;
JpegBitmapEncoder jpg = new JpegBitmapEncoder();
jpg.Frames.Add(BitmapFrame.Create(Crop));
FileStream fp = new FileStream("F:/Crop.jpg", FileMode.Create, FileAccess.Write);
jpg.Save(fp);
fp.Close();
The line
ExpectedCroppedImage = Crop.Source as BitmapImage;
does not return the cropped bitmap, but the original one from which the crop was taken, i.e. the Source bitmap.
Besides that, you don't need any conversion from CroppedBitmap to BitmapImage.
Instead, use a base class of BitmapImage and CroppedBitmap as element type of the List, i.e. use a List<BitmapSource> or List<ImageSource> for your collection.
Now you can assign instances of any class derived from the element type.
List<BitmapSource> images = ...
CroppedBitmap croppedImage = new CroppedBitmap(...);
images.Add(croppedImage);
BitmapImage someOtherImage = new BitmapImage(...);
images.Add(someOtherImage);
private void MyMethod()
{
ImageSource StageWindowImageSource = img.Source;
CroppedBitmap Crop = new CroppedBitmap((BitmapSource) StageWindowImageSource, new Int32Rect(20, 20, 150, 110));
img2.Source = GetImage(Crop, new JpegBitmapEncoder());
}
private BitmapImage GetImage(BitmapSource source, BitmapEncoder encoder)
{
var image = new BitmapImage();
using (var sourceMs = new MemoryStream())
{
encoder.Frames.Add(BitmapFrame.Create(source));
encoder.Save(sourceMs);
sourceMs.Position = 0;
using (var destMs = new MemoryStream(sourceMs.ToArray()))
{
image.BeginInit();
image.StreamSource = destMs;
image.CacheOption = BitmapCacheOption.OnLoad;
image.EndInit();
image.Freeze();
}
}
return image;
}

Merge two image in windows universal 8.1

I have 1.png (150x150 size) and 2.png (150x150 size). I use this code for make a stackpanel (310x150 size):
StackPanel mygrid = new StackPanel();
mygrid.Orientation = Orientation.Horizontal;
Image myimage1 = new Image();
myimage1.Width = 150; myimage1.Height = 150;
myimage1.Source = new BitmapImage(new Uri(#"ms-appx:///assets/1.png", UriKind.RelativeOrAbsolute));
Image myimage2 = new Image();
myimage2.Width = 150; myimage2.Height = 150;
myimage2.Source = new BitmapImage(new Uri(#"ms-appx:///assets/2.png", UriKind.RelativeOrAbsolute));
mygrid.Children.Add(myimage1);
mygrid.Children.Add(myimage2);
Then I convert this stackpanel to Image:
RenderTargetBitmap renderTargetBitmap = new RenderTargetBitmap();
await renderTargetBitmap.RenderAsync(mygrid, 310, 150);
I want to save this image in "ms-appx:///assets/3.png" (like this name) and use that. In this way, I merge two image to one image But I can't save them to 3.png. How can I do that?
If this is not a good way to merge two picture in one picture, Is it possible to help me?
Update: I'm sorry but question has problems and it is deleted. I can't delete it because there is answer on it. Thanks for helping me.
I think you are using generally the wrong approach to do this. I would load the 2 images into WriteableBitmaps and then blend them with the WriteableBitmapEx library
Having said that, here is how you can save the WriteableBitmap as png, taken from here:
// Save the writeableBitmap object to JPG Image file
IStorageFile saveFile = todo;// insert your code for opening the file here
IRandomAccessStream stream = await savefile.OpenAsync(FileAccessMode.ReadWrite);
BitmapEncoder encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.PngEncoderId, stream);
// Get pixels of the WriteableBitmap object
Stream pixelStream = renderTargetBitmap.PixelBuffer.AsStream();
byte[] pixels = new byte[pixelStream.Length];
await pixelStream.ReadAsync(pixels, 0, pixels.Length);
// Save the image file with jpg extension
encoder.SetPixelData(BitmapPixelFormat.Bgra8, BitmapAlphaMode.Ignore, (uint)writeableBitmap.PixelWidth, (uint)writeableBitmap.PixelHeight, 96.0, 96.0, pixels);
await encoder.FlushAsync();
You try to save the image as ms-appx:///assets/3.png that won't work as you can't save the image in the application package.
You need to save it to somewhere where your app has write access to.

Cannot save a Transparent PNG from my canvas in C#

I made a WPF canvas program which lets users add some PNG templates and make their own new design.
I could complete the working
However when I try to save , I get the white background
Is there any way to get a transparent output ?
This is my code on saving image
public void SaveTo(string f)
{
Visual v = Dc;
/// get bound of the visual
Rect b = VisualTreeHelper.GetDescendantBounds(v);
/// new a RenderTargetBitmap with actual size of c
RenderTargetBitmap r = new RenderTargetBitmap(
(int)b.Width, (int)b.Height,
96, 96, PixelFormats.Pbgra32);
/// render visual
r.Render(v);
/// new a JpegBitmapEncoder and add r into it
JpegBitmapEncoder e = new JpegBitmapEncoder();
e.Frames.Add(BitmapFrame.Create(r));
/// new a FileStream to write the image file
FileStream s = new FileStream(f,
FileMode.OpenOrCreate, FileAccess.Write);
e.Save(s);
s.Close();
}
You are encoding to a Jpeg.
Jpegs have no transparency information (aka alpha channel).
You should use a PngBitmapEncoder.

WPF: "edit" image and save

I want to do something like that: open an image in the <image> tag and add some other tags on it, for example green rectangle. After that I want to save it like image with rectangle on some part of it. In general user should drag&drop rectangle and could resize it. But the question is: How can I save it? I suppose that I should save parent tag for all of them, for example <grid> or <canvas> but is it possible?
Transform transform = myCanvas.LayoutTransform;
myCanvas.LayoutTransform = null; Size size = new Size(myCanvas.Width,myCanvas.Height); myCanvas.Measure(size);
myCanvas.Arrange(new Rect(size));
RenderTargetBitmap renderBitmap = new RenderTargetBitmap((int)size.Width, (int)size.Height, 96d, 96d,PixelFormats.Pbgra32);
renderBitmap.Render(myCanvas);
using (FileStream outStream = new FileStream(path.LocalPath, FileMode.Create))
{
PngBitmapEncoder encoder = new PngBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(renderBitmap));
encoder.Save(outStream);
}
myCanvas.LayoutTransform = transform;
For a detailed explanation (and the source of the above code), see this blog post:
http://denisvuyka.wordpress.com/2007/12/03/wpf-diagramming-saving-you-canvas-to-image-xps-document-or-raw-xaml/
You can save as PNG, JPG, etc depending on the encoder that you use

WPF Printing to printer with Magstrip encoding

I am writing a new WPF application that creates some visual elements and then trying to print them on a Poloroid printer. I am successfully printing using the System.Printing classes in WPF as follows:
Dim Pd As PrintDialog = New PrintDialog()
Dim Ps = New LocalPrintServer()
Dim PrintQueue = New PrintQueue(Ps, "Poloroid Printer")
Pd.PrintQueue = PrintQueue
Pd.PrintVisual(Me.Grid1, "Print Job 1") 'this prints out perfectly
The problem is that the poloroid printer has an SDK that you can use to write to the Magstrip on the back of the card. I have a working example using the PrintPageEventArgs in System.Drawing.Printing but I cannot find any close matches for the WPF world. Here is that code:
Private Sub PrintPage(ByVal sender as Object, ByVal e As System.Drawing.Printing.PrintPageEventArgs)
'...
' Obtain the device context for this printer
deviceContext = e.Graphics.GetHdc().ToInt32()
'... device context is used in SDK to write to magstrip
e.Graphics.ReleaseHdc(New IntPtr(deviceContext))
End Sub
So, my question is:
How can I print my existing markup (XAML) using System.Drawing.Printing
OR
Are there events in the System.Printing to talk to the SDK and getting the Int32 deviceContext?
and I tried to RenderTargetBitmap class to render the visual in WPF to bitmap and convert the bitmap to System.Drawing.Bitmap
RenderTargetBitmap bitmapSource;
...
bitmapSource.Render(visual);
...
using(MemoryStream outStream = new MemoryStream())
{
BitmapEncoder enc = new BmpBitmapEncoder();
enc.Frames.Add(BitmapFrame.Create(bitmapSource));
enc.Save(outStream);
System.Drawing.Bitmap bitmap = new System.Drawing.Bitmap(outStream);
...
}
But printing was not clear and perfect.
Try this
Rect bounds = VisualTreeHelper.GetDescendantBounds(FrontCanvas);
double dpiX =e.Graphics.DpiX , dpiY=e.Graphics.DpiY ;
RenderTargetBitmap rtb = new RenderTargetBitmap((int)(bounds.Width * dpiX / 96.0),
(int)(bounds.Height * dpiY / 96.0),
dpiX,
dpiY,
PixelFormats.Pbgra32);
DrawingVisual dv = new DrawingVisual();
using (DrawingContext ctx = dv.RenderOpen())
{
VisualBrush vb = new VisualBrush(FrontCanvas);
ctx.DrawRectangle(vb, null, new Rect(new Point(), bounds.Size));
}
rtb.Render(dv);
//System.Drawing.Bitmap bitmap = new System.Drawing.Bitmap(rtb);
//e.Graphics.DrawImage(rtb, 0, 0);
using (MemoryStream outStream = new MemoryStream())
{
// Use png encoder for data
BitmapEncoder encoder = new PngBitmapEncoder();
// push the rendered bitmap to it
encoder.Frames.Add(BitmapFrame.Create(rtb));
encoder.Save(outStream);
System.Drawing.Bitmap bitmap = new System.Drawing.Bitmap(outStream);
e.Graphics.DrawImage(bitmap, 0, 0);
}
I recently answered a similar question that can be found here: https://stackoverflow.com/a/43373398/3393832. That question and answer relate more to magnetic encoding (on ID cards) than image printing, but I will try to give some insight about that here, as well.
For the card images, I actually set up two Grids within my XAML: an outer grid that houses everything (buttons, labels, combo-boxes, the inner grid) and an inner grid that is essentially the image I want to apply, in full, on the card itself. In code, I take a "snapshot" of the inner grid after all elements have been added/updated and simply send that image into the Print Job.
To continue with my previous post (the link above), I add the image print AFTER the magnetic encoding step for the first side of the card (PageCount == 0).
Below is some code that I use to get the Bitmap "snapshot" of the Grid/Full Image without any loss of clarity/resolution or any pixelation:
RenderTargetBitmap rtb = new RenderTargetBitmap(gridWidth, gridHeight, 210, 210, PixelFormats.Pbgra32);
rtb.Render(YourGrid);
// If you need to Crop Anything Out
CroppedBitmap crop = new CroppedBitmap();
crop = new CroppedBitmap(rtb, new Int32Rect(0, 0, gridWidth, gridHeight));
Bitmap bmpToPrint = BitmapSourceToBitmap(crop);
// Helper Method
public Bitmap BitmapSourceToBitmap(BitmapSource bs)
{
Bitmap bitmap;
using (MemoryStream ms = new MemoryStream())
{
BitmapEncoder enc = new BmpBitmapEncoder();
enc.Frames.Add(BitmapFrame.Create(bs));
enc.Save(ms);
bitmap = new Bitmap(ms);
}
return bitmap;
}
For the Magnetic Encoding, I use e.Graphics.DrawString and for the Image (you guessed it) e.Graphics.DrawImage. Simply call DrawString prior to DrawImage and your Printer Driver should pick up the encode prior to the image within the PrintPage method (again, please refer to the link above for more details into the Print method I am using. This method is also not tied to a printer make or model and is not reliant on any SDK).
Though generic and in need of your particular implementation details, I hope this post helps guide you to a solution that fits your particular needs. Please don't hesitate to ask if you have any follow-up questions or need more detail into the particular elements of the print job itself.

Categories