Подтвердить что ты не робот

Сжатие существующего PDF с использованием программирования на С# с использованием бесплатных библиотек

Я много искал в Google о том, как сжать существующий pdf (размер). Моя проблема

  • Я не могу использовать какое-либо приложение, потому что это нужно сделать с помощью программы на С#.

  • Я не могу использовать какую-либо платную библиотеку, поскольку мои клиенты не хотят выходить из бюджета. Таким образом, библиотека PAID, безусловно, НЕТ

Я работаю на дому в течение последних 2 дней и натолкнулся на решение, используя iTextSharp, BitMiracle, но безрезультатно, поскольку первые уменьшают только 1% файла, а позже платят.

Я также столкнулся с PDFcompressNET и pdftk, но я не смог найти их .dll.

На самом деле pdf - это страховой полис с 2-3 изображениями (черно-белый) и около 70 страниц с размером 5 МБ.

Мне нужен вывод только в формате pdf (не может быть в другом формате)

4b9b3361

Ответ 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);
    }
}