iTextSharp image stretching not proportional - wpf

I am using Telerik RadRadialGauge and I need to export it to pdf like a picture.
On my GUI the control looks normal
When I try to export it to pdf it is resized not proportionally.
All other elements look good.
using (var ms = new MemoryStream())
{
var document = new Document(PageSize.LETTER, 0, 0, 0, 0);
PdfWriter.GetInstance(document, new FileStream(pdfFile, FileMode.Create));
PdfWriter.GetInstance(document, ms).SetFullCompression();
document.Open();
FileStream fs = new FileStream(imageFile1, FileMode.Open);
var image = iTextSharp.text.Image.GetInstance(fs);
image.ScalePercent(80);
// image.ScaleToFit(document.PageSize.Width , document.PageSize.Height);
// image.ScaleAbsolute(document.PageSize.Width , document.PageSize.Height));
document.Add(image);
}
Here the code to save all the data from GUI as png file.
private void SaveAsPng(RenderTargetBitmap src, string targetFile)
{
try
{
PngBitmapEncoder encoder = new PngBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(src));
using (var stm = File.Create(targetFile))
{
encoder.Save(stm);
}
}
catch (Exception)
{
... }
}

Related

WPF Canvas to word documents using OpenXML

I'm currently working on a project that requires importing the image drawn on a WPF Canvas (Mostly Geometries like lines and ellipses inside Path) into a Word Document. I'm using Openxml to do the job. Here's what I did
I convert read the content of the Canvas into a memory stream
I used the guide provided my Microsoft on how to insert image into Word files How to: Insert a picture into a word processing document (Open XML SDK)
Here's what I've got so far,
Canvas is converted into memory stream by the following piece of code
public static Stream CreateJPGStream(this Canvas canvas)
{
RenderTargetBitmap renderBitmap = new RenderTargetBitmap((int)canvas.ActualWidth, (int)canvas.ActualHeight, 96d, 96d, PixelFormats.Pbgra32);
canvas.Measure(new Size((int)canvas.ActualWidth, (int)canvas.ActualHeight));
canvas.Arrange(new Rect(new Size((int)canvas.ActualWidth, (int)canvas.ActualHeight)));
renderBitmap.Render(canvas);
var stream = new MemoryStream();
var encoder = new JpgBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(renderBitmap));
encoder.Save(stream);
return stream;
}
I believe this was not the cause of the problem since I have been using this code for a while now and I haven't had any issues so far
Then I just modified code from Microsoft Guide
public static void InsertPicture(this WordprocessingDocument word, Stream stream)
{
MainDocumentPart mainPart = word.MainDocumentPart;
if (mainPart == null)
{
mainPart = word.AddMainDocumentPart();
mainPart.Document = new Document() { Body = new Body() };
}
ImagePart imagePart = mainPart.AddImagePart(ImagePartType.Jpeg);
imagePart.FeedData(stream);
AddImageToBody(word, mainPart.GetIdOfPart(imagePart));
}
private static void AddImageToBody(WordprocessingDocument wordDoc, string relationshipId)
{
var element =
new Drawing(
new DW.Inline(
new DW.Extent() { Cx = 990000L, Cy = 792000L },
new DW.EffectExtent()
{
LeftEdge = 0L,
TopEdge = 0L,
RightEdge = 0L,
BottomEdge = 0L
},
new DW.DocProperties()
{
Id = 1U,
Name = "Picture 1"
},
new DW.NonVisualGraphicFrameDrawingProperties(
new A.GraphicFrameLocks() { NoChangeAspect = true }),
new A.Graphic(
new A.GraphicData(
new PIC.Picture(
new PIC.NonVisualPictureProperties(
new PIC.NonVisualDrawingProperties()
{
Id = (UInt32Value)0U,
Name = "New Bitmap Image.jpg"
},
new PIC.NonVisualPictureDrawingProperties()),
new PIC.BlipFill(
new A.Blip(
new A.BlipExtensionList(
new A.BlipExtension()
{
Uri =
"{28A0092B-C50C-407E-A947-70E740481C1C}"
})
)
{
Embed = relationshipId,
CompressionState =
A.BlipCompressionValues.Print
},
new A.Stretch(
new A.FillRectangle())),
new PIC.ShapeProperties(
new A.Transform2D(
new A.Offset() { X = 0L, Y = 0L },
new A.Extents() { Cx = 990000L, Cy = 792000L }),
new A.PresetGeometry(
new A.AdjustValueList()
)
{ Preset = A.ShapeTypeValues.Rectangle }))
)
{ Uri = "http://schemas.openxmlformats.org/drawingml/2006/picture" })
)
{
DistanceFromTop = 0U,
DistanceFromBottom = 0U,
DistanceFromLeft = 0U,
DistanceFromRight = 0U,
EditId = "50D07946"
});
wordDoc.MainDocumentPart.Document.Body.AppendChild(new Paragraph(new Run(element)));
}
Now to join this two methods together
public void InsertPicture(Canvas c)
{
using (var word = OpenXmlHelper.Create(filePath))
{
var stream = c.CreateJPGStream();
word.InsertPicture(stream);
}
}
But when I open the document, I get this
Am I doing something wrong with the memorysteam or on the openxml side? Can someone enlighten me please.
PS: I have looked at similar questions already like Inserting Image into DocX using OpenXML and setting the size
After writing to a stream, the stream's position will be at the end of the stream. You must rewind the stream to the beginning before you read from it.
stream.Position = 0;
or
stream.Seek(0, System.IO.SeekOrigin.Begin);

How to optimally find the smallest image rendered by a WPF control

I am using the FormulaControl from WPF-Math to render a bitmap for a tek equation. The bitmap will be delivered as content over a web service ( slack ). There is no desktop component. I am only using the WPF framework to try to capture the image from the tek control. The code for the renderer component is
public static class Renderer
{
private static readonly StaTaskScheduler _StaTaskScheduler = new StaTaskScheduler( 1 );
public static async Task<string> GenerateImage(string formula)
{
string Build()
{
var control = new FormulaControl
{
Formula = formula
, Background = Brushes.White
};
control.Measure(new Size(300, 300));
control.Arrange(new Rect(new Size(300, 300)));
var bmp = new RenderTargetBitmap(300, 300, 96, 96, PixelFormats.Pbgra32);
bmp.Render(control);
var encoder = new PngBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(bmp));
var file = #"test.png";
using (Stream stm = File.Create(file))
encoder.Save(stm);
return file;
}
return await Task.Factory.StartNew
( Build, CancellationToken.None, TaskCreationOptions.None, _StaTaskScheduler );
}
}
Using the above code and the input
k_{n+1} = n^2 + k_n^2 - k_{n-1}
the below image is generated
As you can see, in this case, an arbitrary size of 300x300 is too big and for a different tek input it maybe too small.
The challenge is to generate a bitmap of exactly the correct size for the rendered equation. How can this be done?
One solution is to render to a large bitmap then auto crop the whitespace. There is a solution for auto cropping whitespace at
Cropping whitespace from image in C#
Using the ImageCrop class from above I modified the rendering code to
public static class Renderer
{
private static readonly StaTaskScheduler _StaTaskScheduler = new StaTaskScheduler( 1 );
public static Bitmap Convert( RenderTargetBitmap inmap )
{
MemoryStream stream = new MemoryStream();
BitmapEncoder encoder = new BmpBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(inmap));
encoder.Save(stream);
Bitmap bitmap = new Bitmap(stream);
return bitmap;
}
public static async Task<string> GenerateImage(string formula)
{
string Build()
{
var control = new FormulaControl
{
Formula = formula
, Background = Brushes.White
};
control.Measure(new Size(300, 300));
control.Arrange(new Rect(new Size(300, 300)));
var bmp = new RenderTargetBitmap(300, 300, 96, 96, PixelFormats.Pbgra32);
bmp.Render(control);
var image = ImageCrop.AutoCrop( Convert( bmp ) );
var file = #"test.png";
image.Save( file,ImageFormat.Png );
return file;
}
return await Task.Factory.StartNew
( Build, CancellationToken.None, TaskCreationOptions.None, _StaTaskScheduler );
}
}
The output in my slackbot is now perfectly cropped.
Obviously this is not perfect as there is an upper bound on the render size.

Download and save .pdf file in Documents/Download Folder - WP8 Silverlight

Direct to the point: I want to download and save a .pdf file so that the user can see it later in the Media Library.
I'm looking for a way to achieve this in Windows Phone 8 Silverlight.
Here is the code I'm using right now:
private void DownloadPDF(string url)
{
var client = new WebClient();
client.OpenReadCompleted += client_OpenReadCompleted;
this.FileName = Path.GetFileName(url);
client.OpenReadAsync(new Uri(url));
}
async void client_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
{
// Save file:
var buffer = new byte[e.Result.Length];
await e.Result.ReadAsync(buffer, 0, buffer.Length);
using (var storageFile = IsolatedStorageFile.GetUserStoreForApplication())
{
using (var stream = storageFile.OpenFile(this.FileName, FileMode.Create))
{
await stream.WriteAsync(buffer, 0, buffer.Length);
}
}
// Open file:
var local = ApplicationData.Current.LocalFolder;
var pdffile = await local.GetFileAsync(this.FileName);
Windows.System.Launcher.LaunchFileAsync(pdffile);
var progressIndicator = new ProgressIndicator()
{
IsVisible = false
};
SystemTray.SetProgressIndicator(this, progressIndicator);
}
Thank you very much!

Error converting clipboard image

Using WPF 4.5
private Bitmap BitmapFromSource(BitmapSource bitmapsource)
{
Bitmap bitmap;
using (var outStream = new MemoryStream())
{
BitmapEncoder enc = new BmpBitmapEncoder();
enc.Frames.Add(BitmapFrame.Create(bitmapsource));
enc.Save(outStream);
bitmap = new Bitmap(outStream);
}
return bitmap;
}
}
and then later:
if (Clipboard.ContainsImage())
{
var bitmapSouce = Clipboard.GetImage();
var bitmap = BitmapFromSource(bitmapSouce);
var tmp = Path.GetTempFileName();
bitmap.Save(tmp, ImageFormat.Png);
...
bitmap.Save() throws an ExternalException, "A generic error in GDI+"
Is it really so hard to save a clipboard image to disk?
It is not necessary to create a System.Drawing.Bitmap (which is WinForms) from a WPF BitmapSource just for saving it.
You could as well directly save to a FileStream:
private void SaveBitmap(BitmapSource bitmapSource, string fileName)
{
var enc = new PngBitmapEncoder();
enc.Frames.Add(BitmapFrame.Create(bitmapSource));
using (var outStream = new FileStream(fileName, FileMode.Create))
{
enc.Save(outStream);
}
}
...
var bitmapSource = Clipboard.GetImage();
var tmp = Path.GetTempFileName();
SaveBitmap(bitmapSource, tmp);

Save content of a visual Object as a image file in WPF?

I need to save the content of a WPF Object as an Image file. In my application I have a chart drawn on a Canvas object. This is what I need to save. The Canvas with all child objects.
What you're looking for is the RenderTargetBitmap class. There's an example of its use on the MSDN page I linked, and there's another good example that includes saving to a file here:
RenderTargetBitmap by Eric Sinc
Here is the func which creates RenderTargetBitmap object, that will be used in further funcs.
public static RenderTargetBitmap ConvertToBitmap(UIElement uiElement, double resolution)
{
var scale = resolution / 96d;
uiElement.Measure(new Size(Double.PositiveInfinity, Double.PositiveInfinity));
var sz = uiElement.DesiredSize;
var rect = new Rect(sz);
uiElement.Arrange(rect);
var bmp = new RenderTargetBitmap((int)(scale * (rect.Width)), (int)(scale * (rect.Height)), scale * 96, scale * 96, PixelFormats.Default);
bmp.Render(uiElement);
return bmp;
}
This functionc creates JPEG string content of file and writes it to a file:
public static void ConvertToJpeg(UIElement uiElement, string path, double resolution)
{
var jpegString = CreateJpeg(ConvertToBitmap(uiElement, resolution));
if (path != null)
{
try
{
using (var fileStream = File.Create(path))
{
using (var streamWriter = new StreamWriter(fileStream, Encoding.Default))
{
streamWriter.Write(jpegString);
streamWriter.Close();
}
fileStream.Close();
}
}
catch (Exception ex)
{
//TODO: handle exception here
}
}
}
This function used above to create JPEG string representation of Image content:
public static string CreateJpeg(RenderTargetBitmap bitmap)
{
var jpeg = new JpegBitmapEncoder();
jpeg.Frames.Add(BitmapFrame.Create(bitmap));
string result;
using (var memoryStream = new MemoryStream())
{
jpeg.Save(memoryStream);
memoryStream.Seek(0, SeekOrigin.Begin);
using (var streamReader = new StreamReader(memoryStream, Encoding.Default))
{
result = streamReader.ReadToEnd();
streamReader.Close();
}
memoryStream.Close();
}
return result;
}
Hope this helps.
With the help of the Eric Sinc tutorial I came to the following solution:
It uses a win32 SaveDialog to choose where the file should go and a PngBitmapEncoder (many other BitmapEncoders available!) to convert it to something we can save.
Note that the element being saved in this example is "cnvClasses" and that the size of the output is, quite deliberately, the same as the control.
SaveFileDialog svDlg = new SaveFileDialog();
svDlg.Filter = "PNG files|*.png|All Files|*.*";
svDlg.Title = "Save diagram as PNG";
if (svDlg.ShowDialog().Value == true)
{
RenderTargetBitmap render = new RenderTargetBitmap((int)this.cnvClasses.ActualWidth, (int)this.cnvClasses.ActualHeight, 96, 96, PixelFormats.Pbgra32);
render.Render(cnvClasses);
PngBitmapEncoder encoder = new PngBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(render));
using (FileStream fs = new FileStream(svDlg.FileName, FileMode.Create))
encoder.Save(fs);
}

Resources