Сжатие существующего PDF с использованием программирования на С# с использованием бесплатных библиотек
Я много искал в Google о том, как сжать существующий pdf
(размер).
Моя проблема
-
Я не могу использовать какое-либо приложение, потому что это нужно сделать с помощью программы на С#.
-
Я не могу использовать какую-либо платную библиотеку, поскольку мои клиенты не хотят выходить из бюджета. Таким образом, библиотека PAID, безусловно, НЕТ
Я работаю на дому в течение последних 2 дней и натолкнулся на решение, используя iTextSharp, BitMiracle, но безрезультатно, поскольку первые уменьшают только 1% файла, а позже платят.
Я также столкнулся с PDFcompressNET и pdftk, но я не смог найти их .dll.
На самом деле pdf - это страховой полис с 2-3 изображениями (черно-белый) и около 70 страниц с размером 5 МБ.
Мне нужен вывод только в формате pdf (не может быть в другом формате)
Ответы
Ответ 1
Вот такой подход для этого (и это должно работать независимо от используемого инструментария):
Если у вас есть 24-битное изображение rgb или 32 бит cmyk, выполните следующие действия:
- определить, действительно ли это изображение. Если это cmyk, конвертируйте в rgb. Если он rgb и действительно серый, конвертируйте в серый цвет. Если он серый или палированный и имеет только 2 реальных цвета, конвертируйте их в 1 бит. Если он серый и относительно мало вариантов серого цвета, рассмотрите преобразование в 1 бит с помощью подходящей техники бинаризации.
- Измерьте размеры изображения относительно того, как он размещается на странице - если он имеет разрешение 300 dpi или более, рассмотрите возможность передискретизации изображения на меньший размер в зависимости от глубины бита изображения - например, вы, вероятно, можете пойти от 300 точек на дюйм серого или от rgb до 200 dpi и не теряйте слишком много деталей.
- Если у вас есть изображение rgb, которое действительно цветное, подумайте о его палиттинге.
- Изучите содержимое изображения, чтобы увидеть, можете ли вы помочь сделать его более сжимаемым. Например, если вы просматриваете цветное/серое изображение и выделяете много цветов в этом кластере, подумайте о его сглаживании. Если он серый или черно-белый и содержит несколько пятнышек, рассмотрите despeckling.
- выберите окончательное сжатие с умом. JPEG2000 может работать лучше, чем JPEG. JBIG2 работает намного лучше, чем G4. Flate, вероятно, является лучшим неразрушающим сжатием для серого. Большинство реализаций JPEG2000 и JBIG2 не являются бесплатными.
- Если вы рок-звезда, вы хотите попробовать сегментировать изображение и разбить его на области, которые действительно черно-белые и действительно цветные.
Тем не менее, если вы это сделаете, вы можете сделать все это хорошо неконтролируемым образом, у вас есть коммерческий продукт в своем собственном праве.
Я скажу, что вы можете сделать большую часть этого с помощью Atalasoft dotImage (отказ от ответственности: он не бесплатный, я там работаю, я написал почти все инструменты PDF, Я работал в Acrobat).
Один конкретный способ использования метода dotImage - вытащить все страницы, которые являются только имиджем, повторно сжать их и сохранить в новый PDF файл, а затем построить новый 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-формате) или извлечение изображения (и отслеживание матрицы преобразования на изображении), и выполните перечисленные выше действия. Это нетривиально, но это выполнимо.
Ответ 2
Я думаю, вы, возможно, захотите, чтобы ваши клиенты знали, что любая из упомянутых вами библиотек не является полностью бесплатной:
- iTextSharp имеет лицензию AGPL, поэтому вы должны освободить исходный код своего решения или купить коммерческую лицензию.
- PDFcompressNET - это коммерческая библиотека.
- pdftk лицензирован GPL, поэтому вы должны освободить исходный код своего решения или купить коммерческую лицензию.
- Docotic.Pdf - это коммерческая библиотека.
Учитывая все вышеизложенное, я предполагаю, что могу отказаться от бесплатного требования.
Docotic.Pdf может уменьшить размер сжатых и несжатых PDF файлов в разной степени без каких-либо деструктивных изменений.
Доходы зависят от размера и структуры 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
.
Библиотека при необходимости преобразует цветные изображения в двууровневые. Вы можете указать уровень сжатия дефлята, качество 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.
Ответ 3
GhostScript - это лицензионное программное обеспечение AGPL, которое может сжимать PDF файлы. Существует также AGPL-лицензированная оболочка С# для нее на github здесь.
Вы можете использовать класс GhostscriptProcessor
из этой оболочки для передачи пользовательских команд GhostScript, например, найденных в этом ответе AskUbuntu, описывающих сжатие PDF.
Ответ 4
Использование 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);
}
}