美文网首页
iText读取pdf中cmyk图片,颜色反转问题

iText读取pdf中cmyk图片,颜色反转问题

作者: 叶迎宪 | 来源:发表于2024-05-08 12:06 被阅读0次

    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阅读器也把图片反转了。

    相关文章

      网友评论

          本文标题:iText读取pdf中cmyk图片,颜色反转问题

          本文链接:https://www.haomeiwen.com/subject/jyidfjtx.html