i am using MagickImage to change Dpi of an image but it doesn't work
MagickNET.SetGhostscriptDirectory(System.IO.Directory.GetCurrentDirectory());
MagickReadSettings settings = new MagickReadSettings();
settings.Density = new Density(72, 72);
using (MagickImage image = new MagickImage(#"C:\Users\User\AppData\Local\Temp\Chapter 4\Figure 4-1.tif", settings))
{
image.Write(#"C:\Users\User\AppData\Local\Temp\Chapter 4\Figure 4-1.jpg");
}
or if this doesn't work
is there a way to resize the image like what the photoshop did
example the image with 300 dPi have a w1200xh788 size
and using photoshop. i changed the dpi to 72 and it creates a w288xh189
how can i programmatically do this. thank you
You can do as following :
using System;
namespace ImageDPI
{
public class Program
{
public static void Main(string[] args)
{
int Aw, Ah, Rw, Rh, Adpi, Rdpi;
Aw = 1200;
Ah = 788;
Adpi = 300;
Rdpi = 72;
Rw= (Aw * Rdpi) / Adpi;
Rh= (Ah * Rdpi) / Adpi;
Console.WriteLine(Rw);
Console.WriteLine(Rh);
}
}
}
Related
I'm trying to scale down large images (~ 23k x 1k) to be displayed in winforms. The current way I'm scaling the images is taking too long, which is why I want to use the GPU through SharpDX (C#) to improve performance. What would be a good way to do this?
I'm working on a method to scale an image by applying the scale effect (that I don't have access to right now), but I still don't fully understand SharpDX, so I'm wondering if there's a better way to go about this. I modeled my code off of this example but I removed the text overlay, the image saving, the drawing portion, and I replaced the gaussian with the scaling effect. Since I'm using GDI to do the drawing for simplicity, the image is in the form of a systems drawing bitmap so I initialize the encoder with a memory stream that I use to get the output image after the scaling effect is applied. The smaller tests I have done with this method don't seem to make the scaling much quicker, but I haven't been able to put this fully in action yet.
Is there a quicker way to scale down an image using SharpDX, or is something along the lines of my current method the quickest?
Based on what I found on https://csharp.hotexamples.com/examples/SharpDX.WIC/WICStream/-/php-wicstream-class-examples.html
Looks like SharpDX about twice the performance of GDI or better.
Test code that works on my Windows 11 computer. Should be enough to get you started even if you know as little of SharpDX as I do.
var inputPath = #"x:\Temp\1\_Landscape.jpg";
var data = File.ReadAllBytes(inputPath);
var sw = Stopwatch.StartNew();
var iu6 = new ImageUtilities6();
Debug.WriteLine($"Init: {sw.ElapsedMilliseconds}ms total");
for (int i = 0; i < 10; i++)
{
sw.Restart();
var image = iu6.ResizeImage(data, 799, 399);
Debug.WriteLine($"Resize: {sw.ElapsedMilliseconds}ms total");
File.WriteAllBytes(#"X:\TEMP\1\007-xxx.jpg", image);
}
sw.Restart();
iu6.Dispose();
Debug.WriteLine($"Dispose: {sw.ElapsedMilliseconds}ms total");
Class I made based on the samples found on that page.
using SharpDX;
using dw = SharpDX.DirectWrite;
using d2 = SharpDX.Direct2D1;
using d3d = SharpDX.Direct3D11;
using dxgi = SharpDX.DXGI;
using wic = SharpDX.WIC;
using System;
using System.IO;
using SharpDX.Direct3D11;
using SharpDX.WIC;
using SharpDX.DirectWrite;
namespace SharpDX_ImageResizingTest
{
public class ImageUtilities6 : IDisposable
{
private Device defaultDevice;
private Device1 d3dDevice;
private dxgi.Device dxgiDevice;
private d2.Device d2dDevice;
private ImagingFactory2 imagingFactory;
//private d2.DeviceContext d2dContext;
private Factory dwFactory;
private d2.PixelFormat d2PixelFormat;
public ImageUtilities6()
{
//SharpDX.Configuration.EnableObjectTracking = true; //Turn on memory leak logging
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// INITIALIZATION ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// initialize the D3D device which will allow to render to image any graphics - 3D or 2D
defaultDevice = new SharpDX.Direct3D11.Device(SharpDX.Direct3D.DriverType.Hardware,
d3d.DeviceCreationFlags.VideoSupport
| d3d.DeviceCreationFlags.BgraSupport
| d3d.DeviceCreationFlags.Debug); // take out the Debug flag for better performance
d3dDevice = defaultDevice.QueryInterface<d3d.Device1>(); // get a reference to the Direct3D 11.1 device
dxgiDevice = d3dDevice.QueryInterface<dxgi.Device>(); // get a reference to DXGI device
//var dxgiSurface = d3dDevice.QueryInterface<dxgi.Surface>(); // get a reference to DXGI surface
d2dDevice = new d2.Device(dxgiDevice); // initialize the D2D device
imagingFactory = new wic.ImagingFactory2(); // initialize the WIC factory
dwFactory = new dw.Factory();
// specify a pixel format that is supported by both D2D and WIC
d2PixelFormat = new d2.PixelFormat(dxgi.Format.R8G8B8A8_UNorm, d2.AlphaMode.Premultiplied);
// if in D2D was specified an R-G-B-A format - use the same for wic
}
public byte[] ResizeImage(byte[] image, int targetWidth, int targetHeight)
{
int dpi = 72; //96? does it even matter
var wicPixelFormat = wic.PixelFormat.Format32bppPRGBA;
// initialize the DeviceContext - it will be the D2D render target and will allow all rendering operations
var d2dContext = new d2.DeviceContext(d2dDevice, d2.DeviceContextOptions.None);
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// IMAGE LOADING ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
var imageStream = new MemoryStream(image);
//var decoder = new wic.PngBitmapDecoder(imagingFactory); // we will load a PNG image
var decoder = new wic.JpegBitmapDecoder(imagingFactory); // we will load a JPG image
var inputStream = new wic.WICStream(imagingFactory, imageStream); // open the image for reading
decoder.Initialize(inputStream, wic.DecodeOptions.CacheOnLoad);
// decode the loaded image to a format that can be consumed by D2D
var formatConverter = new wic.FormatConverter(imagingFactory);
var frame = decoder.GetFrame(0);
formatConverter.Initialize(frame, wicPixelFormat);
// load the base image into a D2D Bitmap
var inputBitmap = d2.Bitmap1.FromWicBitmap(d2dContext, formatConverter, new d2.BitmapProperties1(d2PixelFormat));
// store the image size - output will be of the same size
var inputImageSize = formatConverter.Size;
var pixelWidth = inputImageSize.Width;
var pixelHeight = inputImageSize.Height;
// Calculate correct aspect ratio
double aspectRatio = (double)pixelHeight / (double)pixelWidth;
double targetAspectRatio = (double)targetHeight / (double)targetWidth;
if (targetAspectRatio > aspectRatio)
{
targetHeight = (int)(targetHeight * (aspectRatio / targetAspectRatio));
}
else
{
targetWidth = (int)(targetWidth * (targetAspectRatio / aspectRatio));
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// EFFECT SETUP ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//Effect 1 : BitmapSource - take decoded image data and get a BitmapSource from it
//var bitmapSourceEffect = new d2.Effects.BitmapSource(d2dContext);
//bitmapSourceEffect.WicBitmapSource = formatConverter;
// Effect 2 : GaussianBlur - give the bitmapsource a gaussian blurred effect
//var gaussianBlurEffect = new d2.Effects.GaussianBlur(d2dContext);
//gaussianBlurEffect.SetInput(0, bitmapSourceEffect.Output, true);
//gaussianBlurEffect.StandardDeviation = 5f;
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// RENDER TARGET SETUP ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// create the d2d bitmap description using default flags (from SharpDX samples) and 96 DPI
var d2dBitmapProps = new d2.BitmapProperties1(d2PixelFormat, 96, 96, d2.BitmapOptions.Target | d2.BitmapOptions.CannotDraw);
// the render target
var d2dRenderTarget = new d2.Bitmap1(d2dContext, new Size2(targetWidth, targetHeight), d2dBitmapProps);
d2dContext.Target = d2dRenderTarget; // associate bitmap with the d2d context
d2dContext.BeginDraw();
//d2dContext.DrawImage(bitmapSourceEffect); //Way #1
//d2dContext.DrawImage(gaussianBlurEffect); //Way #2
//d2dContext.DrawBitmap(inputBitmap, 1, d2.InterpolationMode.Linear); //Way #3
d2dContext.DrawBitmap(inputBitmap, new SharpDX.Mathematics.Interop.RawRectangleF(0, 0, targetWidth, targetHeight), 1, d2.InterpolationMode.Linear, null, null); //Way #4 - resizing
d2dContext.EndDraw();
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// IMAGE SAVING ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// delete the output file if it already exists
//if (System.IO.File.Exists(outputPath)) System.IO.File.Delete(outputPath);
// use the appropiate overload to write either to stream or to a file
var outputStream = new MemoryStream();
var stream = new wic.WICStream(imagingFactory, outputStream);
// select the image encoding format HERE
var encoder = new wic.JpegBitmapEncoder(imagingFactory);
encoder.Initialize(stream);
var bitmapFrameEncode = new wic.BitmapFrameEncode(encoder);
bitmapFrameEncode.Options.ImageQuality = 0.95f;
bitmapFrameEncode.Initialize();
bitmapFrameEncode.SetSize(targetWidth, targetHeight);
bitmapFrameEncode.SetPixelFormat(ref wicPixelFormat);
// this is the trick to write D2D1 bitmap to WIC
var imageEncoder = new wic.ImageEncoder(imagingFactory, d2dDevice);
imageEncoder.WriteFrame(d2dRenderTarget, bitmapFrameEncode, new wic.ImageParameters(d2PixelFormat, dpi, dpi, 0, 0, targetWidth, targetHeight));
bitmapFrameEncode.Commit();
encoder.Commit();
imageEncoder.Dispose();
bitmapFrameEncode.Dispose();
encoder.Dispose();
stream.Dispose();
formatConverter.Dispose();
d2dRenderTarget.Dispose();
inputStream.Dispose();
decoder.Dispose();
inputBitmap.Dispose();
frame.Dispose();
d2dContext.Dispose();
return outputStream.ToArray();
}
public void Dispose()
{
//bitmapSourceEffect.Dispose();
dwFactory.Dispose();
imagingFactory.Dispose();
d2dDevice.Dispose();
dxgiDevice.Dispose();
d3dDevice.Dispose();
defaultDevice.Dispose();
//System.Diagnostics.Debug.WriteLine(SharpDX.Diagnostics.ObjectTracker.ReportActiveObjects()); Log that memory leak
}
public byte[] ResizeImage1(byte[] data, int width, int height)
{
var ms = new MemoryStream(data);
//Image image = Image.FromStream(ms);
System.Drawing.Image image = System.Drawing.Image.FromStream(ms, false, false);
System.Drawing.Bitmap result = new System.Drawing.Bitmap(width, height);
// set the resolutions the same to avoid cropping due to resolution differences
result.SetResolution(image.HorizontalResolution, image.VerticalResolution);
//use a graphics object to draw the resized image into the bitmap
using (System.Drawing.Graphics graphics = System.Drawing.Graphics.FromImage(result))
{
//set the resize quality modes to high quality
graphics.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
//draw the image into the target bitmap
graphics.DrawImage(image, 0, 0, result.Width, result.Height);
}
var stream = new System.IO.MemoryStream();
image.Save(stream, System.Drawing.Imaging.ImageFormat.Jpeg);
stream.Position = 0;
return stream.ToArray();
}
}
}
Library used was SharpDX + .Direct2D1 + .Direct3D11 + .DXGI 4.2.
I am using DevExpress 18.1 on Windows 10 with VS 2017 for a WPF application. Additionally I am using the DevExpress BarCode Class. I am trying to create a QR Code that is 1 inch in size but am unable to do it without using something like Photoshop to shrink the output. I think I must be missing something in the process. Below is the code being used:
using System.Diagnostics;
using System.Drawing;
using System.Text;
using System.Windows;
using DevExpress.BarCodes;
namespace WpfBarcode01
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Btn_1_Click(object sender, RoutedEventArgs e)
{
BarCode barCode = new BarCode();
barCode.Symbology = Symbology.QRCode;
barCode.CodeText =
"Alexander Johnathon Stevenson JR;Senior Software Developer;alexanderjohnathonstevensonjr#somesamplewebsite.com;20180709-08:00:00;9993334444;Los Angeles;CA;USA;ABC Company";
barCode.BackColor = Color.White;
barCode.ForeColor = Color.Black;
barCode.RotationAngle = 0;
barCode.CodeBinaryData = Encoding.Default.GetBytes(barCode.CodeText);
barCode.Options.QRCode.Version = QRCodeVersion.Version5;
barCode.Options.QRCode.CompactionMode = QRCodeCompactionMode.Byte;
barCode.Options.QRCode.ErrorLevel = QRCodeErrorLevel.H;
barCode.Options.QRCode.ShowCodeText = false;
barCode.DpiX = 100;
barCode.DpiY = 100;
barCode.AutoSize = false;
barCode.Unit = GraphicsUnit.Millimeter;
barCode.ImageWidth = (float)70;
barCode.ImageHeight = (float)70;
barCode.BarCodeImage.Save("d1.png", System.Drawing.Imaging.ImageFormat.Png);
Process.Start("d1.png");
}
}
}
When this runs, a QR Code is created which a hand held scanner is able to scan both on paper and screen. The problem is it is about 2.76 inches in size. I want one about 1 inch so I end up importing the .png file to Photoshop and reducing the image size to 1 inch. This works as the images now becomes small enough for label or document printing. This workflow though seems too time consuming if someone has to do this for a few hundred QR Codes.
I tried different values for the ImageWidth and ImageHeight as well as different values for DpiX and DPiY but no luck. And I tried to change the GraphicsUnit to Inches but that option does not seem to work as I always get an image of very irregular size. So I ended up using the Millimeter option for GraphicsUnit with a basis that 1 inch = 25.4 millimeters. If I use an ImageWidth or ImageHeight value lower than 65 the QR Code box gets clipped and becomes invalid for scanning.
Is there something else I can do to make the output be 1 inch and still valid? Or perhaps some graphic library call in DevExpress I can call to reduce the .png file to 1 inch like Photoshop does? Thanks in advance.
=====================================
Update July 9, 2018
Based on PepitoSH's suggested link below I was able to find a solution which I have added here in the code update. This code produces a 1 inch .png QRCode file which is a resize from the original that was 2.76 inches.
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.Text;
using System.Windows;
using DevExpress.BarCodes;
namespace WpfBarcode01
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Btn_1_Click(object sender, RoutedEventArgs e)
{
BarCode barCode = new BarCode();
barCode.Symbology = Symbology.QRCode;
barCode.CodeText =
"Alexander Johnathon Stevenson JR;Senior Software Developer;alexanderjohnathonstevensonjr#somesamplewebsite.com;20180709-08:00:00;9993334444;Los Angeles;CA;USA;ABC Company";
barCode.BackColor = Color.White;
barCode.ForeColor = Color.Black;
barCode.RotationAngle = 0;
barCode.CodeBinaryData = Encoding.Default.GetBytes(barCode.CodeText);
barCode.Options.QRCode.Version = QRCodeVersion.Version5;
barCode.Options.QRCode.CompactionMode = QRCodeCompactionMode.Byte;
barCode.Options.QRCode.ErrorLevel = QRCodeErrorLevel.H;
barCode.Options.QRCode.ShowCodeText = false;
barCode.Dpi = 200;
barCode.AutoSize = false; //needs to be off if specifying unit and widths
barCode.Unit = GraphicsUnit.Millimeter; // Note: 1 inch = 25.4 Millimeters
barCode.ImageWidth = 70F;
barCode.ImageHeight = 70F;
Bitmap bitmap = ResizeImage(barCode.BarCodeImage, 200, 200);
bitmap.Save("QRCode.png");
Process.Start("QRCode.png");
}
public static Bitmap ResizeImage(Image originalImage, int newWidthInPixels, int newHeightInPixels)
{
var destRect = new Rectangle(0, 0, newWidthInPixels, newHeightInPixels);
var destImage = new Bitmap(newWidthInPixels, newHeightInPixels);
destImage.SetResolution(originalImage.HorizontalResolution, originalImage.VerticalResolution);
using (var graphics = Graphics.FromImage(destImage))
{
graphics.CompositingMode = CompositingMode.SourceCopy;
graphics.CompositingQuality = CompositingQuality.HighQuality;
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphics.SmoothingMode = SmoothingMode.HighQuality;
graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
using (var wrapMode = new ImageAttributes())
{
wrapMode.SetWrapMode(WrapMode.TileFlipXY);
graphics.DrawImage(originalImage, destRect, 0, 0, originalImage.Width, originalImage.Height, GraphicsUnit.Pixel, wrapMode);
}
}
return destImage;
}
}
}
Update July 9, 2018
Based on PepitoSH's suggested link I was able to find a solution which I have added here in the code update. This code produces a 1 inch .png QRCode file which is a resize from the original that was 2.76 inches.
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.Text;
using System.Windows;
using DevExpress.BarCodes;
namespace WpfBarcode01
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Btn_1_Click(object sender, RoutedEventArgs e)
{
BarCode barCode = new BarCode();
barCode.Symbology = Symbology.QRCode;
barCode.CodeText =
"Alexander Johnathon Stevenson JR;Senior Software Developer;alexanderjohnathonstevensonjr#somesamplewebsite.com;20180709-08:00:00;9993334444;Los Angeles;CA;USA;ABC Company";
barCode.BackColor = Color.White;
barCode.ForeColor = Color.Black;
barCode.RotationAngle = 0;
barCode.CodeBinaryData = Encoding.Default.GetBytes(barCode.CodeText);
barCode.Options.QRCode.Version = QRCodeVersion.Version5;
barCode.Options.QRCode.CompactionMode = QRCodeCompactionMode.Byte;
barCode.Options.QRCode.ErrorLevel = QRCodeErrorLevel.H;
barCode.Options.QRCode.ShowCodeText = false;
barCode.Dpi = 200;
barCode.AutoSize = false; //needs to be off if specifying unit and widths
barCode.Unit = GraphicsUnit.Millimeter; // Note: 1 inch = 25.4 Millimeters
barCode.ImageWidth = 70F;
barCode.ImageHeight = 70F;
Bitmap bitmap = ResizeImage(barCode.BarCodeImage, 200, 200);
bitmap.Save("QRCode.png");
Process.Start("QRCode.png");
}
public static Bitmap ResizeImage(Image originalImage, int newWidthInPixels, int newHeightInPixels)
{
var destRect = new Rectangle(0, 0, newWidthInPixels, newHeightInPixels);
var destImage = new Bitmap(newWidthInPixels, newHeightInPixels);
destImage.SetResolution(originalImage.HorizontalResolution, originalImage.VerticalResolution);
using (var graphics = Graphics.FromImage(destImage))
{
graphics.CompositingMode = CompositingMode.SourceCopy;
graphics.CompositingQuality = CompositingQuality.HighQuality;
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphics.SmoothingMode = SmoothingMode.HighQuality;
graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
using (var wrapMode = new ImageAttributes())
{
wrapMode.SetWrapMode(WrapMode.TileFlipXY);
graphics.DrawImage(originalImage, destRect, 0, 0, originalImage.Width, originalImage.Height, GraphicsUnit.Pixel, wrapMode);
}
}
return destImage;
}
}
}
I use ZXing.Net library to generate a QR code image -
At the top of my class:
[System.Runtime.InteropServices.DllImport("gdi32.dll")]
public static extern bool DeleteObject(IntPtr hObject);
My method:
protected void UpdateQRSource(String address)
{
QRCodeWriter qrcode = new QRCodeWriter();
BarcodeWriter barcodeWriter = new BarcodeWriter
{
Format = BarcodeFormat.QR_CODE,
Options = new EncodingOptions
{
Width = 300,
Height = 300,
Margin = 4
}
};
using (Bitmap bitmap = barcodeWriter.Write(address))
{
IntPtr hbmp = bitmap.GetHbitmap();
try
{
BitmapSource source = Imaging.CreateBitmapSourceFromHBitmap(
hbmp,
IntPtr.Zero,
Int32Rect.Empty,
BitmapSizeOptions.FromEmptyOptions());
qrImage.Source = source; // set WPF image source
}
finally
{
DeleteObject(hbmp);
}
}
}
Please advise me how to add short text string or a custom image in the middle of the QR code - similar to the Wikipedia visual QR code below:
UPDATE:
Embedding custom logo in QR code (without breaking the latter!) seems to be not a trivial task as the scientific publication QR Images: Optimized Image Embedding in QR Codes shows...
But I still wonder if I could generate a QR code (as in the above source code), then overlay it with a custom text or logo, then validate the resulting image again by ZXing.Net.
Here we go (you can use any logo):
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;
using ZXing;
using ZXing.QrCode.Internal;
using ZXing.Rendering;
namespace Test
{
public partial class Form1 : Form
{
private string imagePath = #"YourPath";
private string url = #"https://en.WIKIPEDIA.ORG/";
private int size = 400;
public Form1()
{
InitializeComponent();
pictureBox1.Image = GenerateQR(size, size, url);
pictureBox1.Height = size;
pictureBox1.Width = size;
Console.WriteLine(checkQR(new Bitmap(pictureBox1.Image)));
}
public bool checkQR(Bitmap QrCode)
{
var reader = new BarcodeReader();
var result = reader.Decode(QrCode);
if (result == null)
return false;
return result.Text == url;
}
public Bitmap GenerateQR(int width, int height, string text)
{
var bw = new ZXing.BarcodeWriter();
var encOptions = new ZXing.Common.EncodingOptions
{
Width = width,
Height = height,
Margin = 0,
PureBarcode = false
};
encOptions.Hints.Add(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
bw.Renderer = new BitmapRenderer();
bw.Options = encOptions;
bw.Format = ZXing.BarcodeFormat.QR_CODE;
Bitmap bm = bw.Write(text);
Bitmap overlay = new Bitmap(imagePath);
int deltaHeigth = bm.Height - overlay.Height;
int deltaWidth = bm.Width - overlay.Width;
Graphics g = Graphics.FromImage(bm);
g.DrawImage(overlay, new Point(deltaWidth/2,deltaHeigth/2));
return bm;
}
}
The result:
And the output:
True
Since you get a bitmap out of ZXing you can use standard C# techniques to draw text. See this answer for more info:
c# write text on bitmap
For posterity here's some shamelessly copied code:
Bitmap bmp = //from ZXing;
RectangleF rectf = new RectangleF(70, 90, 90, 50);
Graphics g = Graphics.FromImage(bmp);
g.SmoothingMode = SmoothingMode.AntiAlias;
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.PixelOffsetMode = PixelOffsetMode.HighQuality;
g.DrawString("yourText", new Font("Tahoma",8), Brushes.Black, rectf);
g.Flush();
I'm having some troubles printing images and texts that have a 8 bit alpha channel.
It looks like most printer drivers will incorrectly render the alpha channel, adding some dithering patterns instead of blending the various layers.
For instance, the code at the end of this question produces something like this (notice the dithering in the left square): Virtual PDF printer - Laser printer
So far only the XPS virtual printer works fine.
What I've always done to avoid this is printing on an intermediate bitmap, but for a standard 11x8.5'' page at 1200 DPI it would take approx 400 MB of RAM just for storing this bitmap and I'm now wondering which is the correct way to print such objects.
Thanks
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Printing;
using System.Windows.Forms;
class Program
{
static void Main(string[] args)
{
PrintDocument printDoc = new PrintDocument();
printDoc.PrintPage += new PrintPageEventHandler(printDoc_PrintPage);
PrintDialog print = new PrintDialog();
print.Document = printDoc;
if (print.ShowDialog() == DialogResult.OK)
printDoc.Print();
}
static void printDoc_PrintPage(object sender, PrintPageEventArgs e)
{
//draw directly on the print graphics
e.Graphics.TranslateTransform(50, 50);
drawStuff(e.Graphics);
//draw on an intermediate bitmap
e.Graphics.ResetTransform();
using (Bitmap bmp = new Bitmap((int)e.Graphics.DpiX, (int)e.Graphics.DpiY))
{
bmp.SetResolution(e.Graphics.DpiX, e.Graphics.DpiY);
using (Graphics g = Graphics.FromImage(bmp))
{
g.ScaleTransform(e.Graphics.DpiX / 100, e.Graphics.DpiY / 100);
drawStuff(g);
}
e.Graphics.DrawImageUnscaled(bmp, new Point(175, 50));
}
}
private static void drawStuff(Graphics graphics)
{
Brush b1 = new SolidBrush(Color.LightGray);
Brush b2 = new SolidBrush(Color.FromArgb(50, Color.Black));
graphics.FillRectangle(b1, new Rectangle(0, 0, 100, 100));
graphics.FillRectangle(b2, new Rectangle(25, 25, 50, 50));
}
}
Could you use a library such as iTextSharp? The library has a bunch of different classes that will handle images and fonts.
here's my code. It correctly adds the pictures I want and everything works except that the images are using their native resolution, so if the image is big it's being cropped to fit the page.
Is there some way to have the picture use like a Zoom feature to stretch to fit, but also maintain the aspect ratio? There has to be something I'm missing there. :P
Here's a picture to illustrate the problem:
using System;
using System.IO;
using iTextSharp.text;
using iTextSharp.text.pdf;
using System.Drawing;
using System.Collections.Generic;
namespace WinformsPlayground
{
public class PDFWrapper
{
public void CreatePDF(List<System.Drawing.Image> images)
{
if (images.Count >= 1)
{
Document document = new Document(PageSize.LETTER);
try
{
// step 2:
// we create a writer that listens to the document
// and directs a PDF-stream to a file
PdfWriter.GetInstance(document, new FileStream("Chap0101.pdf", FileMode.Create));
// step 3: we open the document
document.Open();
foreach (var image in images)
{
iTextSharp.text.Image pic = iTextSharp.text.Image.GetInstance(image, System.Drawing.Imaging.ImageFormat.Jpeg);
document.Add(pic);
document.NewPage();
}
}
catch (DocumentException de)
{
Console.Error.WriteLine(de.Message);
}
catch (IOException ioe)
{
Console.Error.WriteLine(ioe.Message);
}
// step 5: we close the document
document.Close();
}
}
}
}
I solved it using the following:
foreach (var image in images)
{
iTextSharp.text.Image pic = iTextSharp.text.Image.GetInstance(image, System.Drawing.Imaging.ImageFormat.Jpeg);
if (pic.Height > pic.Width)
{
//Maximum height is 800 pixels.
float percentage = 0.0f;
percentage = 700 / pic.Height;
pic.ScalePercent(percentage * 100);
}
else
{
//Maximum width is 600 pixels.
float percentage = 0.0f;
percentage = 540 / pic.Width;
pic.ScalePercent(percentage * 100);
}
pic.Border = iTextSharp.text.Rectangle.BOX;
pic.BorderColor = iTextSharp.text.BaseColor.BLACK;
pic.BorderWidth = 3f;
document.Add(pic);
document.NewPage();
}
Personally, I use something close from fubo's solution and it works well:
image.ScaleToFit(document.PageSize);
image.SetAbsolutePosition(0,0);
You can try something like this:
Image logo = Image.GetInstance("pathToTheImage")
logo.ScaleAbsolute(500, 300)
image.ScaleToFit(500f,30f);
this method keeps the aspect ratio of the image
image.SetAbsolutePosition(1,1);