How to generate a image with text and images in C# - c#

I have several paragraphs of text and couple of pictures between these paragraphs.
Now, I want to generate a picture using these materials, merging them vertically. But all the blocks of the text and pictures can not have bigger width than that of the generating picture, which means I have to zoom out the origin pictures, and fill each paragraph of text into a rectangle to fit the width.
Here is the tough thing:
To figure out the size of the rectangle to contain the text, I need use Graphics.MeasureString() method, which needs an instance of Graphics used to generate my picture(now, I'm using a blank template picture). But I do not know the exact size of this Graphics until I figure out all the sizes of rectangles and pictures.
Is there any method to get an instance of Graphics without source image?
Or is there any other method to do this work?

hope this could help dude .
http://chiragrdarji.wordpress.com/2008/05/09/generate-image-from-text-using-c-or-convert-text-in-to-image-using-c/
https://web.archive.org/web/20131231000000/http://tech.pro/tutorial/654/csharp-snippet-tutorial-how-to-draw-text-on-an-image
http://www.codeproject.com/Questions/388845/HOW-TO-MAKE-HIGH-QAULITY-IMAGE-WITH-TEXT-IN-Csharp
thank you

For people how are intrested in a WPF solution (as asked):
public static BitmapSource CreateImage(string text, double width, double heigth)
{
// create WPF control
var size = new Size(width, heigth);
var stackPanel = new StackPanel();
var header = new TextBlock();
header.Text = "Header";
header.FontWeight = FontWeights.Bold;
var content = new TextBlock();
content.TextWrapping = TextWrapping.Wrap;
content.Text = text;
stackPanel.Children.Add(header);
stackPanel.Children.Add(content);
// process layouting
stackPanel.Measure(size);
stackPanel.Arrange(new Rect(size));
// Render control to an image
RenderTargetBitmap rtb = new RenderTargetBitmap((int)stackPanel.ActualWidth, (int)stackPanel.ActualHeight, 96, 96, PixelFormats.Pbgra32);
rtb.Render(stackPanel);
return rtb;
}

Related

Image is not drawn at the correct spot

Bitmap image = ReadBitmap("image.png");
Bitmap imageCopy = new Bitmap(image);
Bitmap canvas = new Bitmap(imageCopy.Width+100, imageCopy.Height);
// From this bitmap, the graphics can be obtained, because it has the right PixelFormat
using(Graphics g = Graphics.FromImage(canvas))
{
// Draw the original bitmap onto the graphics of the new bitmap
g.DrawImage(image, 0, 0);
}
// Use tempBitmap as you would have used originalBmp
InputPictureBox.Image = image;
OutputPictureBox.Image = canvas;
I haven't understood the output of this c# code.
The original image is not placed at the correct position. It should have been at (0, 0).
Also, I need a black background.
So, what is going on and how to correct this?
You are loading an Image, then a copy of this source is created using:
Bitmap bitmap = new Bitmap();
When you create a copy of an Image this way, you sacrifice/alter some details:
Dpi Resolution: if not otherwise specified, the resolution is set to the UI resolution. 96 Dpi, as a standard; it might be different with different screen resolutions and scaling. The System in use also affects this value (Windows 7 and Windows 10 will probably/possibly provide different values)
PixelFormat: If not directly copied from the Image source or explicitly specified, the PixelFormat is set to PixelFormat.Format32bppArgb.
From what you were saying, you probably wanted something like this:
var imageSource = Image.FromStream(new MemoryStream(File.ReadAllBytes(#"[SomeImageOfLena]"))), true, false)
var imageCopy = new Bitmap(imageSource.Width + 100, imageSource.Height, imageSource.PixelFormat))
imageCopy.SetResolution(imageSource.HorizontalResolution, imageSource.VerticalResolution);
using (var g = Graphics.FromImage(imageCopy)) {
g.Clear(Color.Black);
g.CompositingMode = CompositingMode.SourceCopy;
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.DrawImage(imageSource, (imageCopy.Width - imageSource.Width) / 2, 0);
pictureBox1.Image?.Dispose();
pictureBox2.Image?.Dispose();
pictureBox1.Image = imageSource;
pictureBox2.Image = imageCopy;
}
This is the result:
(The upper/lower frame black color is actually the Picturebox background color)
When the original Image Dpi Resolution is different from the base Dpi Resolution used when creating an Image copy with new Bitmap(), your results may be different from what is expected.
This is what happens with a source Image of 150, 96 and 72 Dpi in the same scenario:
Another important detail is the IDisposable nature of the Image object.
When you create one, you have to Dispose() of it; explicitly, calling the Dispose method, or implicitly, enclosing the Image contructor in a Using statement.
Also, possibly, don't assign an Image object directly loaded from a FileStream.
GDI+ will lock the file, and you will not be able to copy, move or delete it.
With the file, all resources tied to the Images will also be locked.
Make a copy with new Bitmap() (if you don't care of the above mentioned details), or with Image.Clone(), which will preserve the Image Dpi Resolution and PixelFormat.
I am not completely clear on what you are actually needing to do. But anyway, here is a WPF-friendly example of how to draw an image at a specific position inside another image.
Note if all you want to do is display the image in different size and/or put a black border around it, there are much simpler ways to do simply that, without having to create a second image, such as just laying out the image inside a panel that already has the border style you want.
Notice that I am using classes from the System.Windows.Media namespace because that is what WPF uses. These don't mix easily with the older classes from System.Drawing namespace (some of the class names conflict, and Microsoft's .Net framework lacks built-in methods for converting objects between those types), so normally one needs to simply decide whether to use one or the other sets of drawing tools. I assume you have been trying to use System.Drawing. Each has its own pros and cons that would take too long to explain here.
// using System.Windows.Media;
// using System.Windows.Media.Imaging;
private void DrawTwoImages()
{
// For InputPictureBox
var file = new Uri("C:\\image.png");
var inputImage = new BitmapImage(file);
// If your image is stored in a Resource Dictionary, instead use:
// var inputImage = (BitmapImage) Resources["image.png"];
InputPicture.Source = inputImage;
// imageCopy isn't actually needed for this example.
// But since you had it in yours, here is how it's done, anyway.
var imageCopy = inputImage.Clone();
// Parameters for setting up our output picture
int leftMargin = 50;
int topMargin = 5;
int rightMargin = 50;
int bottomMargin = 5;
int width = inputImage.PixelWidth + leftMargin + rightMargin;
int height = inputImage.PixelHeight + topMargin + bottomMargin;
var backgroundColor = Brushes.Black;
var borderColor = (Pen) null;
// Use a DrawingVisual and DrawingContext for drawing
DrawingVisual dv = new DrawingVisual();
using (DrawingContext dc = dv.RenderOpen())
{
// Draw the black background
dc.DrawRectangle(backgroundColor, borderColor, new Rect(0, 0, width, height));
// Copy input image onto output image at desired position
dc.DrawImage(inputImage, new Rect(leftMargin, topMargin,
inputImage.PixelWidth, inputImage.PixelHeight));
}
// For displaying output image
var rtb = new RenderTargetBitmap( width, height, 96, 96, PixelFormats.Pbgra32 );
rtb.Render(dv);
OutputPicture.Source = rtb;
}

datagridview inside of tabpage to bitmap

i have an dataGridView which is inside of an TabPage. Now i need to create an image of the dataGridView, but i looked online for solutions and i found DrawToBitmap but that only takes a part of the dataGridView.
This is the code i am using right now
bm = new Bitmap(this.dataGridView2.Width, this.dataGridView2.Height);
dataGridView2.DrawToBitmap(bm,new Rectangle(100,100, his.dataGridView1.Width, this.dataGridView1.Height));
e.Graphics.DrawImage(bm, 0, 0);
Here is an example how to fit a DataGridView onto a Bitmap, even if its content is larger than the DataGridView or the TabPage or even the Form.
The trick is to temporarily enlarge the DataGridView for the DrawToBitmap call so that all cells fit in and no scrollbars are there. Afterwards set it back to the original size that fits your layout..:
Size oldsize = dataGridView1.ClientSize;
var tw = dataGridView1.Columns.Cast<DataGridViewColumn>().Select(x => x.Width).Sum();
var th = dataGridView1.Rows.Cast<DataGridViewRow>().Select(x => x.Height).Sum();
dataGridView1.ClientSize = new Size(tw + dataGridView1.RowHeadersWidth,
th + dataGridView1.ColumnHeadersHeight);
Bitmap bmp = new Bitmap(dataGridView1.ClientSize.Width, dataGridView1.ClientSize.Height);
using (Graphics G = Graphics.FromImage(bmp))
dataGridView1.DrawToBitmap(bmp, dataGridView1.ClientRectangle);
bmp.Save(yourFilename, ImageFormat.Png);
dataGridView1.ClientSize = oldsize;
If you want padding around it you can simply make the Bitmap even larger still and write out the target rectangle's coordinates explicitly, instead of using the ClientRectangle..

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);
}
}

Text in drawn image is in wrong font (C#)

I'm trying to write a code that outputs a PNG image for a given block of text. I'm using System.Drawing to achieve this.
My problem is that the text in output image is in wrong font.
Here is the code of the function that I'm using in order to draw the output:
static Bitmap FromTextToPic(string text, Int16 size)
{
//create dummy Bitmap object
Bitmap bitmapImage = new Bitmap(2, 2);
//create dummy measurements
int imageWidth = 0;
int imageHeight = 0;
//naming font
font = "Lohit-Devanagari";
// Creates the Font object for the image text drawing.
System.Drawing.Font fontObject = new System.Drawing.Font(font, size, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Pixel);
// Creates a graphics object to measure the text's width and height.
Graphics graphicsObject = Graphics.FromImage(bitmapImage);
// This is where the bitmap size is determined.
imageWidth = (int)graphicsObject.MeasureString(text, fontObject).Width;
imageHeight = (int)graphicsObject.MeasureString(text, fontObject).Height;
// Creates the bmpImage again with the correct size for the text and font.
bitmapImage = new Bitmap(bitmapImage, new Size(imageWidth, imageHeight));
// Adds the colors to the new bitmap.
graphicsObject = Graphics.FromImage(bitmapImage);
// Sets Background color to white
graphicsObject.Clear(System.Drawing.Color.White);
//enables optimization for LCD screens
graphicsObject.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
//enables antialiasing
graphicsObject.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias;
//draws text to picture with black foreground color
graphicsObject.DrawString(text, fontObject, new SolidBrush(System.Drawing.Color.Black), 0, 0, StringFormat.GenericDefault);
graphicsObject.Flush();
return (bitmapImage);
}
Even when I'm specifying "Lohit-Devanagari" as the font, I always get the output in "Mangal" font (both are Devanagari fonts). So, what have I done wrong?
Also, the output stretches over to a long distance if there isn't a newline character in text (as in this picture). Is there a way to wrap up the output image to some fixed width?
Instead of this:
//naming font
font = "Lohit-Devanagari";
Try this:
//naming font
FontFamily font = new FontFamily("Lohit Devanagari");
The font name are probably without the "-" character.
If you declare a new object FontFamily, it will make an exception if the font does not exist.So you have to download and install it ...

Silverlight printing anti-aliasing

I'm trying to print an image (QR code) from Silverlight 4 app, however the image is antialised when printed (I have tried both XPS file printer and hardware printer)image is blury, and is not readable by barcode reader.
Image from printed XPS document http://img805.imageshack.us/img805/7677/qraliasing.png
I'm using this simple code to print it:
WriteableBitmap bitmap = new WriteableBitmap(width, height);
//write bitmap pixels
Image image = new Image(){Stretch = Stretch.None};
image.Source = bitmap;
image.Width = bitmap.PixelWidth;
image.Height = bitmap.PixelHeight;
//Print
PrintDocument printDocument = new PrintDocument();
printDocument.PrintPage += (sender, args) =>
{
args.PageVisual = image;
};
printDocument.Print("QrCode");
I have found a solution.
When printing Image control in Silverlight 4, it sends to printer not a "print screen" of an image control like it looks in your UserControl but an image set in it's source property. If you generate two bitmaps of 100x100 px and 1000x1000px resolutions and put them in 100x100px size Image controls the print result will not be the same as you may expect.
So the solution is to generate high resolution image (or upscale image) and put it in Image controls of desired size.
It seems you've come across a solution as I was typing mine, but I'll submit anyway...
The reason this happens is that the PrintDocument will essentially take the UIElement (your image), which it normally blits to a 96 DPI screen, and upscale it to 600 DPI suitable for printing. Since there's no way to tell this upscale operation how to handle smoothing, what you get is that ugly blurriness.
However, if you do the upscale blit yourself, then apply an opposite RenderTransform to the image, when the PrintDocument goes to scale up the image, your high-res blit will be the result.
Once you have your high-res blit of the QR code (essentially 600 / 96 = 6.25 times as large as normal), you apply a scale transform that sizes it back down by the exact same amount:
image.RenderTransform = new ScaleTransform {
ScaleX = 96.0 / 600.0,
ScaleY = 96.0 / 600.0
};
When you print this, you should see sharp edges.
Did you try changing the smoothing mode on the graphics object?
WriteableBitmap bitmap = new WriteableBitmap(width, height);
//write bitmap pixels
Image image = new Image(){Stretch = Stretch.None};
image.Source = bitmap;
image.Width = bitmap.PixelWidth;
image.Height = bitmap.PixelHeight;
//Print
PrintDocument printDocument = new PrintDocument();
printDocument.PrintPage += (sender, args) =>
{
//**Add this**
args.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.None;
args.PageVisual = image;
};
printDocument.Print("QrCode");

Categories