【发布时间】:2014-07-17 07:06:10
【问题描述】:
我需要将 PDF 文件转换为 图像。如果PDF文件是多页,我只需要一张包含所有PDF页面的图片。
有没有像 Acrobat 产品一样不收费的开源解决方案?
【问题讨论】:
我需要将 PDF 文件转换为 图像。如果PDF文件是多页,我只需要一张包含所有PDF页面的图片。
有没有像 Acrobat 产品一样不收费的开源解决方案?
【问题讨论】:
线程“converting PDF file to a JPEG image”适合你的要求。
一种解决方案是使用第三方库。 ImageMagick 非常受欢迎,也可以免费获得。你可以得到一个 .NET 包装器here。 ImageMagick 原始下载页面为here。
你也可以看看线程 “How to open a page from a pdf file in pictureBox in C#”.
如果你使用this process to convert a PDF to tiff,你可以使用这个类从TIFF检索位图。
public class TiffImage
{
private string myPath;
private Guid myGuid;
private FrameDimension myDimension;
public ArrayList myImages = new ArrayList();
private int myPageCount;
private Bitmap myBMP;
public TiffImage(string path)
{
MemoryStream ms;
Image myImage;
myPath = path;
FileStream fs = new FileStream(myPath, FileMode.Open);
myImage = Image.FromStream(fs);
myGuid = myImage.FrameDimensionsList[0];
myDimension = new FrameDimension(myGuid);
myPageCount = myImage.GetFrameCount(myDimension);
for (int i = 0; i < myPageCount; i++)
{
ms = new MemoryStream();
myImage.SelectActiveFrame(myDimension, i);
myImage.Save(ms, ImageFormat.Bmp);
myBMP = new Bitmap(ms);
myImages.Add(myBMP);
ms.Close();
}
fs.Close();
}
}
像这样使用它:
private void button1_Click(object sender, EventArgs e)
{
TiffImage myTiff = new TiffImage("D:\\Some.tif");
//imageBox is a PictureBox control, and the [] operators pass back
//the Bitmap stored at that position in the myImages ArrayList in the TiffImage
this.pictureBox1.Image = (Bitmap)myTiff.myImages[0];
this.pictureBox2.Image = (Bitmap)myTiff.myImages[1];
this.pictureBox3.Image = (Bitmap)myTiff.myImages[2];
}
【讨论】:
您可以使用Ghostscript 将 PDF 转换为图像。
要使用 .NET 中的 Ghostscript,您可以查看 Ghostscript.NET 库(Ghostscript 库的托管包装器)。
要使用 Ghostscript.NET 从 PDF 生成 图像,请查看 RasterizerSample。
要将多张图片合并为一张图片,请查看此示例:http://www.niteshluharuka.com/2012/08/combine-several-images-to-form-a-single-image-using-c/#
【讨论】:
至于 2018 年,如何在 C# 中将 PDF 文档转换为图像的问题仍然没有一个简单的答案;许多图书馆使用Ghostscript licensed under AGPL,在大多数情况下,生产使用需要昂贵的商业许可。
一个不错的选择可能是使用具有GPL 许可证的流行“pdftoppm”实用程序;它可以从 C# 中用作使用 System.Diagnostics.Process 执行的命令行工具。流行的工具在 Linux 世界中是众所周知的,但也可以使用 a windows build。
如果你不想自己集成 pdftoppm,可以使用我的PdfRenderer popular wrapper(同时支持经典 .NET Framework 和.NET Core)——它不是免费的,但价格非常实惠。
【讨论】:
我在.NET Standard 2.1 类库中使用了PDFiumSharp 和ImageSharp。
/// <summary>
/// Saves a thumbnail (jpg) to the same folder as the PDF file, using dimensions 300x423,
/// which corresponds to the aspect ratio of 'A' paper sizes like A4 (ratio h/w=sqrt(2))
/// </summary>
/// <param name="pdfPath">Source path of the pdf file.</param>
/// <param name="thumbnailPath">Target path of the thumbnail file.</param>
/// <param name="width"></param>
/// <param name="height"></param>
public static void SaveThumbnail(string pdfPath, string thumbnailPath = "", int width = 300, int height = 423)
{
using var pdfDocument = new PdfDocument(pdfPath);
var firstPage = pdfDocument.Pages[0];
using var pageBitmap = new PDFiumBitmap(width, height, true);
firstPage.Render(pageBitmap);
var imageJpgPath = string.IsNullOrWhiteSpace(thumbnailPath)
? Path.ChangeExtension(pdfPath, "jpg")
: thumbnailPath;
var image = Image.Load(pageBitmap.AsBmpStream());
// Set the background to white, otherwise it's black. https://github.com/SixLabors/ImageSharp/issues/355#issuecomment-333133991
image.Mutate(x => x.BackgroundColor(Rgba32.White));
image.Save(imageJpgPath, new JpegEncoder());
}
【讨论】:
Google Chrome 中使用的 PDF 引擎,名为 PDFium,在“BSD 3-clause”许可下是开源的。我相信这允许在商业产品中使用时重新分发。
它有一个名为PdfiumViewer (NuGet) 的.NET 包装器,在我尝试过的范围内效果很好。它在 Apache 许可下也允许重新分发。
(请注意,这与需要商业许可证的https://pdfium.patagames.com/ 的“包装器”不同*)
(还有另一个 PDFium .NET 包装器,PDFiumSharp,但我没有评估它。)
在我看来,到目前为止,这可能是开源(像啤酒一样免费)PDF 库的最佳选择来完成不对封闭源代码/使用它们的软件的商业性质。据我所知,我认为这里的答案中没有任何其他内容符合该标准。
【讨论】:
关于PDFiumSharp:经过详细阐述,我能够从 PDF 解决方案创建 PNG 文件。
这是我的代码:
using PDFiumSharp;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
public class Program
{
static public void Main(String[] args)
{
var renderfoo = new Renderfoo()
renderfoo.RenderPDFAsImages(@"C:\Temp\example.pdf", @"C:\temp");
}
}
public class Renderfoo
{
public void RenderPDFAsImages(string Inputfile, string OutputFolder)
{
string fileName = Path.GetFileNameWithoutExtension(Inputfile);
using (PDFiumSharp.PdfDocument doc = new PDFiumSharp.PdfDocument(Inputfile))
{
for (int i = 0; i < doc.Pages.Count; i++)
{
var page = doc.Pages[i];
using (var bitmap = new System.Drawing.Bitmap((int)page.Width, (int)page.Height))
{
var grahpics = Graphics.FromImage(bitmap);
grahpics.Clear(Color.White);
page.Render(bitmap);
var targetFile = Path.Combine(OutputFolder, fileName + "_" + i + ".png");
bitmap.Save(targetFile);
}
}
}
}
}
对于初学者,您需要执行以下步骤来启动和运行 PDFium 包装器:
在您的项目中同时引用 PDFiumSharp 和 PDFiumsharp.GdiPlus 程序集
确保 pdfium_x64.dll 和/或 pdfium_x86.dll 都在您的项目输出目录中。
【讨论】:
在 Windows 和 Linux 上寻找强大且免费的 dotnet core 解决方案让我找到了https://github.com/Dtronix/PDFiumCore 和https://github.com/GowenGit/docnet。由于 PDFiumCore 使用更新版本的 Pdfium(这似乎是使用 pdf 库的关键点),我最终使用了它。
注意:如果你想在 Linux 上使用它,你应该按照https://stackoverflow.com/a/59252639/6339469 的建议安装“libgdiplus”。
这是一个简单的单线程代码:
var pageIndex = 0;
var scale = 2;
fpdfview.FPDF_InitLibrary();
var document = fpdfview.FPDF_LoadDocument("test.pdf", null);
var page = fpdfview.FPDF_LoadPage(document, pageIndex);
var size = new FS_SIZEF_();
fpdfview.FPDF_GetPageSizeByIndexF(document, 0, size);
var width = (int)Math.Round(size.Width * scale);
var height = (int)Math.Round(size.Height * scale);
var bitmap = fpdfview.FPDFBitmapCreateEx(
width,
height,
4, // BGRA
IntPtr.Zero,
0);
fpdfview.FPDFBitmapFillRect(bitmap, 0, 0, width, height, (uint)Color.White.ToArgb());
// | | a b 0 |
// | matrix = | c d 0 |
// | | e f 1 |
using var matrix = new FS_MATRIX_();
using var clipping = new FS_RECTF_();
matrix.A = scale;
matrix.B = 0;
matrix.C = 0;
matrix.D = scale;
matrix.E = 0;
matrix.F = 0;
clipping.Left = 0;
clipping.Right = width;
clipping.Bottom = 0;
clipping.Top = height;
fpdfview.FPDF_RenderPageBitmapWithMatrix(bitmap, page, matrix, clipping, (int)RenderFlags.RenderAnnotations);
var bitmapImage = new Bitmap(
width,
height,
fpdfview.FPDFBitmapGetStride(bitmap),
PixelFormat.Format32bppArgb,
fpdfview.FPDFBitmapGetBuffer(bitmap));
bitmapImage.Save("test.jpg", ImageFormat.Jpeg);
有关线程安全的实现,请参见: https://github.com/hmdhasani/DtronixPdf/blob/master/src/DtronixPdfBenchmark/Program.cs
【讨论】:
Apache PDFBox 也很适合我。
使用命令行工具:
javar -jar pdfbox-app-2.0.19.jar PDFToImage -quality 1.0 -dpi 150 -prefix out_dir/page -format png
【讨论】:
使用 AppCompat 等 Android 默认库,您可以将所有 PDF 页面转换为图像。这种方式非常快速且经过优化。 以下代码用于获取 PDF 页面的单独图像。速度非常快。
ParcelFileDescriptor fileDescriptor = ParcelFileDescriptor.open(new File("pdfFilePath.pdf"), MODE_READ_ONLY);
PdfRenderer renderer = new PdfRenderer(fileDescriptor);
final int pageCount = renderer.getPageCount();
for (int i = 0; i < pageCount; i++) {
PdfRenderer.Page page = renderer.openPage(i);
Bitmap bitmap = Bitmap.createBitmap(page.getWidth(), page.getHeight(),Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
canvas.drawColor(Color.WHITE);
canvas.drawBitmap(bitmap, 0, 0, null);
page.render(bitmap, null, null, PdfRenderer.Page.RENDER_MODE_FOR_DISPLAY);
page.close();
if (bitmap == null)
return null;
if (bitmapIsBlankOrWhite(bitmap))
return null;
String root = Environment.getExternalStorageDirectory().toString();
File file = new File(root + filename + ".png");
if (file.exists()) file.delete();
try {
FileOutputStream out = new FileOutputStream(file);
bitmap.compress(Bitmap.CompressFormat.PNG, 100, out);
Log.v("Saved Image - ", file.getAbsolutePath());
out.flush();
out.close();
} catch (Exception e) {
e.printStackTrace();
}
}
================================================ ========
private static boolean bitmapIsBlankOrWhite(Bitmap bitmap) {
if (bitmap == null)
return true;
int w = bitmap.getWidth();
int h = bitmap.getHeight();
for (int i = 0; i < w; i++) {
for (int j = 0; j < h; j++) {
int pixel = bitmap.getPixel(i, j);
if (pixel != Color.WHITE) {
return false;
}
}
}
return true;
}
【讨论】:
NuGet 包Pdf2Png 是免费提供的,仅受MIT License 保护,非常开放。
我已经测试了一下,这是让它将 PDF 文件转换为图像的代码(tt 确实将图像保存在调试文件夹中)。
using cs_pdf_to_image;
using PdfToImage;
private void BtnConvert_Click(object sender, EventArgs e)
{
if(openFileDialog1.ShowDialog() == DialogResult.OK)
{
try
{
string PdfFile = openFileDialog1.FileName;
string PngFile = "Convert.png";
List<string> Conversion = cs_pdf_to_image.Pdf2Image.Convert(PdfFile, PngFile);
Bitmap Output = new Bitmap(PngFile);
PbConversion.Image = Output;
}
catch(Exception E)
{
MessageBox.Show(E.Message);
}
}
}
【讨论】:
有一个免费的 nuget 包 (Pdf2Image),它允许在一行中将 pdf 页面提取为 jpg 文件或图像集合 (List)
string file = "c:\\tmp\\test.pdf";
List<System.Drawing.Image> images = PdfSplitter.GetImages(file, PdfSplitter.Scale.High);
PdfSplitter.WriteImages(file, "c:\\tmp", PdfSplitter.Scale.High, PdfSplitter.CompressionLevel.Medium);
所有源码也可以在 github 上找到Pdf2Image
【讨论】:
您可以查看 Freeware.Pdf2Png MIT 许可证。 只需在您的 nuget 中找到这些名称即可。
var dd = System.IO.File.ReadAllBytes("pdffile.pdf");
byte[] pngByte = Freeware.Pdf2Png.Convert(dd, 1);
System.IO.File.WriteAllBytes(Path.Combine(@"C:\temp", "dd.png"), pngByte );
【讨论】:
【讨论】:
https://www.codeproject.com/articles/317700/convert-a-pdf-into-a-series-of-images-using-csharp
我发现这个 GhostScript 包装器在将 PDF 逐页转换为 PNG 时非常有效。
用法:
string pdf_filename = @"C:\TEMP\test.pdf";
var pdf2Image = new Cyotek.GhostScript.PdfConversion.Pdf2Image(pdf_filename);
for (var page = 1; page < pdf2Image.PageCount; page++)
{
string png_filename = @"C:\TEMP\test" + page + ".png";
pdf2Image.ConvertPdfPageToImage(png_filename, page);
}
基于 GhostScript 构建,显然对于商业应用,许可问题仍然存在。
【讨论】:
(免责声明我曾在 Software Siglo XXI 开发过这个组件)
您可以使用 Super Pdf2Image Converter 生成一个 TIFF 多页文件,其中包含 PDF 中所有呈现的高分辨率页面。它适用于 32 位和 64 位,并且非常便宜且有效。我建议你试试看。
只需一行代码...
GetImage(outputFileName, firstPage, lastPage, resolution, imageFormat)
Converts specifies pages to image and save them to outputFileName (tiff allows multi-page or creates several files)
你可以看这里:http://softwaresigloxxi.com/SuperPdf2ImageConverter.html
【讨论】: