pdf中的cmyk图片,提取出来,保存成文件,看到颜色是反转的
PdfImageXObject image
MemoryStream memoryStream = new MemoryStream(image.GetImageBytes());
using (BinaryWriter writer = new BinaryWriter(File.OpenWrite("1.jpg")))
{
writer.Write(memoryStream.ToArray());
}
可以确定这个pdf中的cmyk图片是jpg的,因为pdf中object的filter是DCTDecode
可是神奇的是,如果把这个图片的数据,重新放回pdf中,pdf里面看到的也是反转颜色的了
using (MagickImage origBitmap = new MagickImage(memoryStream))
{
if (origBitmap.ColorSpace == ColorSpace.CMYK)
{
int width = origBitmap.Width;
int height = origBitmap.Height;
var pixels = origBitmap.GetPixels();
byte[] raw = pixels.GetValues();
ImageData imageData = ImageDataFactory.Create(width, height, 4, 8, raw, null);
PdfImageXObject imageXObject = new PdfImageXObject(imageData);
var imgObj = imageXObject.GetPdfObject();
xObjects.Put(pdfName, imgObj);
}
对比了一下,修改后的pdf文件大了一些,主要是图片的filter变成了FlateDecode,就是从jpg格式变成png格式了。如果还是把图片保存成jpg呢?
using (MagickImage origBitmap = new MagickImage(memoryStream))
{
if (origBitmap.ColorSpace == ColorSpace.CMYK)
{
int width = origBitmap.Width;
int height = origBitmap.Height;
var stream = new MemoryStream();
origBitmap.Write(stream); // 保存回cmyk的jpg
ImageData imageData = ImageDataFactory.Create(stream.ToArray());
PdfImageXObject imageXObject = new PdfImageXObject(imageData);
var imgObj = imageXObject.GetPdfObject();
xObjects.Put(pdfName, imgObj);
}
pdf文件大小相差不大了,可是图片依然是颜色反转的!仔细的对比前后的pdf文件,发现颜色反转的pdf,其图片属性为
<</BitsPerComponent 8/ColorSpace/DeviceCMYK/Decode[1 0 1 0 1 0 1 0]/Filter/DCTDecode/Height 123/Length 3901/Subtype/Image/Type/XObject/Width 166>>
对比之前多出来一行/Decode[1 0 1 0 1 0 1 0]。如果去掉Decode这个属性
imageXObjectStream.Remove(PdfName.Decode);
则pdf中图片颜色终于变成正常了。通过搜索得到的答案
https://graphicdesign.stackexchange.com/questions/12894/cmyk-jpegs-extracted-from-pdf-appear-inverted
https://gitlab.freedesktop.org/cairo/cairo/-/issues/156
原始pdf中,cmyk jpg图片不带/Decode参数。pdf中看到是白底。jpg图片的原始数据也是白底的。
直接把 /DCTDecode 那部分内容保存成jpg,用任何软件看都是黑底。jpg中带有adobe扩展的AppE。即使修改jpg中的AppE部分,去掉Adobe字样或者改AppE段名,依然是黑底。所有的看图软件都默认cmyk的jpeg是反转的。MagickImage也是默认cmyk的jpeg是反转的,解码出来的数据也变成了黑底,但是黑底数据送进去编码又变回白底jpg数据。
itext在加载jpeg时,看到有AppE标识,就认为是反转的,因此加入了decode参数组
itext7\itext.io\itext\io\image\JpegImageHelper.cs
ProcessParameters(Stream jpegStream, String errorID, ImageData image) 中
if (marker == M_APPE) {
len = GetShort(jpegStream) - 2;
byte[] byteappe = new byte[len];
for (int k = 0; k < len; ++k) {
byteappe[k] = (byte)jpegStream.Read();
}
if (byteappe.Length >= 12) {
String appe = iText.Commons.Utils.JavaUtil.GetStringForBytes(byteappe, 0, 5, "ISO-8859-1");
if (appe.Equals("Adobe")) {
image.SetInverted(true);
}
}
UpdateAttributes(ImageData image) 中
if (colorComponents != 1 && colorComponents != 3 && image.IsInverted()) {
image.decode = new float[] { 1, 0, 1, 0, 1, 0, 1, 0 };
}
因为itext多加了一组decode参数进去,让pdf阅读器也把图片反转了。
网友评论