C#中的JPG到PDF转换器

28

我想将图片(如jpg或png)转换为PDF格式。

我查看了ImageMagickNET,但它对我的需求来说过于复杂。

有哪些其他.NET解决方案或代码可用于将图像转换为PDF格式?


还有http://www.graphicsmagick.org/,它是ImageMagick的改进版本(代码方面)。不过我不知道是否有适用于.NET的库。 - csl
这是用于桌面/服务器/网络应用程序吗? - o.k.w
这是一个Web应用程序,但这并不影响应用程序的类型,因为编码将是相同的。 - Coppermill
11个回答

36

使用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();
        }
    }
}

不错,整理得很好,点个赞。顺便问一下(我已经很久没用过了),使用带有IDisposable的Document是否有更简洁的方法?或者应该加上try/finally来保护Close吗?如果imageStream是实际的资源持有者/所有者,那么可能不需要。 - Ruben Bartelink
我收到了“PdfWriter在当前上下文中不存在”的错误信息。 - Ladessa
3
如何在PDF中添加图像的宽度和高度? - Vishal Kiri
以下代码似乎可以缩小大图像而不会扭曲其尺寸: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

19

iTextSharp是一个开源的解决方案,能够干净地实现所需功能。此外,作者还有一本非常好的附带书籍,如果你要处理表单等更有趣的事情,我建议你阅读这本书。对于普通用途,邮件列表和新闻组中有许多资源可以提供如何执行常见操作的示例。

编辑:正如@Chirag的评论所暗示的那样,@Darin的答案中的代码绝对可以与当前版本编译。

示例用法:

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


10
iTextSharp是开源的,但不是免费的。由于他们使用的是AGPL许可证,因此您必须支付许可费或公开自己的代码。请在以下链接中查看详情:http://itextpdf.com/terms-of-use/index.php - user356178
出现错误2:'iTextSharp.text.Document':在using语句中使用的类型必须可以隐式转换为'System.IDisposable'。 - Chirag
@Chirag 我不记得当时是否实际编译了代码,或者你使用的是另一个版本(这里有类似代码的示例来确认它在某个时候是有意义的)。然而,一般来说,如果它不是可处理的,省略 using 应该是安全的。等一下,看看 @Darin 的答案。感谢指出皇帝的衣服 :) - Ruben Bartelink
我已经检查了那段代码,发现一个问题:“由于另一个进程正在使用该文件“test.jpg”,因此无法访问该文件。” - Chirag
@Chirag 这种错误很可能是由于文档生成过程中缺少 Close / Dispose 导致的。 - Ruben Bartelink

9

另一个可用的代码,试一试

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

1
抱歉打扰一个五年前的回答。但第3-8行对我的PDF文件有裁剪图像内容问题帮助很大。谢谢! - Nii

7

我们运用过的一款非常好用的工具是PDFSharp(我们每天使用它将数百份医疗索赔的TIFF和文本转换为PDF)。

http://pdfsharp.com/PDFsharp/


我使用了PDFSharp,但是PDF文件失真了。请查看我的问题:http://stackoverflow.com/questions/15437706/pdf-from-bitmap-wrong-size - Ladessa

4

借助Docotic.Pdf库,可以轻松完成此任务。

以下是一个示例,可从给定的图像(不仅限于JPG)创建PDF:

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

免责声明:我是这个库的供应商工作的人。

3
如果你想以跨平台的方式实现,不使用任何第三方库或支付任何许可费用,你可以使用以下代码。它接受一组图片(我认为只适用于jpg格式),并返回一个pdf文件,每页包含一张图片。
需要创建两个文件:
文件 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; }
    }
}

文件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;
        }
    }
}

您可以以这种简单的方式使用代码。
///////////////////////////////////////导出 PDF//////////////////////////////////////
    private sbyte[] exportPDF(List<Picture> images)
    {
        if (imageBytesList.Count > 0)
        {
            PDFExport pdfExport = new PDFExport();
            sbyte[] fileData = pdfExport.createFile(images);
            return fileData;
        }
        return null;
    }

1
您需要安装Acrobat。在Acrobat DC上进行了测试。这是VB.net代码。由于这些对象是COM对象,因此您应该执行“release object”,而不仅仅是“= Nothing”。您可以在此处转换此代码: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

0
您可以使用以下代码示例将任何图像转换为PDF:
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();
        }

或者如果您需要将图像类转换为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();
        }

0

不确定您是否只寻找免费/开源解决方案,还是也考虑商业解决方案。但如果您包括商业解决方案,有一个名为EasyPDF SDK的工具包,提供了将图像(以及其他文件类型)转换为PDF的API。它支持C#,可以在此处找到:

 http://www.pdfonline.com/

以下是C#代码:

 Printer oPrinter = new Printer();

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

为了完全透明,我应该声明我是EasyPDF SDK制造商的员工(因此我的处理方式),所以这个建议并不是没有一些个人偏见 :) 但如果您有兴趣,请随时查看评估版本。干杯!

0

我使用Sautinsoft,非常简单:

SautinSoft.PdfMetamorphosis p = new SautinSoft.PdfMetamorphosis();
p.Serial="xxx";
p.HtmlToPdfConvertStringToFile("<html><body><img src=\""+filename+"\"></img></body></html>","output.pdf");

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接