i want to generate image for windows 8 app, i'm going to use SharpDX API
here is the code sample which i thankfully coped and paste
private MemoryStream RenderStaticTextToBitmap()
{
var width = 400;
var height = 100;
var pixelFormat = WicPixelFormat.Format32bppBGR;
var wicFactory = new ImagingFactory();
var dddFactory = new SharpDX.Direct2D1.Factory();
var dwFactory = new SharpDX.DirectWrite.Factory();
var wicBitmap = new Bitmap(
wicFactory,
width,
height,
pixelFormat,
BitmapCreateCacheOption.CacheOnLoad);
var renderTargetProperties = new RenderTargetProperties(
RenderTargetType.Default,
new D2DPixelFormat(Format.Unknown, AlphaMode.Unknown),
0,
0,
RenderTargetUsage.None,
FeatureLevel.Level_DEFAULT);
var renderTarget = new WicRenderTarget(
dddFactory,
wicBitmap,
renderTargetProperties)
{
TextAntialiasMode = TextAntialiasMode.Cleartype
};
renderTarget.BeginDraw();
var textFormat = new TextFormat(dwFactory, "Consolas", 48)
{
TextAlignment = SharpDX.DirectWrite.TextAlignment.Center,
ParagraphAlignment = ParagraphAlignment.Center
};
var textBrush = new SharpDX.Direct2D1.SolidColorBrush(
renderTarget,
SharpDX.Colors.Blue);
renderTarget.Clear(Colors.White);
renderTarget.DrawText(
"Hi, mom!",
textFormat,
new RectangleF(0, 0, width, height),
textBrush);
renderTarget.EndDraw();
var ms = new MemoryStream();
var stream = new WICStream(
wicFactory,
ms);
var encoder = new PngBitmapEncoder(wicFactory);
encoder.Initialize(stream);
var frameEncoder = new BitmapFrameEncode(encoder);
frameEncoder.Initialize();
frameEncoder.SetSize(width, height);
frameEncoder.PixelFormat = WicPixelFormat.FormatDontCare;
frameEncoder.WriteSource(wicBitmap);
frameEncoder.Commit();
encoder.Commit();
frameEncoder.Dispose();
encoder.Dispose();
stream.Dispose();
ms.Position = 0;
return ms;
}
this working in excellent way with installed fonts .... i have font in the assets folder and i want to use -i have about 604 custom fonts and i chose the font dynamically- , i know there is away to load file from folder .... help plz
Unfortunately, afaik, there is no API in DirectWrite that supports this easily. You need to develop your own font loader and related classes. There is the SharpDX sample CustomFont that is loading fonts from resources, so you could adapt it to load from another location.
Related
I am trying to move my code from using System.Drawing.Image to using SkiaSharp as recommended here.
I trying to find similar operations for working with Tif files from a stream.
Currently, the following is what I have using System.Drawing.Image:
System.Drawing.Image MyImage = System.Drawing.Image.FromStream(inStream);
PdfDocument doc = new PdfDocument();
for (int PageIndex = 0; PageIndex < MyImage.GetFrameCount(FrameDimension.Page); PageIndex++)
{
MyImage.SelectActiveFrame(FrameDimension.Page, PageIndex);
XImage img = XImage.FromGdiPlusImage(MyImage);
var page = new PdfPage();
page.Width = MyImage.Width;
page.Height = MyImage.Height;
doc.Pages.Add(page);
XGraphics xgr = XGraphics.FromPdfPage(doc.Pages[PageIndex]);
xgr.DrawImage(img, 0, 0, page.Width, page.Height);
}
doc.Save(outStream);
MyImage.Dispose();
My current work with SkiaSharp is the following though it does not work correctly. Note: The following code has the following error and I am trying to figure out why in addition to how to select active frames: Unhandled exception. System.ObjectDisposedException: Cannot access a closed Stream. likely due to SKCodec codec = SkiaSharp.SKCodec.Create(inStream); but I am not sure why.
PdfDocument doc = new PdfDocument();
doc.Info.CreationDate = new DateTime();
using MemoryStream inStream = new MemoryStream(data);
using var imgStream = new SKManagedStream(inStream, false);
using var skData = SKData.Create(imgStream);
using SKCodec codec = SKCodec.Create(skData);
// TODO: codec is null!
for (int PageIndex = 0; PageIndex < codec.FrameCount; PageIndex++)
{
SKImageInfo imageInfo = new SKImageInfo(codec.Info.Width, codec.Info.Height);
// create bitmap stub
using SKBitmap skBitmap = new SKBitmap(imageInfo);
IntPtr pixelsPtr = skBitmap.GetPixels();
// decode particular frame into the bitmap
codec.GetPixels(imageInfo, pixelsPtr, new SKCodecOptions(PageIndex));
// encode bitmap back
using SKData encodedData = skBitmap.Encode(SKEncodedImageFormat.Png, 100);
using Stream frameStream = encodedData.AsStream();
XImage img = XImage.FromStream(frameStream);
var page = new PdfPage();
doc.Pages.Add(page);
XGraphics xgr = XGraphics.FromPdfPage(doc.Pages[PageIndex]);
xgr.DrawImage(img, 0, 0, page.Width, page.Height);
}
doc.Save(destination);
These are other things I have tried:
Using SKCodecOptions to set the FrameIndex but how would I use it since it used for GetPixels() not Decode().
There are no properties, I found, that control FrameIndex within a SKBitmap.
The additional conversion from Image to XImage is a bit confusing as from the source here, it appears to be a constructor that creates an XImage straight from an Image. I would need to create an XImage from a SkiaSharp.SKBitmap instead I believe thought I'm not quite sure how to do this at the moment such as use an existing method like FromStream() though I don't know the differences between the uses necesarily.
You get the exception because decoding SKBitmap with
SkiaSharp.SKBitmap MyImage = SkiaSharp.SKBitmap.Decode(inStream);
disposes the inStream.
Anyway, to get the particular frame using SkiaSharp, you need to get pixels from the codec:
using MemoryStream inStream = new MemoryStream(data);
PdfDocument doc = new PdfDocument();
doc.Info.CreationDate = new DateTime();
using SKCodec codec = SkiaSharp.SKCodec.Create(inStream);
for (int PageIndex = 0; PageIndex < codec.FrameCount; PageIndex++)
{
SKImageInfo imageInfo = new SKImageInfo(codec.Info.Width, codec.Info.Height);
// create bitmap stub
using SKBitmap skBitmap = new SKBitmap(imageInfo);
IntPtr pixelsPtr = skBitmap.GetPixels();
// decode particular frame into the bitmap
codec.GetPixels(imageInfo, pixelsPtr, new SKCodecOptions(PageIndex));
// encode bitmap back
using SKData encodedData = skBitmap.Encode(SKEncodedImageFormat.Png, 100);
using Stream frameStream = encodedData.AsStream();
XImage img = XImage.FromStream(frameStream);
var page = new PdfPage();
doc.Pages.Add(page);
XGraphics xgr = XGraphics.FromPdfPage(doc.Pages[PageIndex]);
xgr.DrawImage(img, 0, 0, page.Width, page.Height);
}
doc.Save(destination);
I am working on a QR Code project and one of the requirements is to be able to download the generated QR Code in SVG format. I was able to display the generated QR Code in PNG format, but I have been trying to download it in SVG format.
I am using XZing library to generate the QR Code in PNG
Color barcodeColor = System.Drawing.ColorTranslator.FromHtml(colorHex);
BarcodeWriter barcodeWriter = new BarcodeWriter
{
Format = BarcodeFormat.QR_CODE,
Options = new EncodingOptions
{
Width = width,
Height = height,
PureBarcode = true
},
Renderer = new BitmapRenderer
{
Foreground = barcodeColor
}
};
Bitmap barCodeBitmap = barcodeWriter.Write(qrContent);
var memoryStream = new MemoryStream();
// save to stream as PNG
barCodeBitmap.Save(memoryStream, System.Drawing.Imaging.ImageFormat.Png);
HttpResponseMessage response = new HttpResponseMessage();
response.Content = new ByteArrayContent(memoryStream.ToArray());
response.Content.Headers.ContentType = new MediaTypeHeaderValue("image/jpeg");
response.StatusCode = HttpStatusCode.OK;
return response;
I was able to create a BarcodeWriterSvg object but I wasn't able to convert it into a stream and pass it in the header like the PNG
BarcodeWriterSvg barcodeWriter = new BarcodeWriterSvg
{
Format = BarcodeFormat.QR_CODE,
Options = new EncodingOptions
{
Width = width,
Height = height,
PureBarcode = true
},
Renderer = new SvgRenderer
{
Foreground = barcodeColor
}
};
var barCodeBitmap = barcodeWriter.Write(qrContent);
var memoryStream = new MemoryStream();
HttpResponseMessage response = new HttpResponseMessage();
...
My question is how to be able to convert the object into a stream and pass it in the header? The ultimate goal is to be able to download the file without actually creating a physical copy.
Off the top of my head, and attempting to use the same code paradigm from your example, I would look into something like this:
var barcodeWriter = new BarcodeWriterSvg();
....
....
var svgImage = barcodeWriter.Write(text); //ZXing.Rendering.SvgRenderer.SvgImage
var response = new HttpResponseMessage();
response.Content = new StringContent(svgImage.Content);
response.Content.Headers.ContentType = new MediaTypeHeaderValue("image/svg+xml");
return response;
I'm trying to save an UIElement created programmatically in a JPG/PNG/BMP image in a Windows Phone 8.1 (C#) application.
I'm using the class RenderTargetBitmap using the method RenderAsync() but it only works with UI elements created in the XAML code. When I use it on UI elements created directly in C# I have this exception: "System.ArgumentException (Value does not fall within the expected range.)"
Am I doing something wrong or this class doesn't allow rendering of UIElement(s) created programmatically? Is there any way to do this on Windows Phone 8.1? Thank you!
Here's the code I use:
private static async void RenderText(string text, int width, int height, int fontsize, string imagename)
{
RenderTargetBitmap b = new RenderTargetBitmap();
var canvas = new Grid();
canvas.Width = width;
canvas.Height = height;
var background = new Canvas();
background.Height = width;
background.Width = height;
SolidColorBrush backColor = new SolidColorBrush(Colors.Red);
background.Background = backColor;
var textBlock = new TextBlock();
textBlock.Text = text;
textBlock.FontWeight = FontWeights.Bold;
textBlock.TextAlignment = TextAlignment.Left;
textBlock.HorizontalAlignment = HorizontalAlignment.Center;
textBlock.VerticalAlignment = VerticalAlignment.Stretch;
textBlock.Margin = new Thickness(35);
//textBlock.Width = b.PixelWidth - textBlock.Margin.Left * 2;
textBlock.TextWrapping = TextWrapping.Wrap;
textBlock.Foreground = new SolidColorBrush(Colors.White); //color of the text on the Tile
textBlock.FontSize = fontsize;
canvas.Children.Add(textBlock);
await b.RenderAsync(background);
await b.RenderAsync(canvas);
// Get the pixels
var pixelBuffer = await b.GetPixelsAsync();
// Get the local folder.
StorageFolder local = Windows.Storage.ApplicationData.Current.LocalFolder;
// Create a new folder name DataFolder.
var dataFolder = await local.CreateFolderAsync("DataFolder",
CreationCollisionOption.OpenIfExists);
StorageFile file = await dataFolder.CreateFileAsync(imagename, CreationCollisionOption.ReplaceExisting);
// Encode the image to the selected file on disk
using (var fileStream = await file.OpenStreamForWriteAsync())
{
var encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.PngEncoderId, fileStream.AsRandomAccessStream());
encoder.SetPixelData(
BitmapPixelFormat.Bgra8,
BitmapAlphaMode.Ignore,
(uint)b.PixelWidth,
(uint)b.PixelHeight,
DisplayInformation.GetForCurrentView().LogicalDpi,
DisplayInformation.GetForCurrentView().LogicalDpi,
pixelBuffer.ToArray());
await encoder.FlushAsync();
}
}
It is not working only with elements created in XAML but with these that (as MSDN says) are in VisualTree:
Renders a snapshot of a UIElement visual tree to an image source.
So your method will work if you add your elements for example to your current Page:
LayoutRoot.Children.Add(canvas);
Your UIElemet Height and Width values will be 0 when you create them using code. If you want the image in a particular resolution, try to assign the same height and width to the UIElement as well.
The code shown below worked well for me.
public static void SaveElementAsJPG(FrameworkElement element, string ImageName)
{
WriteableBitmap wBitmap = new WriteableBitmap(element, null);
using (MemoryStream stream = new MemoryStream())
{
wBitmap.SaveJpeg(stream, (int)element.ActualWidth, (int)element.ActualHeight, 0, 100);
wBitmap = null;
//Use can either save the file to isolated storage or media library.
//Creates file in Isolated Storage.
using (var local = new IsolatedStorageFileStream(ImageName, FileMode.Create, IsolatedStorageFile.GetUserStoreForApplication()))
{
local.Write(stream.GetBuffer(), 0, stream.GetBuffer().Length);
}
//Creates file in Media Library.
var lib = new MediaLibrary();
var picture = lib.SavePicture(ImageName, stream.GetBuffer());
}
}
I'm using QrCode.Net library version 0.3 and I need to use Gma.QrCodeNet.Encoding.Windows.Render in order to create images with qrcode ISizeCalculation but I'm missing somethig or there's another version outhere. What can be the problem?
Anyway I found a solution for people with the same problem and they wanna create images with the same fixed size. Here is the code:
private void gen_qr_file(string file_name, string content, int image_size)
{
string new_file_name = file_name;
QrEncoder qrEncoder = new QrEncoder(ErrorCorrectionLevel.H);
QrCode qrCode = new QrCode();
qrEncoder.TryEncode(content, out qrCode);
Renderer renderer = new Renderer(image_size, Brushes.Black, Brushes.White);
MemoryStream ms = new MemoryStream();
renderer.WriteToStream(qrCode.Matrix, ms, ImageFormat.Png);
var image = new Bitmap(Image.FromStream(ms), new Size(new Point(200, 200)));
image.Save(new_file_name + ".png", ImageFormat.Png);
}
This generate a png image of 200x200 pixels with the qrcode.
The library itself has a method to do this, but I need to include the RENDER thing and I can't. Someone knows what's the problem?
private void gen_qr_file(string file_name, string content, int image_size) {
string new_file_name = file_name;
QrEncoder qrEncoder = new QrEncoder(ErrorCorrectionLevel.H);
QrCode qrCode = new QrCode();
qrEncoder.TryEncode(content, out qrCode);
Renderer renderer = new Renderer(image_size, Brushes.Black, Brushes.White);
MemoryStream ms = new MemoryStream();
renderer.WriteToStream(qrCode.Matrix, ms, ImageFormat.Png);
var imageTemp = new Bitmap(ms);
var image = new Bitmap(imageTemp, new Size(new Point(image_size, image_size)));
image.Save(new_file_name + ".png", ImageFormat.Png);
}
Note: Only 2 lines are modified. I hope it helps somebody.
Use FixedCodeSize. See example below which will produce a 400x400px image, with each 'module' (block) getting smaller the more data is added.
var qrEncoder = new QrEncoder(ErrorCorrectionLevel.M);
var qrCode = qrEncoder.Encode("my value");
var renderer = new GraphicsRenderer(new FixedCodeSize(400, QuietZoneModules.Zero), Brushes.Black, Brushes.White);
renderer.WriteToStream(qrCode.Matrix, ImageFormat.Png, /* OUTPUT STREAM */);
I had to include both of the following statements:
using Gma.QrCodeNet.Encoding;
using Gma.QrCodeNet.Encoding.Windows.Controls;
Also, how big is Gma.QrCodeNet.Encoding.dll ?
It should be over 80K or you have the wrong one.
I had the same issue.
This is my implementation Only change GraphicsRenderer
private string gen_qr_file(string file_name, string content, int image_size)
{
string new_file_name = file_name;
QrEncoder qrEncoder = new QrEncoder(ErrorCorrectionLevel.H);
QrCode qrCode = new QrCode();
qrEncoder.TryEncode(content, out qrCode);
GraphicsRenderer renderer = new GraphicsRenderer(
new FixedCodeSize(400, QuietZoneModules.Zero),
Brushes.Black,
Brushes.White);
MemoryStream ms = new MemoryStream();
renderer.WriteToStream(qrCode.Matrix, ImageFormat.Png, ms);
var imageTemp = new Bitmap(ms);
var image = new Bitmap(imageTemp, new Size(new Point(200, 200)));
image.Save(new_file_name, ImageFormat.Png);
return new_file_name;
}
I'm trying to convert an XPS with WPF.
The idea is that these images can be loaded with silverlight 4, for this I am using the following code:
// XPS Document
XpsDocument xpsDoc = new XpsDocument(xpsFileName, System.IO.FileAccess.Read);
FixedDocumentSequence docSeq = xpsDoc.GetFixedDocumentSequence();
// The number of pages
PageCount = docSeq.References[0].GetDocument(false).Pages.Count;
DocumentPage sizePage = docSeq.DocumentPaginator.GetPage(0);
PageHeight = sizePage.Size.Height;
PageWidth = sizePage.Size.Width;
// Scale dimensions from 96 dpi to 600 dpi.
double scale = 300/ 96;
// Convert a XPS page to a PNG file
for (int pageNum = 0; pageNum < PageCount; pageNum++)
{
DocumentPage docPage = docSeq.DocumentPaginator.GetPage(pageNum);
BitmapImage bitmap = new BitmapImage();
RenderTargetBitmap renderTarget =
new RenderTargetBitmap((int)(scale * (docPage.Size.Height + 1)),
(int)(scale * (docPage.Size.Height + 1)),
scale * 96,
scale * 96, PixelFormats.Pbgra32);
renderTarget.Render(docPage.Visual);
PngBitmapEncoder encoder = new PngBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(renderTarget));
FileStream pageOutStream = new FileStream(name + ".Page" + pageNum + ".png", FileMode.Create, FileAccess.Write);
encoder.Save(pageOutStream);
pageOutStream.Close();
This code is taken from http://xpsreader.codeplex.com/ a project to convert an XPS document.
works great!
But the problem is that the image is low resolution and blurry.
I researched and found that RenderTargetBitmap and find on this page:
http://www.codeproject.com/Questions/213737/Render-target-bitmap-quality-issues
The issue here is you Have That does not use hardware RenderTargetBitmap rendering.
One solution is to use DirectX with WPF to do this, but have not found any clear example to show me the right way to do it.
I appreciate suggestions. Thanks in advance.
Update:I attached the XPS document, I am trying to convert the image
Please download test.xps
There is a project named xps2img on sourceforge.net which converts an xps to image. It is made in C# and also contains the source code. Check it out. It will help you to achieve what you want.
http://sourceforge.net/projects/xps2img/files/
I saw in this post and in many others that peoples have problems with conversion of DocumentPage to Image and saving it on HDD.
This method took all pages from document viewer and save them on HDD as jpg images.
public void SaveDocumentPagesToImages(IDocumentPaginatorSource document, string dirPath)
{
if (string.IsNullOrEmpty(dirPath)) return;
if (dirPath[dirPath.Length - 1] != '\\')
dirPath += "\\";
if (!Directory.Exists(dirPath)) return;
MemoryStream[] streams = null;
try
{
int pageCount = document.DocumentPaginator.PageCount;
DocumentPage[] pages = new DocumentPage[pageCount];
for (int i = 0; i < pageCount; i++)
pages[i] = document.DocumentPaginator.GetPage(i);
streams = new MemoryStream[pages.Count()];
for (int i = 0; i < pages.Count(); i++)
{
DocumentPage source = pages[i];
streams[i] = new MemoryStream();
RenderTargetBitmap renderTarget =
new RenderTargetBitmap((int)source.Size.Width,
(int)source.Size.Height,
96, // WPF (Avalon) units are 96dpi based
96,
System.Windows.Media.PixelFormats.Default);
renderTarget.Render(source.Visual);
JpegBitmapEncoder encoder = new JpegBitmapEncoder(); // Choose type here ie: JpegBitmapEncoder, etc
encoder.QualityLevel = 100;
encoder.Frames.Add(BitmapFrame.Create(renderTarget));
encoder.Save(streams[i]);
FileStream file = new FileStream(dirPath + "Page_" + (i+1) + ".jpg", FileMode.CreateNew);
file.Write(streams[i].GetBuffer(), 0, (int)streams[i].Length);
file.Close();
streams[i].Position = 0;
}
}
catch (Exception e1)
{
throw e1;
}
finally
{
if (streams != null)
{
foreach (MemoryStream stream in streams)
{
stream.Close();
stream.Dispose();
}
}
}
}
A nuget package based on xps2img is now available:
https://www.nuget.org/packages/xps2img/
Api available here:
https://github.com/peters/xps2img#usage
private IList<byte[]> GetTifPagesFromXps(string xXpsFileName, double xQuality)
{
using (var xpsDoc = new XpsDocument(xXpsFileName, FileAccess.Read))
{
var docSeq = xpsDoc.GetFixedDocumentSequence();
var tifPages = new List<byte[]>();
for (var i = 0; i < docSeq.DocumentPaginator.PageCount; i++)
{
using (var docPage = docSeq.DocumentPaginator.GetPage(i))
{
var renderTarget = new RenderTargetBitmap((int)(docPage.Size.Width * xQuality), (int)(docPage.Size.Height * xQuality), 96 * xQuality, 96 * xQuality, PixelFormats.Default);
renderTarget.Render(docPage.Visual);
var jpegEncoder = new JpegBitmapEncoder { QualityLevel = 100 };
jpegEncoder.Frames.Add(BitmapFrame.Create(renderTarget));
byte[] buffer;
using (var memoryStream = new MemoryStream())
{
jpegEncoder.Save(memoryStream);
memoryStream.Seek(0, SeekOrigin.Begin);
buffer = memoryStream.GetBuffer();
}
tifPages.Add(buffer);
}
}
xpsDoc.Close();
return tifPages.ToArray();
}
}