PDF Converter em PNGs em preto e branco
Estou tentando compactar PDFs usando o iTextSharp. Existem muitas páginas com imagens coloridas armazenadas como JPEGs (DCTDECODE) ... então, estou convertendo-as em PNGs em preto-e-branco e substituindo-as no documento (o PNG é muito menor que um JPG para o formato preto e branco)
Eu tenho os seguintes métodos:
private static bool TryCompressPdfImages(PdfReader reader)
{
try
{
int n = reader.XrefSize;
for (int i = 0; i < n; i++)
{
PdfObject obj = reader.GetPdfObject(i);
if (obj == null || !obj.IsStream())
{
continue;
}
var dict = (PdfDictionary)PdfReader.GetPdfObject(obj);
var subType = (PdfName)PdfReader.GetPdfObject(dict.Get(PdfName.SUBTYPE));
if (!PdfName.IMAGE.Equals(subType))
{
continue;
}
var stream = (PRStream)obj;
try
{
var image = new PdfImageObject(stream);
Image img = image.GetDrawingImage();
if (img == null) continue;
using (img)
{
int width = img.Width;
int height = img.Height;
using (var msImg = new MemoryStream())
using (var bw = img.ToBlackAndWhite())
{
bw.Save(msImg, ImageFormat.Png);
msImg.Position = 0;
stream.SetData(msImg.ToArray(), false, PdfStream.NO_COMPRESSION);
stream.Put(PdfName.TYPE, PdfName.XOBJECT);
stream.Put(PdfName.SUBTYPE, PdfName.IMAGE);
stream.Put(PdfName.FILTER, PdfName.FLATEDECODE);
stream.Put(PdfName.WIDTH, new PdfNumber(width));
stream.Put(PdfName.HEIGHT, new PdfNumber(height));
stream.Put(PdfName.BITSPERCOMPONENT, new PdfNumber(8));
stream.Put(PdfName.COLORSPACE, PdfName.DEVICERGB);
stream.Put(PdfName.LENGTH, new PdfNumber(msImg.Length));
}
}
}
catch (Exception ex)
{
Trace.TraceError(ex.ToString());
}
finally
{
// may or may not help
reader.RemoveUnusedObjects();
}
}
return true;
}
catch (Exception ex)
{
Trace.TraceError(ex.ToString());
return false;
}
}
public static Image ToBlackAndWhite(this Image image)
{
image = new Bitmap(image);
using (Graphics gr = Graphics.FromImage(image))
{
var grayMatrix = new[]
{
new[] {0.299f, 0.299f, 0.299f, 0, 0},
new[] {0.587f, 0.587f, 0.587f, 0, 0},
new[] {0.114f, 0.114f, 0.114f, 0, 0},
new [] {0f, 0, 0, 1, 0},
new [] {0f, 0, 0, 0, 1}
};
var ia = new ImageAttributes();
ia.SetColorMatrix(new ColorMatrix(grayMatrix));
ia.SetThreshold((float)0.8); // Change this threshold as needed
var rc = new Rectangle(0, 0, image.Width, image.Height);
gr.DrawImage(image, rc, 0, 0, image.Width, image.Height, GraphicsUnit.Pixel, ia);
}
return image;
}
Tentei variedades de COLORSPACEs e BITSPERCOMPONENTs, mas sempre recebo "Dados insuficientes para uma imagem", "Memória insuficiente" ou "Existe um erro nesta página" ao tentar abrir o PDF resultante ... portanto, devo ser fazendo isto errado. Tenho certeza de que FLATEDECODE é a coisa certa a se usar.
Qualquer ajuda seria muito apreciada.