Convert TIFF to JPG format - c#

I have a TIFF file with two pages. When I convert the file to JPG format I lose the second page. Is there any way to put two images from a TIFF file into one JPG file?
Because TIFF files are too big, I have to decrease their sizes. Is there any way to decrease TIFF size programmatically? That could also help solve my problem.

Since a TIFF can contain multiple frames but JPG can't, you need to convert each single frame into a JPG.
Taken from Windows Dev Center Samples:
public static string[] ConvertTiffToJpeg(string fileName)
{
using (Image imageFile = Image.FromFile(fileName))
{
FrameDimension frameDimensions = new FrameDimension(
imageFile.FrameDimensionsList[0]);
// Gets the number of pages from the tiff image (if multipage)
int frameNum = imageFile.GetFrameCount(frameDimensions);
string[] jpegPaths = new string[frameNum];
for (int frame = 0; frame < frameNum; frame++)
{
// Selects one frame at a time and save as jpeg.
imageFile.SelectActiveFrame(frameDimensions, frame);
using (Bitmap bmp = new Bitmap(imageFile))
{
jpegPaths[frame] = String.Format("{0}\\{1}{2}.jpg",
Path.GetDirectoryName(fileName),
Path.GetFileNameWithoutExtension(fileName),
frame);
bmp.Save(jpegPaths[frame], ImageFormat.Jpeg);
}
}
return jpegPaths;
}
}

using System.Drawing;
using System.Drawing.Imaging;
Bitmap bm=Bitmap.FromFile("photo.tif");
bm.Save("photo.jpg",ImageFormat.Jpeg);

public static class ConvertTiffToJpeg
{
static string base64String = null;
public static string ImageToBase64(string tifpath)
{
string path = tifpath;
using (System.Drawing.Image image = System.Drawing.Image.FromFile(path))
{
using (MemoryStream m = new MemoryStream())
{
image.Save(m, ImageFormat.Jpeg);
byte[] imageBytes = m.ToArray();
base64String = Convert.ToBase64String(imageBytes);
return base64String;
}
}
}
}
< img src="data:image/jpeg;base64, #ConvertTiffToJpeg.ImageToBase64(#"c:\sample.tif")"/>
c# .net tiff-to-jpeg tiff

We faced some problems when converting TIF files to JPEG, because TIF format supports some types of compressions that are not supported in free toolkits.
I searched the internet and tried some commercial toolkits, but most of them are hard to implement with many limitations. The toolkit that drew my attention is leadtools, because it supports loading and saving many file formats (including TIF images with different compressions). We used this toolkit convert our images to JPEG format. You can find more information in the following page:
http://support.leadtools.com/CS/forums/8925/ShowPost.aspx
Note that you can convert any VB.Net code to C# by using this free code converter:
http://www.developerfusion.com/tools/convert/vb-to-csharp/

Related

Get an error writing Linear DNG via Libtiff .NET

I am trying to create a linear DNG file based on JPG using Lossy JPEG (34892) compression (which was introduced in DNG 1.4.0.0). After running the method below I got an error "Error: File format is invalid (JPEG dimensions do not match tile)" from dng_validate.exe.
It would be nice if someone can resolve it by adjusting my code. Also, I will be happy for a tutorial link. Using of image tools (magick, dcraw, exiftool) also could be a solution.
public static void LinearRawDng()
{
string file = "eva.jpg";
using (Tiff tif = Tiff.Open("eva-linear.dng", "w"))
{
Image img = Image.FromFile(file);
byte[] raster;
using (MemoryStream ms = new MemoryStream())
{
img.Save(ms, ImageFormat.Jpeg);
raster = ms.ToArray();
}
tif.SetField(TiffTag.MAKE, "Fitler");
tif.SetField(TiffTag.UNIQUECAMERAMODEL, "Fitler");
tif.SetField(TiffTag.DNGVERSION, "\x1\x4\x0\x0");
tif.SetField(TiffTag.DNGBACKWARDVERSION, "\x1\x4\x0\x0");
tif.SetField(TiffTag.SUBFILETYPE, 0);
tif.SetField(TiffTag.PHOTOMETRIC, 34892);
tif.SetField(TiffTag.COMPRESSION, 34892);
tif.SetField(TiffTag.SAMPLESPERPIXEL, 1);
tif.SetField(TiffTag.BITSPERSAMPLE, 8);
tif.SetField(TiffTag.ORIENTATION, Orientation.TOPLEFT);
tif.SetField(TiffTag.PLANARCONFIG, PlanarConfig.CONTIG);
tif.SetField(TiffTag.IMAGEWIDTH, img.Width);
tif.SetField(TiffTag.IMAGELENGTH, img.Height);
var result = tif.WriteRawStrip(0, raster, raster.Length);
tif.Close();
Console.WriteLine("Finished");
}
}

how do i know my byte array containing blank .tif file or not

i have a application where i need to check my scanner generates blank tif file or not.
here i share my example code
private void button1_Click(object sender, EventArgs e)
{
string path2 = #"F:\3333.tif";
string path = #"F:\Document Scanned # 1-blank.tif";
System.Drawing.Image img = System.Drawing.Image.FromFile(path);
byte[] bytes;
using (MemoryStream ms = new MemoryStream())
{
img.Save(ms, System.Drawing.Imaging.ImageFormat.Tiff);
bytes = ms.ToArray();
}
System.Drawing.Image img2 = System.Drawing.Image.FromFile(path2);
byte[] bytes2;
using (MemoryStream ms3 = new MemoryStream())
{
img2.Save(ms3, System.Drawing.Imaging.ImageFormat.Tiff);
bytes2 = ms3.ToArray();
}
bool t = false;
t = bytes.SequenceEqual(bytes2);
}
Note: Blank tif image meance white page .
In above bool t always returns true why ? i used two diff images solved
Essentially, you are comparing the bytes of two TIF files (with the indirection of using Image). This can fail for various reasons:
Dimension: If the two images do not have the exact same height and width, the byte sequences will -of course- be different even if both are completely white.
Metadata: As far as I know, the TIF format contains various metadata. Therefore, two files may be different even if they have the same pixels. I would recommend manually checking all pixel values (e.g. Bitmap.GetPixel) and comparing them to white (Color.FromArgb(255,255,255,255)).
Noise: Are you sure that a blank file is always pure white (255,255,255)? Maybe some random pixels have slightly different values such as (255,254,255)...

System.Drawing.Image.RotateFlip(RotateFlipType)

I have the following code to rotate an image in C#:
using (var stream = new FileStream(path, FileMode.Open))
{
using (var image = Image.FromStream(stream))
{
stream.Close();
image.RotateFlip(rotateType);
image.Save(path1, ImageFormat.Png);
image.Dispose();
}
}
If the original file size was 700 KiB, the new rotated file has size of 7+ MiB.
What is wrong with this code? Any help is much appreciated.
Update:
I tried changing the line image.Save(path1, ImageFormat.Png) to image.Save(path1) and image.Save(path1, image.RawFormt) with no improvement.
C# - How to change PNG quality or color depth
This guy's question looks similar to the same thing you are seeing.
PNG is a bitmap file format:
higher filesize compared to jpg
Because of this you should safe your image as jpg:
Thus lossless PNG format is best suited for pictures still under edition - and the lossy formats, like JPEG, are best for the final distribution of photographic images, because in this case JPG files are usually smaller [...]
Source: wikipedia
Try safing the image in JPEG via:
image.Save(path, YourClass.GetImageFormat(image));
Tests:
Rotating an JPG file with this method and the size stays the same.
Rotating a 15.7MiB BMP file, the new size is ~800kiB.
To use the existing file format, use this extension method:
public static System.Drawing.Imaging.ImageFormat GetImageFormat(System.Drawing.Image img)
{
if (img.RawFormat.Equals(System.Drawing.Imaging.ImageFormat.Jpeg))
return System.Drawing.Imaging.ImageFormat.Jpeg;
if (img.RawFormat.Equals(System.Drawing.Imaging.ImageFormat.Bmp))
return System.Drawing.Imaging.ImageFormat.Bmp;
if (img.RawFormat.Equals(System.Drawing.Imaging.ImageFormat.Png))
return System.Drawing.Imaging.ImageFormat.Png;
if (img.RawFormat.Equals(System.Drawing.Imaging.ImageFormat.Emf))
return System.Drawing.Imaging.ImageFormat.Emf;
if (img.RawFormat.Equals(System.Drawing.Imaging.ImageFormat.Exif))
return System.Drawing.Imaging.ImageFormat.Exif;
if (img.RawFormat.Equals(System.Drawing.Imaging.ImageFormat.Gif))
return System.Drawing.Imaging.ImageFormat.Gif;
if (img.RawFormat.Equals(System.Drawing.Imaging.ImageFormat.Icon))
return System.Drawing.Imaging.ImageFormat.Icon;
if (img.RawFormat.Equals(System.Drawing.Imaging.ImageFormat.MemoryBmp))
return System.Drawing.Imaging.ImageFormat.MemoryBmp;
if (img.RawFormat.Equals(System.Drawing.Imaging.ImageFormat.Tiff))
return System.Drawing.Imaging.ImageFormat.Tiff;
else
return System.Drawing.Imaging.ImageFormat.Wmf;
}
Source: StackOverflow
Remember you have to look for the format before you manipulate the image.
Otherwise the image will be recognised as MemoryBmp.
using (var stream = new FileStream(path, FileMode.Open))
{
using (var image = Image.FromStream(stream))
{
stream.Close();
var format = YourClass.GetImageFormat(image);
image.RotateFlip(RotateFlipType.Rotate180FlipNone);
image.Save(path, format);
image.Dispose();
}
}

PDF Compression with iTextSharp [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 5 years ago.
Improve this question
I am currently trying to recompress a pdf that has already been created, I am trying to find a way to recompress the images that are in the document, to reduce the file size.
I have been trying to do this with the DataLogics PDE and iTextSharp libraries but I can not find a way to do the stream recompression of the items.
I have though about looping over the xobjects and getting the images and then dropping the DPI down to 96 or using the libjpeg C# implimentation to change the quality of the image but getting it back into the pdf stream seems to always end up, with memory corruption or some other issue.
Any samples will be appreciated.
Thanks
iText and iTextSharp have some methods for replacing indirect objects. Specifically there's PdfReader.KillIndirect() which does what it says and PdfWriter.AddDirectImageSimple(iTextSharp.text.Image, PRIndirectReference) which you can then use to replace what you killed off.
In pseudo C# code you'd do:
var oldImage = PdfReader.GetPdfObject();
var newImage = YourImageCompressionFunction(oldImage);
PdfReader.KillIndirect(oldImage);
yourPdfWriter.AddDirectImageSimple(newImage, (PRIndirectReference)oldImage);
Converting the raw bytes to a .Net image can be tricky, I'll leave that up to you or you can search here. Mark has a good description here. Also, technically PDFs don't have a concept of DPI, that's for printers mostly. See the answer here for more on that.
Using the method above your compression algorithm can actually do two things, physically shrink the image as well as apply JPEG compression. When you physically shrink the image and add it back it will occupy the same amount of space as the original image but with less pixels to work with. This will get you what you consider to be DPI reduction. The JPEG compression speaks for itself.
Below is a full working C# 2010 WinForms app targeting iTextSharp 5.1.1.0. It takes an existing JPEG on your desktop called "LargeImage.jpg" and creates a new PDF from it. Then it opens the PDF, extracts the image, physically shrinks it to 90% of the original size, applies 85% JPEG compression and writes it back to the PDF. See the comments in the code for more of an explanation. The code needs lots more null/error checking. Also looks for NOTE comments where you'll need to expand to handle other situations.
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
using System.IO;
using iTextSharp.text;
using iTextSharp.text.pdf;
namespace WindowsFormsApplication1 {
public partial class Form1 : Form {
public Form1() {
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e) {
//Our working folder
string workingFolder = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
//Large image to add to sample PDF
string largeImage = Path.Combine(workingFolder, "LargeImage.jpg");
//Name of large PDF to create
string largePDF = Path.Combine(workingFolder, "Large.pdf");
//Name of compressed PDF to create
string smallPDF = Path.Combine(workingFolder, "Small.pdf");
//Create a sample PDF containing our large image, for demo purposes only, nothing special here
using (FileStream fs = new FileStream(largePDF, FileMode.Create, FileAccess.Write, FileShare.None)) {
using (Document doc = new Document()) {
using (PdfWriter writer = PdfWriter.GetInstance(doc, fs)) {
doc.Open();
iTextSharp.text.Image importImage = iTextSharp.text.Image.GetInstance(largeImage);
doc.SetPageSize(new iTextSharp.text.Rectangle(0, 0, importImage.Width, importImage.Height));
doc.SetMargins(0, 0, 0, 0);
doc.NewPage();
doc.Add(importImage);
doc.Close();
}
}
}
//Now we're going to open the above PDF and compress things
//Bind a reader to our large PDF
PdfReader reader = new PdfReader(largePDF);
//Create our output PDF
using (FileStream fs = new FileStream(smallPDF, FileMode.Create, FileAccess.Write, FileShare.None)) {
//Bind a stamper to the file and our reader
using (PdfStamper stamper = new PdfStamper(reader, fs)) {
//NOTE: This code only deals with page 1, you'd want to loop more for your code
//Get page 1
PdfDictionary page = reader.GetPageN(1);
//Get the xobject structure
PdfDictionary resources = (PdfDictionary)PdfReader.GetPdfObject(page.Get(PdfName.RESOURCES));
PdfDictionary xobject = (PdfDictionary)PdfReader.GetPdfObject(resources.Get(PdfName.XOBJECT));
if (xobject != null) {
PdfObject obj;
//Loop through each key
foreach (PdfName name in xobject.Keys) {
obj = xobject.Get(name);
if (obj.IsIndirect()) {
//Get the current key as a PDF object
PdfDictionary imgObject = (PdfDictionary)PdfReader.GetPdfObject(obj);
//See if its an image
if (imgObject.Get(PdfName.SUBTYPE).Equals(PdfName.IMAGE)) {
//NOTE: There's a bunch of different types of filters, I'm only handing the simplest one here which is basically raw JPG, you'll have to research others
if (imgObject.Get(PdfName.FILTER).Equals(PdfName.DCTDECODE)) {
//Get the raw bytes of the current image
byte[] oldBytes = PdfReader.GetStreamBytesRaw((PRStream)imgObject);
//Will hold bytes of the compressed image later
byte[] newBytes;
//Wrap a stream around our original image
using (MemoryStream sourceMS = new MemoryStream(oldBytes)) {
//Convert the bytes into a .Net image
using (System.Drawing.Image oldImage = Bitmap.FromStream(sourceMS)) {
//Shrink the image to 90% of the original
using (System.Drawing.Image newImage = ShrinkImage(oldImage, 0.9f)) {
//Convert the image to bytes using JPG at 85%
newBytes = ConvertImageToBytes(newImage, 85);
}
}
}
//Create a new iTextSharp image from our bytes
iTextSharp.text.Image compressedImage = iTextSharp.text.Image.GetInstance(newBytes);
//Kill off the old image
PdfReader.KillIndirect(obj);
//Add our image in its place
stamper.Writer.AddDirectImageSimple(compressedImage, (PRIndirectReference)obj);
}
}
}
}
}
}
}
this.Close();
}
//Standard image save code from MSDN, returns a byte array
private static byte[] ConvertImageToBytes(System.Drawing.Image image, long compressionLevel) {
if (compressionLevel < 0) {
compressionLevel = 0;
} else if (compressionLevel > 100) {
compressionLevel = 100;
}
ImageCodecInfo jgpEncoder = GetEncoder(ImageFormat.Jpeg);
System.Drawing.Imaging.Encoder myEncoder = System.Drawing.Imaging.Encoder.Quality;
EncoderParameters myEncoderParameters = new EncoderParameters(1);
EncoderParameter myEncoderParameter = new EncoderParameter(myEncoder, compressionLevel);
myEncoderParameters.Param[0] = myEncoderParameter;
using (MemoryStream ms = new MemoryStream()) {
image.Save(ms, jgpEncoder, myEncoderParameters);
return ms.ToArray();
}
}
//standard code from MSDN
private static ImageCodecInfo GetEncoder(ImageFormat format) {
ImageCodecInfo[] codecs = ImageCodecInfo.GetImageDecoders();
foreach (ImageCodecInfo codec in codecs) {
if (codec.FormatID == format.Guid) {
return codec;
}
}
return null;
}
//Standard high quality thumbnail generation from http://weblogs.asp.net/gunnarpeipman/archive/2009/04/02/resizing-images-without-loss-of-quality.aspx
private static System.Drawing.Image ShrinkImage(System.Drawing.Image sourceImage, float scaleFactor) {
int newWidth = Convert.ToInt32(sourceImage.Width * scaleFactor);
int newHeight = Convert.ToInt32(sourceImage.Height * scaleFactor);
var thumbnailBitmap = new Bitmap(newWidth, newHeight);
using (Graphics g = Graphics.FromImage(thumbnailBitmap)) {
g.CompositingQuality = CompositingQuality.HighQuality;
g.SmoothingMode = SmoothingMode.HighQuality;
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
System.Drawing.Rectangle imageRectangle = new System.Drawing.Rectangle(0, 0, newWidth, newHeight);
g.DrawImage(sourceImage, imageRectangle);
}
return thumbnailBitmap;
}
}
}
I don't know about iTextSharp, but you have to rewrite a PDF file if anything is changed, as it contains an xref table (index) with the exact file position of each object. This means if even one byte is added or removed, the PDF becomes corrupted.
Your best bet for recompressing the images is JBIG2 if they are B&W, or JPEG2000 otherwise, for which Jasper library will happily encode JPEG2000 codestreams for placement into PDF files at whatever quality you so desire.
If it were me I'd do it all from code without the PDF libraries. Just find all images (anything between stream and endstream after an occurance of JPXDecode (JPEG2000), JBIG2Decode (JBIG2) or DCTDecode (JPEG)) pull that out, reencode it with Jasper, then stick it back in again and update the xref table.
To update the xref table, find the positions of each object (starting 00001 0 obj) and just update the new positions in the xref table. It's not too much work, less than it sounds. You might be able to get all the offsets with a single regular expression (I'm not a C# programmer, but in PHP it would be that simple.)
Then finally update the value of the startxref tag in the trailer with the offset of the beginning of the xref table (where it says xref in the file).
Otherwise you'll end up decoding the entire PDF and rewriting it all, which will be slow, and you might lose something along the way.
There is an example on how to find and replace images in an existing PDF by the creator of iText. It's actually a small excerpt from his book. Since it's in Java, here's a simple replacement:
public void ReduceResolution(PdfReader reader, long quality) {
int n = reader.XrefSize;
for (int i = 0; i < n; i++) {
PdfObject obj = reader.GetPdfObject(i);
if (obj == null || !obj.IsStream()) {continue;}
PdfDictionary dict = (PdfDictionary)PdfReader.GetPdfObject(obj);
PdfName subType = (PdfName)PdfReader.GetPdfObject(
dict.Get(PdfName.SUBTYPE)
);
if (!PdfName.IMAGE.Equals(subType)) {continue;}
PRStream stream = (PRStream )obj;
try {
PdfImageObject image = new PdfImageObject(stream);
PdfName filter = (PdfName) image.Get(PdfName.FILTER);
if (
PdfName.JBIG2DECODE.Equals(filter)
|| PdfName.JPXDECODE.Equals(filter)
|| PdfName.CCITTFAXDECODE.Equals(filter)
|| PdfName.FLATEDECODE.Equals(filter)
) continue;
System.Drawing.Image img = image.GetDrawingImage();
if (img == null) continue;
var ll = image.GetImageBytesType();
int width = img.Width;
int height = img.Height;
using (System.Drawing.Bitmap dotnetImg =
new System.Drawing.Bitmap(img))
{
// set codec to jpeg type => jpeg index codec is "1"
System.Drawing.Imaging.ImageCodecInfo codec =
System.Drawing.Imaging.ImageCodecInfo.GetImageEncoders()[1];
// set parameters for image quality
System.Drawing.Imaging.EncoderParameters eParams =
new System.Drawing.Imaging.EncoderParameters(1);
eParams.Param[0] =
new System.Drawing.Imaging.EncoderParameter(
System.Drawing.Imaging.Encoder.Quality, quality
);
using (MemoryStream msImg = new MemoryStream()) {
dotnetImg.Save(msImg, codec, eParams);
msImg.Position = 0;
stream.SetData(msImg.ToArray());
stream.SetData(
msImg.ToArray(), false, PRStream.BEST_COMPRESSION
);
stream.Put(PdfName.TYPE, PdfName.XOBJECT);
stream.Put(PdfName.SUBTYPE, PdfName.IMAGE);
stream.Put(PdfName.FILTER, filter);
stream.Put(PdfName.FILTER, PdfName.DCTDECODE);
stream.Put(PdfName.WIDTH, new PdfNumber(width));
stream.Put(PdfName.HEIGHT, new PdfNumber(height));
stream.Put(PdfName.BITSPERCOMPONENT, new PdfNumber(8));
stream.Put(PdfName.COLORSPACE, PdfName.DEVICERGB);
}
}
}
catch {
// throw;
// iText[Sharp] can't handle all image types...
}
finally {
// may or may not help
reader.RemoveUnusedObjects();
}
}
}
You'll notice it's only handling JPEG. The logic is reversed (instead of explicitly handling only DCTDECODE/JPEG) so you can uncomment some of the ignored image types and experiment with the PdfImageObject in the code above. In particular, most of the FLATEDECODE images (.bmp, .png, and .gif) are represented as PNG (confirmed in the DecodeImageBytes method of the PdfImageObject source code). As far as I know, .NET does not support PNG encoding. There are some references to support this here and here. You can try a stand-alone PNG optimization executable, but you also have to figure out how to set PdfName.BITSPERCOMPONENT and PdfName.COLORSPACE in the PRStream.
For completeness sake, since your question specifically asks about PDF compression, here's how you compress a PDF with iTextSharp:
PdfStamper stamper = new PdfStamper(
reader, YOUR-STREAM, PdfWriter.VERSION_1_5
);
stamper.Writer.CompressionLevel = 9;
int total = reader.NumberOfPages + 1;
for (int i = 1; i < total; i++) {
reader.SetPageContent(i, reader.GetPageContent(i));
}
stamper.SetFullCompression();
stamper.Close();
You might also try and run the PDF through PdfSmartCopy to get the file size down. It removes redundant resources, but like the call to RemoveUnusedObjects() in the finally block, it may or may not help. That will depend on how the PDF was created.
IIRC iText[Sharp] doesn't deal well with JBIG2DECODE, so #Alasdair's suggestion looks good - if you want to take the time learning the Jasper library and using the brute-force approach.
Good luck.
EDIT - 2012-08-17, comment by #Craig:
To save the PDF after compressing the jpegs using the ReduceResolution() method above:
a. Instantiate a PdfReader object:
PdfReader reader = new PdfReader(pdf);
b. Pass the PdfReader to the ReduceResolution() method above.
c. Pass the altered PdfReader to a PdfStamper. Here's one way using a MemoryStream:
// Save altered PDF. then you can pass the btye array to a database, etc
using (MemoryStream ms = new MemoryStream()) {
using (PdfStamper stamper = new PdfStamper(reader, ms)) {
}
return ms.ToArray();
}
Or you can use any other Stream if you don't need to keep the PDF in memory. E.g. use a FileStream and save directly to disk.
I've written a library to do just that. It will also OCR the pdf's using Tesseract or Cuneiform and create searchable, compressed PDF files. It's a library that uses several open source projects (iTextsharp, jbig2 encoder, Aforge, muPDF#) to complete the task. You can check it out here http://hocrtopdf.codeplex.com/
I am not sure if you are considering other libraries, but you can easily recompress existing images using Docotic.Pdf library (Disclaimer: I work for the company).
Here is some sample code:
static void RecompressExistingImages(string fileName, string outputName)
{
using (PdfDocument doc = new PdfDocument(fileName))
{
foreach (PdfImage image in doc.Images)
image.RecompressWithGroup4Fax();
doc.Save(outputName);
}
}
There are also RecompressWithFlate, RecompressWithGroup3Fax, RecompressWithJpeg and Uncompress methods.
The library will convert color images to bilevel ones if needed. You can specify deflate compression level, JPEG quality etc.
I am also ask you to think twice before using approach suggested by #Alasdair. If you are going to deal with PDF files that weren't created by you than the task is far more complex that it might seem.
To start with, there is great deal of images compressed by codecs other than JPXDecode, JBIG2Decode or DCTDecode. And PDF can also contain inline images.
PDF files saved using newer versions of standard (1.5 or newer) can contain cross-reference streams. It means that reading and updating such files is more complex than just finding/updating some numbers at the end of the file.
So, please, use a PDF library.
A simple way to compress PDF is using gsdll32.dll (Ghostscript) and Cyotek.GhostScript.dll (wrapper):
public static void CompressPDF(string sInFile, string sOutFile, int iResolution)
{
string[] arg = new string[]
{
"-sDEVICE=pdfwrite",
"-dNOPAUSE",
"-dSAFER",
"-dBATCH",
"-dCompatibilityLevel=1.5",
"-dDownsampleColorImages=true",
"-dDownsampleGrayImages=true",
"-dDownsampleMonoImages=true",
"-sPAPERSIZE=a4",
"-dPDFFitPage",
"-dDOINTERPOLATE",
"-dColorImageDownsampleThreshold=1.0",
"-dGrayImageDownsampleThreshold=1.0",
"-dMonoImageDownsampleThreshold=1.0",
"-dColorImageResolution=" + iResolution.ToString(),
"-dGrayImageResolution=" + iResolution.ToString(),
"-dMonoImageResolution=" + iResolution.ToString(),
"-sOutputFile=" + sOutFile,
sInFile
};
using(GhostScriptAPI api = new GhostScriptAPI())
{
api.Execute(arg);
}
}

Resize image while preserving mimetype using .Net

I am loading images from a database and want to dynamically resize them according to some input.
Code is something like this:
public ActionResult GetImage(string imageID, int? width, int? height, bool constrain)
{
ValidateImageInput(width, height, constrain);
ImageWithMimeType info = LoadFromDatabase(imageID);
if(info == null)
throw new HttpException(404, "Image with that name or id was not found.");
Resize(info.Bytedata, width, height, constrain, info.MimeType);
return File(info.Data, info.MimeType);
}
How would I implement Resize in a way that preserves encoding type etc? I've looked at Image resizing efficiency in C# and .NET 3.5 but don't see how it would preserve encoding - since creating a new Bitmap surely isn't encoded?
Fact is, I managed to solve it with some help of google eventually. Guess I was a bit too trigger happy with the question. Anyway, the basic bits is that I look up the proper ImageFormat from the mimetype using ImageCodecInfo.GetImageEncoders(), then save using the correct encoding, as following:
private ImageFormat GetEncoderInfo(string mimeType)
{
// Get image codecs for all image formats
ImageCodecInfo[] codecs = ImageCodecInfo.GetImageEncoders();
// Find the correct image codec
for (int i = 0; i < codecs.Length; i++)
if (codecs[i].MimeType == mimeType)
return new ImageFormat(codecs[i].FormatID);
return null;
}
This is a slightly different version I made of the code on http://www.switchonthecode.com/tutorials/csharp-tutorial-image-editing-saving-cropping-and-resizing
Using the ImageFormat I can simply do
image.Save(dest, GetEncoderInfo(mimetype));
To preserve the filetype you have to look at that filetype the original file has and when saving the file you specify the file format.
Bitmap b = new Bitmap("foo.jpg");
b.Save("bar.jpg", System.Drawing.Imaging.ImageFormat.Jpeg);
In your case you would probably save to an MemoryStream that you later convert to the byte array (guessing that your info.Data is of type byte[]).

Categories

Resources