28

I would like to convert from an image (like jpg or png) to PDF.

I've checked out ImageMagickNET, but it is far too complex for my needs.

What other .NET solutions or code are there for converting an image to a PDF?

p.campbell
  • 98,673
  • 67
  • 256
  • 322
Coppermill
  • 6,676
  • 14
  • 67
  • 92
  • There is also http://www.graphicsmagick.org/ which is an improved version og ImageMagick (code-wise). I don't know if you'll find .NET libraries for it, though. – csl Oct 29 '09 at 08:30
  • Is it for a desktop/server/web application? – o.k.w Oct 29 '09 at 08:32
  • It's a web application, however that does not make any difference to the type of application as the coding will be the same – Coppermill Oct 30 '09 at 09:38

11 Answers11

36

Easy with iTextSharp:

class Program
{
    static void Main(string[] args)
    {
        Document document = new Document();
        using (var stream = new FileStream("test.pdf", FileMode.Create, FileAccess.Write, FileShare.None))
        {
            PdfWriter.GetInstance(document, stream);
            document.Open();
            using (var imageStream = new FileStream("test.jpg", FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
            {
                var image = Image.GetInstance(imageStream);
                document.Add(image);
            }
            document.Close();
        }
    }
}
Darin Dimitrov
  • 1,023,142
  • 271
  • 3,287
  • 2,928
  • Nice, +1 for the tidying too. As a matter of interest (I havent used it in ages), is there a cleaner way to use Document w/ IDisposable and/or should there be a try/finally guarding the Close? Presumably not if imageStream is the actual resource holder/owner? – Ruben Bartelink Oct 29 '09 at 09:54
  • I'm getting "PdfWriter does not exist in current context" – Ladessa Jan 14 '13 at 15:04
  • 3
    How to add image width and height in pdf? – Vishal Kiri Dec 09 '15 at 14:20
  • The following seems to work as far as scaling down large images without distorting their dimensions: float maxWidth = document.PageSize.Width - document.LeftMargin - document.RightMargin; float maxHeight = document.PageSize.Height - document.TopMargin - document.BottomMargin; if (image.Height > maxHeight || image.Width > maxWidth) image.ScaleToFit(maxWidth, maxHeight); – user1566694 May 05 '17 at 18:01
19

iTextSharp does it pretty cleanly and is open source. Also, it has a very good accompanying book by the author which I recommend if you end up doing more interesting things like managing forms. For normal usage, there are plenty resources on mailing lists and newsgroups for samples of how to do common things.

EDIT: as alluded to in @Chirag's comment, @Darin's answer has code that definitely compiles with current versions.

Example usage:

public static void ImagesToPdf(string[] imagepaths, string pdfpath)
{
    using(var doc = new iTextSharp.text.Document())
    {
        iTextSharp.text.pdf.PdfWriter.GetInstance(doc, new FileStream(pdfpath, FileMode.Create));
        doc.Open();
        foreach (var item in imagepaths)
        {
            iTextSharp.text.Image image = iTextSharp.text.Image.GetInstance(item);
            doc.Add(image);
        }
    }
}

Community
  • 1
  • 1
Ruben Bartelink
  • 59,778
  • 26
  • 187
  • 249
  • 10
    iTextSharp is open source, but not free. You will have to either pay the license fee or make your own code open source because of the AGPL license they're using. See for yourself here : http://itextpdf.com/terms-of-use/index.php –  Oct 05 '12 at 18:00
  • getting error Error 2 'iTextSharp.text.Document': type used in a using statement must be implicitly convertible to 'System.IDisposable' – Chirag Oct 10 '15 at 07:29
  • @Chirag I have no recollection of whether I actually compiled the code at the time or whether the likelihood is that you're using another version (here is [an example of similar code](http://stackoverflow.com/questions/28923080/itextsharp-can-not-convert-all-html-to-pdf) to confirm it made sense at some point). However in general if it is not Disposable, it should be safe to omit the `using`. Hang on, have a look at [@Darin's answer](http://stackoverflow.com/a/1642301/11635). Thanks for pointing to the Emperor's clothes :) – Ruben Bartelink Oct 10 '15 at 08:01
  • I have already check that code also, there is one problem "The process cannot access the file "test.jpg" because it is being used by another process." – Chirag Oct 10 '15 at 08:41
  • @Chirag It's not unlikely such an error would be down to a missing Close / Dispose somewhere in the doc generation – Ruben Bartelink Oct 11 '15 at 06:51
9

Another working code, try it

public void ImagesToPdf(string[] imagepaths, string pdfpath)
{
        iTextSharp.text.Rectangle pageSize = null;

        using (var srcImage = new Bitmap(imagepaths[0].ToString()))
        {
            pageSize = new iTextSharp.text.Rectangle(0, 0, srcImage.Width, srcImage.Height);
        }

        using (var ms = new MemoryStream())
        {
            var document = new iTextSharp.text.Document(pageSize, 0, 0, 0, 0);
            iTextSharp.text.pdf.PdfWriter.GetInstance(document, ms).SetFullCompression();
            document.Open();
            var image = iTextSharp.text.Image.GetInstance(imagepaths[0].ToString());
            document.Add(image);
            document.Close();

            File.WriteAllBytes(pdfpath+"cheque.pdf", ms.ToArray());
        }
}
Chirag
  • 324
  • 2
  • 4
  • 27
  • 1
    sorry to bump a 5 years old answer. but lines 3-8 helped me a lot with my pdf file having cut image contents. thanks! – Nii Jan 16 '21 at 16:05
7

One we've had great luck with is PDFSharp (we use it for TIFF and Text to PDF conversion for hundreds of medical claims every day).

http://pdfsharp.com/PDFsharp/

Bob Palmer
  • 4,714
  • 2
  • 27
  • 31
  • I have used PDFSharp but the pdf is distort. Please, see my question http://stackoverflow.com/questions/15437706/pdf-from-bitmap-wrong-size – Ladessa Mar 18 '13 at 12:11
4

Such task can be easily done with help of Docotic.Pdf library.

Here is a sample that creates PDF from given images (not only JPGs, actually):

public static void imagesToPdf(string[] images, string pdfName)
{
    using (PdfDocument pdf = new PdfDocument())
    {
        for (int i = 0; i < images.Length; i++)
        {
            if (i > 0)
                pdf.AddPage();

            PdfPage page = pdf.Pages[i];
            string imagePath = images[i];
            PdfImage pdfImage = pdf.AddImage(imagePath);

            page.Width = pdfImage.Width;
            page.Height = pdfImage.Height;
            page.Canvas.DrawImage(pdfImage, 0, 0);
        }

        pdf.Save(pdfName);
    }
}

Disclaimer: I work for the vendor of the library.

Bobrovsky
  • 13,789
  • 19
  • 80
  • 130
2

If you want to do it in a cross-platform way, without any thirty part library, or paying any license, you can use this code. It takes an array of pictures (I think it only works only with jpg) with its sizes and return a pdf file, with one picture per page.

You have to create two files:

File Picture:

using System;
using System.Collections.Generic;
using System.Text;

namespace PDF
{
    public class Picture
    {
        private byte[] data;
        private int width;
        private int height;

        public byte[] Data { get => data; set => data = value; }
        public int Width { get => width; set => width = value; }
        public int Height { get => height; set => height = value; }
    }
}

File PDFExport:

using System;
using System.Collections.Generic;

namespace PDF
{
    public class PDFExport
    {
        private string company = "Your Company Here";

        public sbyte[] createFile(List<Picture> pictures)
        {
            int N = (pictures.Count + 1) * 3;
            string dateTimeStr = DateTime.Now.ToString("yyyyMMddhhmmss");

            string file1 =
            "%PDF-1.4\n";

            string file2 =
                "2 0 obj\n" +
                "<<\n" +
                "/Type /Pages\n" +
                getKids(pictures) +
                "/Count " + pictures.Count + "\n" +
                 ">>\n" +
                 "endobj\n" +
                "1 0 obj\n" +
                "<<\n" +
                "/Type /Catalog\n" +
                "/Pages 2 0 R\n" +
                "/PageMode /UseNone\n" +
                "/PageLayout /SinglePage\n" +
                 "/Metadata 7 0 R\n" +
                 ">>\n" +
                  "endobj\n" +
                N + " 0 obj\n" +
                "<<\n" +
                "/Creator(" + company + ")\n" +
                "/Producer(" + company + ")\n" +
                "/CreationDate (D:" + dateTimeStr + ")\n" +
                "/ModDate (D:" + dateTimeStr + ")\n" +
                ">>\n" +
                "endobj\n" +
                "xref\n" +
                "0 " + (N + 1) + "\n" +
                "0000000000 65535 f\n" +
                "0000224088 00000 n\n" +
                "0000224031 00000 n\n" +
                "0000000015 00000 n\n" +
                "0000222920 00000 n\n" +
                "0000222815 00000 n\n" +
                "0000224153 00000 n\n" +
                "0000223050 00000 n\n" +
                "trailer\n" +
                "<<\n" +
                "/Size " + (N + 1) + "\n" +
                 "/Root 1 0 R\n" +
                  "/Info 6 0 R\n" +
                   ">>\n" +
                   "startxref\n" +
                "0\n" +
                "%% EOF";

            sbyte[] part1 = file1.GetBytes();
            sbyte[] part2 = file2.GetBytes();

            List<sbyte[]> fileContents = new List<sbyte[]>();
            fileContents.Add(part1);
            for (int i = 0; i < pictures.Count; i++)
            {
                fileContents.Add(getPageFromImage(pictures[i], i));
            }
            fileContents.Add(part2);
            return getFileContent(fileContents);
        }

        private string getKids(List<Picture> pictures)
        {
            string kids = "/Kids[";
            for (int i = 0; i < pictures.Count; i++)
            {
                kids += (3 * (i + 1) + 1) + " 0 R ";
            }
            kids += "]\n";
            return kids;
        }

        private sbyte[] getPageFromImage(Picture picture, int P)
        {
            int N = (P + 1) * 3;
            string imageStart =
            N + " 0 obj\n" +
            "<<\n" +
            "/Type /XObject\n" +
            "/Subtype /Image\n" +
            "/Width " + picture.Width + "\n" +
             "/Height " + picture.Height + "\n" +
              "/BitsPerComponent 8\n" +
               "/ColorSpace /DeviceRGB\n" +
               "/Filter /DCTDecode\n" +
               "/Length " + picture.Data.Length + "\n" +
                ">>\n" +
                "stream\n";

            string dimentions = "q\n" +
            picture.Width + " 0 0 " + picture.Height + " 0 0 cm\n" +
            "/X0 Do\n" +
            "Q\n";

            string imageEnd =
                "\nendstream\n" +
                "endobj\n" +
                (N + 2) + " 0 obj\n" +
                "<<\n" +
                "/Filter []\n" +
                "/Length " + dimentions.Length + "\n" +
                ">>\n" +
                "stream\n";

            string page =
                "\nendstream\n" +
                "endobj\n" +
                (N + 1) + " 0 obj\n" +
                "<<\n" +
                "/Type /Page\n" +
                "/MediaBox[0 0 " + picture.Width + " " + picture.Height + "]\n" +
                "/Resources <<\n" +
                "/XObject <<\n" +
                "/X0 " + N + " 0 R\n" +
                ">>\n" +
                ">>\n" +
                "/Contents 5 0 R\n" +
                "/Parent 2 0 R\n" +
                ">>\n" +
                "endobj\n";

            List<sbyte[]> fileContents = new List<sbyte[]>();
            fileContents.Add(imageStart.GetBytes());
            fileContents.Add(byteArrayToSbyteArray(picture.Data));
            fileContents.Add(imageEnd.GetBytes());
            fileContents.Add(dimentions.GetBytes());
            fileContents.Add(page.GetBytes());
            return getFileContent(fileContents);
        }

        private sbyte[] byteArrayToSbyteArray(byte[] data)
        {
            sbyte[] data2 = new sbyte[data.Length];
            for (int i = 0; i < data2.Length; i++)
            {
                data2[i] = (sbyte)data[i];
            }
            return data2;
        }

        private sbyte[] getFileContent(List<sbyte[]> fileContents)
        {
            int fileSize = 0;
            foreach (sbyte[] content in fileContents)
            {
                fileSize += content.Length;
            }
            sbyte[] finaleFile = new sbyte[fileSize];
            int index = 0;
            foreach (sbyte[] content in fileContents)
            {
                for (int i = 0; i < content.Length; i++)
                {
                    finaleFile[index + i] = content[i];
                }
                index += content.Length;
            }
            return finaleFile;
        }
    }
}

You can use the code in this easy way

///////////////////////////////////////Export PDF//////////////////////////////////////

    private sbyte[] exportPDF(List<Picture> images)
    {
        if (imageBytesList.Count > 0)
        {
            PDFExport pdfExport = new PDFExport();
            sbyte[] fileData = pdfExport.createFile(images);
            return fileData;
        }
        return null;
    }
Led Machine
  • 7,122
  • 3
  • 47
  • 49
1

You need Acrobat to be installed. Tested on Acrobat DC. This is a VB.net code. Due to that these objects are COM objects, you shall do a 'release object', not just a '=Nothing". You can convert this code here: https://converter.telerik.com/

Private Function ImageToPDF(ByVal FilePath As String, ByVal DestinationFolder As String) As String
    Const PDSaveCollectGarbage  As Integer = 32
    Const PDSaveLinearized      As Integer = 4
    Const PDSaveFull            As Integer = 1
    Dim PDFAVDoc                As Object = Nothing
    Dim PDFDoc                  As Object = Nothing

    Try
        'Check destination requirements
        If Not DestinationFolder.EndsWith("\") Then DestinationFolder += "\"
        If Not System.IO.Directory.Exists(DestinationFolder) Then Throw New Exception("Destination directory does not exist: " & DestinationFolder)
        Dim CreatedFile As String = DestinationFolder & System.IO.Path.GetFileNameWithoutExtension(FilePath) & ".pdf"
        'Avoid conflicts, therefore previous file there will be deleted
        If File.Exists(CreatedFile) Then File.Delete(CreatedFile)

        'Get PDF document
        PDFAVDoc = GetPDFAVDoc(FilePath)
        PDFDoc = PDFAVDoc.GetPDDoc

        If Not PDFDoc.Save(PDSaveCollectGarbage Or PDSaveLinearized Or PDSaveFull, CreatedFile) Then Throw New Exception("PDF file cannot be saved: " & PDFDoc.GetFileName())
        If Not PDFDoc.Close() Then Throw New Exception("PDF file could not be closed: " & PDFDoc.GetFileName())
        PDFAVDoc.Close(1)
        Return CreatedFile
    Catch Ex As Exception
        Throw Ex
    Finally
        System.Runtime.InteropServices.Marshal.ReleaseComObject(PDFDoc)
        System.Runtime.InteropServices.Marshal.FinalReleaseComObject(PDFDoc)
        PDFDoc = Nothing
        System.Runtime.InteropServices.Marshal.ReleaseComObject(PDFAVDoc)
        System.Runtime.InteropServices.Marshal.FinalReleaseComObject(PDFAVDoc)
        PDFAVDoc = Nothing
        GC.Collect()
        GC.WaitForPendingFinalizers()
        GC.Collect()
    End Try
End Function
AndrewK
  • 79
  • 3
0

not sure if you're looking for just free / open source solutions or considering commercial ones as well. But if you're including commercial solutions, there's a toolkit called EasyPDF SDK that offers an API for converting images (plus a number of other file types) to PDF. It supports C# and can be found here:

 http://www.pdfonline.com/

The C# code would look as follows:

 Printer oPrinter = new Printer();

 ImagePrintJob oPrintJob = oPrinter.ImagePrintJob;
 oPrintJob.PrintOut(imageFile, pdfFile);

To be fully transparent, I should disclaim that I do work for the makers of EasyPDF SDK (hence my handle), so this suggestion is not without some personal bias :) But feel free to check out the eval version if you're interested. Cheers!

0

I use Sautinsoft, its very simple:

SautinSoft.PdfMetamorphosis p = new SautinSoft.PdfMetamorphosis();
p.Serial="xxx";
p.HtmlToPdfConvertStringToFile("<html><body><img src=\""+filename+"\"></img></body></html>","output.pdf");
user3600403
  • 339
  • 1
  • 2
  • 18
0

You may try to convert any Images to PDF using this code sample:

PdfVision v = new PdfVision();
        ImageToPdfOptions options = new ImageToPdfOptions();
        options.JpegQuality = 95;

        try
        {
            v.ConvertImageToPdf(new string[] {inpFile}, outFile, options);
            System.Diagnostics.Process.Start(new System.Diagnostics.ProcessStartInfo(outFile) { UseShellExecute = true });
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Error: {ex.Message}");
            Console.ReadLine();
        }

Or if you need to convert Image Class to PDF:

System.Drawing.Image image = Image.FromFile(@"..\..\image-jpeg.jpg");
        string outFile = new FileInfo(@"Result.pdf").FullName;

        PdfVision v = new PdfVision();
        ImageToPdfOptions options = new ImageToPdfOptions();
        options.PageSetup.PaperType = PaperType.Auto;


        byte[] imgBytes = null;

        using (MemoryStream ms = new System.IO.MemoryStream())
        {
            image.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
            imgBytes = ms.ToArray();
        }

        try
        {
            v.ConvertImageToPdf(imgBytes, outFile, options);
            System.Diagnostics.Process.Start(new System.Diagnostics.ProcessStartInfo(outFile) { UseShellExecute = true });
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Error: {ex.Message}");
            Console.ReadLine();
        }
Rickie
  • 11
  • 1
-6

Many diff tools out there. One I use is PrimoPDF (FREE) http://www.primopdf.com/ you go to print the file and you print it to pdf format onto your drive. works on Windows

Harry
  • 1