WPF: "edit" image and save - c#

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

Related

XAML to Bitmap with high quality

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

Draw a bitmap in WPF

I am trying to draw some string to bitmap at certain position and copy a barcode bitmap to the new bitmap.I have not done with graphics before so i don't know where to start.
Can anyone guide me on this?my output of the bitmap is a receipt like.
Here is a solution. Please make a grid or canvas and put the barcode image and use a label with desired text and put the label on desired location relative to barcode grid. So, trick is you can immediately take screenshot of this grid using following code.Then, you are done.
public void ConvertToBitmapSource(UIElement element)
{
var target = new RenderTargetBitmap(
(int)element.RenderSize.Width, (int)element.RenderSize.Height,
96, 96, PixelFormats.Pbgra32);
target.Render(element);
var encoder = new PngBitmapEncoder();
var outputFrame = BitmapFrame.Create(target);
encoder.Frames.Add(outputFrame);
using (var file = File.OpenWrite("TestImage.png"))
{
encoder.Save(file);
}
}

How to overlap images and store them in new image objects

I have two images,now i want to overlay the images,such that the other image appears on center or left corner of the other image,and then when finally both the images are overlayed i can store it in another new image object,and i want to all this in code behind only not xaml,how to do this?
if (((Grid)sender).Children.Count > 0)
{
gridBackground = (ImageBrush)(((Grid)sender).Background);
gridBackImage = new System.Windows.Controls.Image();
gridBackImage.Source = gridBackground.ImageSource;
}
System.Windows.Controls.Image imgRejectIcon;
if (((Grid)sender).Children.Count > 0)
{
imgRejectIcon = (System.Windows.Controls.Image)(((Grid)sender).Children[0]);
}
Now i want to merge gridBackImage and imgRejection and store it in new image object
You can arrange your two Images in any way that you want and I'll leave that code for you to do (it'd much simpler to do in XAML). In WPF, all UI controls extend the Visual class. This is very useful for making BitmapImages from UI controls, when used with the RenderTargetBitmap.Render method.
First, arrange your two Image controls into a Grid, or other container control, and then you can pass the container control to the RenderTargetBitmap.Render method and create an Image something like this:
RenderTargetBitmap renderTargetBitmap =
new RenderTargetBitmap(width, height, 96, 96, PixelFormats.Pbgra32);
renderTargetBitmap.Render(yourContainerControl);
PngBitmapEncoder pngImage = new PngBitmapEncoder();
pngImage.Frames.Add(BitmapFrame.Create(renderTargetBitmap));
using (Stream fileStream = File.Create(filePath))
{
pngImage.Save(fileStream);
}

Rotating an Image in Windows Phone

I display a photo I took on one of my pages.
I capture the photo in Portrait mode and it works ok.
When I show the picture on my next view, it treats the photo like it was taken in Landscape.
So I need to rotate the picture/image by -90 to correct this.
Here is the relevant code of my .XAML:
<!--ContentPanel - place additional content here-->
<Grid x:Name="ContentPanelx" Grid.Row="1" Margin="0,0,0,0">
</Grid>
And here is the methods where I load the photo and put it into the ContentPanel.:
void loadImage()
{
// The image will be read from isolated storage into the following byte array
byte[] data;
// Read the entire image in one go into a byte array
using (IsolatedStorageFile isf = IsolatedStorageFile.GetUserStoreForApplication())
{
// Open the file - error handling omitted for brevity
// Note: If the image does not exist in isolated storage the following exception will be generated:
// System.IO.IsolatedStorage.IsolatedStorageException was unhandled
// Message=Operation not permitted on IsolatedStorageFileStream
using (IsolatedStorageFileStream isfs = isf.OpenFile("0.jpg", FileMode.Open, FileAccess.Read))
{
// Allocate an array large enough for the entire file
data = new byte[isfs.Length];
// Read the entire file and then close it
isfs.Read(data, 0, data.Length);
isfs.Close();
}
}
// Create memory stream and bitmap
MemoryStream ms = new MemoryStream(data);
BitmapImage bi = new BitmapImage();
// Set bitmap source to memory stream
bi.SetSource(ms);
// Create an image UI element – Note: this could be declared in the XAML instead
Image image = new Image();
// Set size of image to bitmap size for this demonstration
image.Height = bi.PixelHeight;
image.Width = bi.PixelWidth;
// Assign the bitmap image to the image’s source
image.Source = bi;
// Add the image to the grid in order to display the bit map
ContentPanelx.Children.Add(image);
}
}
I am thinking on a simple rotate on the image after I've loaded this. I can do this in iOS, but my C# is skills are worse than bad.
Can anybody advise on this?
If the image is declared in xaml you can rotate it like this:
//XAML
<Image.RenderTransform>
<RotateTransform Angle="90" />
</Image.RenderTransform>
Same thing can be done thru c# also. If you always rotate the image , then doint it in xaml is the better optioin
//C#
((RotateTransform)image.RenderTransform).Angle = angle;
Please try this one:
RotateTransform rt = new RotateTransform();
rt.Angle = 90;
image.RenderTransform = rt;
You can create a RotateTransform object to use for the image's RenderTransform property. This will cause WPF to rotate the Image control when rendered.
If you want to rotate the image about it's center you will also need to set the rotation origin, as shown below:
RotateTransform rt = new RotateTransform();
rt.Angle = 90;
image.RenderTransform = rt;
image.RenderTransformOrigin = new Point(0.5, 0.5);

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