Edit multipage TIFF image using System.Drawing - c#

I'm tring to edit multipage tiff by creating Graphics from the image, but i encountered the error message: “A Graphics object cannot be created from an image that has an indexed pixel format.”
How can i edit multipage tiff?

I wrote something to extract single pages from a multipage tiff file.
// Load as Bitmap
using (Bitmap bmp = new Bitmap(file))
{
// Get pages in bitmap
int frames = bmp.GetFrameCount(System.Drawing.Imaging.FrameDimension.Page);
bmp.SelectActiveFrame(System.Drawing.Imaging.FrameDimension.Page, tiffpage);
if (bmp.PixelFormat != PixelFormat.Format1bppIndexed)
{
using (Bitmap bmp2 = new Bitmap(bmp.Width, bmp.Height))
{
bmp2.Palette = bmp.Palette;
bmp2.SetResolution(bmp.HorizontalResolution, bmp.VerticalResolution);
// create graphics object for new bitmap
using (Graphics g = Graphics.FromImage(bmp2))
{
// copy current page into new bitmap
g.DrawImageUnscaled(bmp, 0, 0);
// do whatever you migth to do
...
}
}
}
}
The snippet loads the tif file and extracts the one page (number in variable tiffpage) into a new bitmap. This is not indexed and an graphics object can be created.

The error : A Graphics object cannot be created from an image that has an indexed pixel format.
...has nothing to do with it being a multipage TIFF. An indexed image format means it has a palette of colours, e.g. it's a 256-colour image. A 1-bit image (B&W) would also count as having a palette of 2 colours.
You can't perform Graphics operations on images that use a palette, they'd need to be converted to 15-bit or more colour depth first.

Here is a link to a CodeProject sample that includes code for converting a TIFF file to a normal Bitmap, which you can then work with like any other Bitmap:
http://www.codeproject.com/KB/GDI-plus/BitonalImageConverter.aspx

I once wrote little utility to create encrypted pdfs from tiff images. Here is a piece of code to get pages from tiff image:
var bm= new System.Drawing.Bitmap('tif path');
var total = bm.GetFrameCount(System.Drawing.Imaging.FrameDimension.Page);
for(var x=0;x<total;x++)
{
bm.SelectActiveFrame(System.Drawing.Imaging.FrameDimension.Page,x);
var img=Image.GetInstance(bm,null,false);
//do what ever you want with img object
}

Related

Convert PNG to GIF or JPG

I am trying to convert png image to gif and jpg format. I am using the code that I've found at Microsoft documentation.
I've created git-hub example by modifying this code into this:
public static void Main(string[] args)
{
// Load the image.
using (Image png = Image.FromFile("test-image.png"))
{
var withBackground = SetWhiteBackground(png);
// Save the image in JPEG format.
withBackground.Save("test-image.jpg");
// Save the image in GIF format.
withBackground.Save("test-image.gif");
withBackground.Dispose();
}
}
private static Image SetWhiteBackground(Image img)
{
Bitmap imgWithBackground = new Bitmap(img.Width, img.Height);
Rectangle rect = new Rectangle(Point.Empty, img.Size);
using (Graphics g = Graphics.FromImage(imgWithBackground))
{
g.Clear(Color.White);
g.DrawImageUnscaledAndClipped(img, rect);
}
return imgWithBackground;
}
Original image (fictional data) is this:
And when I convert it to gif I get this:
So my question:
is there a way to get gif format out of png that would look the same?
Edit:
Hans Passant pointed out that the root problem was transparent background.
After some digging I found answer here.
I used code snipped mentioned in the link to set background to white:
private Image SetWhiteBackground(Image img)
{
Bitmap imgWithBackground = new Bitmap(img.Width, img.Height);
Rectangle rect = new Rectangle(Point.Empty, img.Size);
using (Graphics g = Graphics.FromImage(imgWithBackground))
{
g.Clear(Color.White);
g.DrawImageUnscaledAndClipped(img, rect);
}
return imgWithBackground;
}
So now the gif looks like this:
Something like (https://docs.sixlabors.com/articles/imagesharp/gettingstarted.html):
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Processing;
// Open the file and detect the file type and decode it.
// Our image is now in an uncompressed, file format agnostic, structure in-memory as a series of pixels.
using (Image image = Image.Load("test-image.png"))
{
// The library automatically picks an encoder based on the file extensions then encodes and write the data to disk.
image.Save("test.gif");
}

Dynamically generated Bitmap image with aligned data in it

I'm developing an Winforms application to be used for Led displays. The Led display is size 64x32. I created a test bitmap image with 4 cells size 64x16, so I can output it it to the LED display.
When the user enters 4 numbers in the input form, those Strings are then converted to Bitmap Image and placed inside the cells. I somehow got it to work with this method; It edits the same bitmap image, inserts the numbers, and saves it into a new bmp (or am I wrong?).
public static Bitmap Convert_Text_to_Image(string txt, string fontname, int fontsize)
{
//creating bitmap image
Bitmap bmp = new Bitmap("cells.bmp");
//FromImage method creates a new Graphics from the specified Image.
Graphics graphics = Graphics.FromImage(bmp);
// Create the Font object for the image text drawing.
Font font = new Font(fontname, fontsize);
// Instantiating object of Bitmap image again with the correct size for the text and font.
SizeF stringSize = graphics.MeasureString(txt, font);
bmp = new Bitmap(bmp, (int)stringSize.Width, (int)stringSize.Height);
graphics = Graphics.FromImage(bmp);
//Draw Specified text with specified format
graphics.DrawString(txt, font, Brushes.Red, 0, 0);
font.Dispose();
graphics.Flush();
graphics.Dispose();
bmp.Save("cells2.bmp", System.Drawing.Imaging.ImageFormat.Bmp);
return bmp; //return Bitmap Image
}
The output in the PictureBox is This
Now I've created myself multiple problems with the alignment, since I just pasted "bmp numbers" directly onto the "bmp cells"... is there a function of "mapping" the numbers correctly inside the cells, depending if its a single-digit or a two-digit number?
I'm pretty certain there's a way easier way to do all of this, maybe with the DataGridView? I only started using C#, any help would be appreciated.
The image "cells.bmp" is just a test image i created in Paint (xd), rather than that, I'm trying to write a function that will create the Bitmap cells through code
if (want_x_number_cells) {
//create bmp with appropriate number of cells
}

Unsupported Pixel Format of source or template image. AForge Imaging

I am getting the following Exception at ProcessImage(bitmap1, bitmap2);
Unsupported Pixel Format of source or template image
and this is my code:
public static double FindComparisonRatioBetweenImages(
System.Drawing.Image one, System.Drawing.Image two)
{
Bitmap bitmap1 = new Bitmap(one);
Bitmap bitmap2 = new Bitmap(two);
ExhaustiveTemplateMatching tm = new ExhaustiveTemplateMatching(0);
TemplateMatch[] matchings = null;
matchings = tm.ProcessImage(bitmap1, bitmap2); // Exception occurs here!
return matchings[0].Similarity;
}
I have also passed managedImage from the below code into the method, but it still gives error:
UnmanagedImage unmanagedImageA = UnmanagedImage.FromManagedImage(bitmap1);
Bitmap managedImageA = unmanagedImageA.ToManagedImage();
UnmanagedImage unmanagedImageB = UnmanagedImage.FromManagedImage(bitmap2);
Bitmap managedImageB = unmanagedImageB.ToManagedImage();
I have passed Images randomly from my computer, they all give exception.
I have passed Blank Image edited in paint into the method,it still give exception.
Also checked, jpeg, png, bmp formats, nothing work.
Try ExhaustiveTemplateMatching:
The class implements exhaustive template matching algorithm, which performs complete scan of source image, comparing each pixel with corresponding pixel of template.
The class processes only grayscale 8 bpp and color 24 bpp images.
So, those are the image formats you must use.
As requested, to convert to a specific pixel format, you can do this:
public static Bitmap ConvertToFormat(this Image image, PixelFormat format)
{
Bitmap copy = new Bitmap(image.Width, image.Height, format);
using (Graphics gr = Graphics.FromImage(copy))
{
gr.DrawImage(image, new Rectangle(0, 0, copy.Width, copy.Height));
}
return copy;
}
The one you would use is System.Drawing.Imaging.PixelFormat.Format24bppRgb.

Image manipulation - converting transparent pixels before saving as jpg

I'm saving a an image with a transparent background to jpeg.
Is there a way to convert the transparent pixels to a certain color without iterating on all the pixels?
This is the code I'm using (also - is the first line a common way to do it? are there different encoders?)
public void SaveImage(Bitmap image, string path)
{
var encoder = ImageCodecInfo.GetImageEncoders().FirstOrDefault(c => c.MimeType == "image/jpeg");
var encodeParams = new EncoderParameters(1);
encodeParams.Param[0] = new EncoderParameter(Encoder.Quality, (long)100);
image.Save(path, encoder, encodeParams);
}
image.MakeTransparent(image.GetPixel(0, 0));
But this can saved as png because sadly jpg doesn't support transparency
The usual solution is to make a bitmap image with your desired background color, render your image to it, and save/convert this bitmap as an image.
Check Graphics.FromImage. This will give you a Graphics rendering object for a bitmap.

Accurate BoundingBox on Microsoft ISF?

I have a set of Microsoft ISF (Ink Serialized Format) images, which I am attempting to convert to PNGs to include in a web page. I have successfully used the C# package Microsoft.Ink to draw the ink to a Bitmap and save as PNG:
byte[] data; // data has the raw bytes of the ISF file
Ink ink = new Ink();
Renderer renderer = new Renderer();
Stream outStream; // a Stream to hold the PNG data
ink.Load(data);
using (Strokes strokes = ink.Strokes) {
// get bounds of ISF
rect = strokes.GetBoundingBox(BoundingBoxMode.PointsOnly);
// create bitmap matching bounds
bm = new Bitmap(rect.Width, rect.Height);
// draw the ISF onto the Bitmap
using (Graphics g = Graphics.FromImage(bm)) {
g.Clear(Color.Transparent);
renderer.Draw(g, strokes);
}
}
// save the Bitmap to PNG format
bm.Save(outStream, System.Drawing.Imaging.ImageFormat.Png);
... however, the image dimensions seem to be abnormally large. Changing the BoundingBoxMode enum passed in to the GetBoundingBox method does not appear to change anything, and I'm getting images that are 465px × 660px and contain only a handwritten letter 'a' taking up maybe 25px × 30px in actual space.
Any suggestions on how to get a more accurate bounding box?
The bounding box rectangle is in "Inkspace" coordinates - create throwaway bitmap and graphics objects, then convert the rectangle using renderer.InkSpacetoPixel.
Add these lines between the GetBoundingBox call and the creation of the Bitmap bm, and the Bitmap should be sized correctly:
Bitmap bmTrash = new Bitmap(10, 10);
Graphics gTrash = Graphics.FromImage(bmTrash);
renderer.InkSpaceToPixel(gTrash, rect.Location);
renderer.InkSpaceToPixel(gTrash, rect.Size);

Categories

Resources