使用免费软件库使用 C# 编程压缩现有 PDF
Posted
技术标签:
【中文标题】使用免费软件库使用 C# 编程压缩现有 PDF【英文标题】:Compress existing PDF using C# programming using freeware libraries 【发布时间】:2012-11-23 01:28:48 【问题描述】:我在 Google 上搜索了很多关于如何压缩现有 pdf
(大小)的信息。
我的问题是
我不能使用任何应用程序,因为它需要由 C# 程序完成。
我不能使用任何付费图书馆,因为我的客户不想超出预算。所以付费图书馆肯定是NO
我过去 2 天做了功课,并使用 iTextSharp、BitMiracle 找到了一个解决方案,但无济于事,因为前者仅减少 1% 的文件,而后者是付费的。
我也遇到了 PDFcompressNET 和 pdftk,但我找不到它们的 .dll。
实际上,pdf 是包含 2-3 张图像(黑白)和大约 70 页的保险单,大小为 5 MB。
我只需要pdf格式的输出(不能是任何其他格式)
【问题讨论】:
BitMiracle 压缩结果是什么? 我不能使用 bitmiracle,因为它是一个付费图书馆!!! 你确定压缩会有帮助吗?尝试创建一些 PDF 文件的测试用例,并使用各种现成的程序/方法对其进行压缩。这些的压缩率是多少?也许您正在尝试做一些不值得/可能的事情? 如果您提到的文件具有代表性,那么“合并 50 个 pdf 文件”的步骤不幸地以错误的方式使用了 iTextSharp 4.1.2 库(在此任务中使用 PdfWriter 而不是 PdfCopy)。 .. 好吧,乍一看,您的主要问题可能是包含的 70 个字体子集文件;尽管压缩,但其中许多都需要超过 80 KB!不幸的是,重新组合同一字体的多个不同子集通常很困难(文档的大多数页面的内容可能必须重写),并且 iText(Sharp) 并不明确支持;这将是一项壮举! @Vijay 没有任何进一步的解释我怀疑你的赏金是否得到了充分利用。根据您的要求和尝试(我希望您已经尝试过)提出一个新问题会更好。 【参考方案1】:我认为您可能想让您的客户意识到您提到的任何库都不是完全免费的:
iTextSharp 已获得 AGPL 许可,因此您必须发布解决方案的源代码或购买商业许可。 PDFcompressNET 是一个商业库。 pdftk 已获得 GPL 许可,因此您必须发布解决方案的源代码或购买商业许可。 Docotic.Pdf 是一个商业图书馆。鉴于以上所有情况,我认为我可以放弃 免费软件 要求。
Docotic.Pdf 可以在不同程度上reduce size of compressed and uncompressed PDFs 而不引入任何破坏性更改。
增益取决于 PDF 的大小和结构:对于小文件或主要是扫描图像的文件,减少可能不是那么好,因此您应该尝试包含文件的库并亲自查看。
如果您最关心大小并且您的文件中有很多图像并且您可以放心地丢失这些图像的一些质量,然后您可以轻松地重新压缩使用 Docotic.Pdf 的现有图像。
这是使所有图像双层并使用传真压缩进行压缩的代码:
static void RecompressExistingImages(string fileName, string outputName)
using (PdfDocument doc = new PdfDocument(fileName))
foreach (PdfImage image in doc.Images)
image.RecompressWithGroup4Fax();
doc.Save(outputName);
还有RecompressWithFlate
、RecompressWithGroup3Fax
和RecompressWithJpeg
方法。
如果需要,该库会将彩色图像转换为双层图像。您可以指定 deflate 压缩级别、JPEG 质量等。
Docotic.Pdf 还可以在 PDF 中调整大图像的大小(并同时重新压缩它们)。如果文档中的图像实际上比需要的大,或者图像质量不是那么重要,这可能会很有用。
以下代码可缩放宽度或高度大于或等于 256 的所有图像。缩放后的图像随后使用 JPEG 压缩进行编码。
public static void RecompressToJpeg(string path, string outputPath)
using (PdfDocument doc = new PdfDocument(path))
foreach (PdfImage image in doc.Images)
// image that is used as mask or image with attached mask are
// not good candidates for recompression
if (!image.IsMask && image.Mask == null && (image.Width >= 256 || image.Height >= 256))
image.Scale(0.5, PdfImageCompression.Jpeg, 65);
doc.Save(outputPath);
可以使用ResizeTo
方法之一将图像调整为指定的宽度和高度。请注意ResizeTo
方法不会尝试保留图像的纵横比。您应该自己计算适当的宽度和高度。
免责声明:我为 Bit Miracle 工作。
【讨论】:
使用 JPEG 缩放/重新压缩并更改 jpeg 质量时要格外小心。我知道有一个程序员被分配了这项任务,需要归档法律文件,结果是一些法庭案件不得不被丢弃,因为文件的唯一副本现在不可读。【参考方案2】:使用PdfSharp
public static void CompressPdf(string targetPath)
using (var stream = new MemoryStream(File.ReadAllBytes(targetPath)) Position = 0)
using (var source = PdfReader.Open(stream, PdfDocumentOpenMode.Import))
using (var document = new PdfDocument())
var options = document.Options;
options.FlateEncodeMode = PdfFlateEncodeMode.BestCompression;
options.UseFlateDecoderForJpegImages = PdfUseFlateDecoderForJpegImages.Automatic;
options.CompressContentStreams = true;
options.NoCompression = false;
foreach (var page in source.Pages)
document.AddPage(page);
document.Save(targetPath);
【讨论】:
谢谢@Simon。这是我的第一个任务(我失败得很厉害)。现在我开始研究 BI 应用程序和数据库【参考方案3】:GhostScript 是 AGPL 许可软件,可以压缩 PDF。在 github here 上还有一个 AGPL 许可的 C# 包装器。
您可以使用该包装器中的 GhostscriptProcessor
类将自定义命令传递给 GhostScript,就像在描述 PDF 压缩的 this AskUbuntu answer 中找到的命令一样。
【讨论】:
【参考方案4】:这是一种方法(不管您使用的工具包,这应该可以工作):
如果您有 24 位 rgb 或 32 位 cmyk 图像,请执行以下操作:
确定图像是否真实。如果是 cmyk,则转换为 rgb。如果它是 rgb 并且真的是灰色的,则转换为灰色。如果它是灰色或调色板并且只有 2 种真实颜色,则转换为 1 位。如果它是灰色的并且灰度变化的方式相对较少,请考虑使用合适的二值化技术转换为 1 位。 根据图像在页面上的放置方式测量图像尺寸 - 如果 300 dpi 或更高,请考虑根据图像的位深度将图像重新采样为更小的尺寸 - 例如,您可以 可能从 300 dpi 灰色或 rgb 到 200 dpi 并且不会丢失太多细节。 如果您有一个真正彩色的 rgb 图像,请考虑将其调色。 检查图像的内容,看看是否可以帮助使其更易于压缩。例如,如果您浏览一个彩色/灰色图像并细化很多聚集的颜色,请考虑对它们进行平滑处理。如果它是灰色或黑白并包含许多斑点,请考虑去除斑点。 明智地选择最终压缩。 JPEG2000 可以比 JPEG 做得更好。 JBIG2 比 G4 做得好得多。 Flate 可能是灰色的最佳非破坏性压缩。 JPEG2000 和 JBIG2 的大多数实现不是免费的。 如果您是摇滚明星,您想尝试分割图像并将其分成真正黑白和真正彩色的区域。也就是说,如果您能以无人监督的方式完成所有这些工作,那么您就拥有了自己的商业产品。
我会说您可以使用 Atalasoft dotImage 完成大部分工作(免责声明:它不是免费的;我在那里工作;我编写了几乎所有的 PDF 工具;我曾经在 Acrobat 上工作)。
使用 dotImage 的一种特殊方法是提取所有仅是图像的页面,重新压缩它们并将它们保存到新的 PDF 中,然后通过从原始文档中获取所有页面并将它们替换为重新压缩页面,然后再次保存。没那么难。
List<int> pagesToReplace = new List<int>();
PdfImageCollection pagesToEncode = new PdfImageCollection();
using (Document doc = new Document(sourceStream, password))
for (int i=0; i < doc.Pages.Count; i++)
Page page = doc.Pages[i];
if (page.SingleImageOnly)
pagesToReplace.Add(i);
// a PDF image encapsulates an image an compression parameters
PdfImage image = ProcessImage(sourceStream, doc, page, i);
pagesToEncode.Add(i);
PdfEncoder encoder = new PdfEncoder();
encoder.Save(tempOutStream, pagesToEncode, null); // re-encoded pages
tempOutStream.Seek(0, SeekOrigin.Begin);
sourceStream.Seek(0, SeekOrigin.Begin);
PdfDocument finalDoc = new PdfDocument(sourceStream, password);
PdfDocument replacementPages = new PdfDocument(tempOutStream);
for (int i=0; i < pagesToReplace.Count; i++)
finalDoc.Pages[pagesToReplace[i]] = replacementPages.Pages[i];
finalDoc.Save(finalOutputStream);
这里缺少的是 ProcessImage()。 ProcessImage 将对页面进行光栅化(您无需了解图像可能已被缩放到 PDF 上)或提取图像(并跟踪图像上的转换矩阵),然后执行上面列出的步骤。这不是微不足道的,但它是可行的。
【讨论】:
以上是关于使用免费软件库使用 C# 编程压缩现有 PDF的主要内容,如果未能解决你的问题,请参考以下文章
使用免费的 c# 解决方案将 pdf 转换为 jpeg [关闭]