2016-08-24 26 views
2

我來到翻過以下問題嵌入透明java.awt.Image中與iText的PDF文件(試圖與2.1.7 UND 5.5.9)。iText的二進制透過錯誤

我想iText的不正確地在這種特殊情況下,從ARGB圖像轉換他們的iText圖像時處理二進制透明圖像。

當提供的圖像只包含100%和0%透明像素(即二進制透明度),並且所有像素都是黑色(即opaqe和透明像素 - 即圖像的所有像素都具有color = black,但alpha值爲0%或100%),透明像素顏色值在內部被檢測爲黑色(這在我看來是錯誤的),這導致生成的pdf中的不可見圖像。

測試用例:

import java.awt.AlphaComposite; 
import java.awt.BasicStroke; 
import java.awt.Color; 
import java.awt.Dimension; 
import java.awt.Graphics2D; 
import java.awt.RenderingHints; 
import java.awt.image.BufferedImage; 
import java.io.File; 
import java.io.FileOutputStream; 
import java.io.IOException; 
import java.net.MalformedURLException; 
import java.net.URL; 

import com.itextpdf.text.BadElementException; 
import com.itextpdf.text.Document; 
import com.itextpdf.text.DocumentException; 
import com.itextpdf.text.Image; 
import com.itextpdf.text.PageSize; 
import com.itextpdf.text.Paragraph; 
import com.itextpdf.text.pdf.PdfContentByte; 
import com.itextpdf.text.pdf.PdfWriter; 

public class BinaryTransparencyBug { 


    private static Image bkgnd; 


    public static void main(String[] args) throws Exception { 

     bkgnd = Image.getInstance(new URL("http://gitlab.itextsupport.com/itext/sandbox/raw/master/resources/images/berlin2013.jpg")); 
     bkgnd.scaleAbsolute(PageSize.A4); 
     bkgnd.setAbsolutePosition(0, 0); 


     Document document = new Document(); 
     File file = new File("target/binary_transparency_bug.pdf"); 
     FileOutputStream outputStream = new FileOutputStream(file); 
     PdfWriter writer = PdfWriter.getInstance(document, outputStream); 
     document.open(); 


     addBackground(writer); 
     document.add(new Paragraph("Binary transparency bug test case")); 
     document.add(new Paragraph("OK: Visible image (opaque pixels are red, non opaque pixels are black)")); 
     document.add(com.itextpdf.text.Image.getInstance(createBinaryTransparentAWTImage(Color.red,false,null), null)); 
     document.newPage(); 

     addBackground(writer); 
     document.add(new Paragraph("Suspected bug: invisible image (both opaque an non opaque pixels have the same color)")); 
     document.add(com.itextpdf.text.Image.getInstance(createBinaryTransparentAWTImage(Color.black,false,null), null)); 
     document.newPage(); 

     addBackground(writer); 
     document.add(new Paragraph("Analysis: Aliasing makes the problem disappear, because this way the image is not binary transparent any more")); 
     document.add(com.itextpdf.text.Image.getInstance(createBinaryTransparentAWTImage(Color.black,true,null), null)); 
     document.newPage(); 

     addBackground(writer); 
     document.add(new Paragraph("Analysis: Setting the color of the transparent pixels to anything but black makes the problem go away, too")); 
     document.add(com.itextpdf.text.Image.getInstance(createBinaryTransparentAWTImage(Color.black,false,Color.red), null)); 

     document.close(); 

    } 

    private static void addBackground(PdfWriter writer) 
      throws BadElementException, MalformedURLException, IOException, DocumentException { 
     PdfContentByte canvas = writer.getDirectContentUnder(); 
     canvas.saveState(); 
     canvas.addImage(bkgnd); 
     canvas.restoreState(); 
    } 

    // Create an ARGB AWT Image that has only 100% transparent and 0% 
    // transparent pixels. 
    // All 100% opaque pixels have the provided color "color" 
    // All transparent pixels have the Color "backgroundColor" 
    public static BufferedImage createBinaryTransparentAWTImage(Color color, boolean alias, Color backgroundColor) { 
     Dimension size = new Dimension(200, 200); 
     BufferedImage awtimg = new BufferedImage(size.width, size.height, BufferedImage.TYPE_INT_ARGB); 
     Graphics2D g2d = awtimg.createGraphics(); 

     if (backgroundColor!=null) 
     { 
      //Usually it doen't make much sense to set the color of transparent pixels... 
      //but in this case it changes the behavior of com.itextpdf.text.Image.getInstance fundamentally! 
      g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC, 0f));  
      g2d.setColor(backgroundColor); 
      g2d.fillRect(0, 0, size.width, size.height); 
     } 
     g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f)); 
     g2d.setColor(color); 
     if (alias) 
     { 
      g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); 
      g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); 
     } 

     BasicStroke bs = new BasicStroke(2); 
     g2d.setStroke(bs); 
     for (int i = 0; i < 5; i++) { 
      g2d.drawLine((size.width + 2)/4 * i, 0, (size.width + 2)/4 * i, size.height - 1); 
      g2d.drawLine(0, (size.height + 2)/4 * i, size.width - 1, (size.height + 2)/4 * i); 
     } 
     return awtimg; 
    } 
} 

回答

2

這裏是我的問題的修復建議:

在Image.getInstance(AWTImage,顏色,forcebw): 的情況下forceBW =假,顏色=空:

for (int j = 0; j < size; j++) { 
    byte alpha = smask[j] = (byte) (pixels[j] >> 24 & 0xff); 
    /* bugfix by Chris Nokleberg */ 
    if (!shades) { 
     if (alpha != 0 && alpha != -1) { 
      //as soon as there is any pixel with alpha not 0% or 100% 
      //switch to smask 
      shades = true; 
     } else if (transparency == null) { 
      //in binary transparency mode, determine the transparentPixel Color to be the 
      //value of the first Pixel we find with 100% transparency 
      if (alpha == 0) { 
       transparentPixel = pixels[j] & 0xffffff; 
       transparency = new int[6]; 
       transparency[0] = transparency[1] = transparentPixel >> 16 & 0xff; 
       transparency[2] = transparency[3] = transparentPixel >> 8 & 0xff; 
       transparency[4] = transparency[5] = transparentPixel & 0xff; 
       // vvv--- added by mkl 
       // Check whether this value for transparent pixels 
       // has already been used for a non-transparent one 
       // before this position 
       for (int jj = 0; jj < j; jj++) 
       { 
        if ((pixels[jj] & 0xffffff) == transparentPixel) 
        { 
         // found a prior use of the transparentPixel color 
         // and, therefore, cannot make use of this color 
         // for transparency; we could still use an image 
         // mask but for simplicity let's use a soft mask 
         // which already is implemented here 
         shades = true; 
         break; 
        } 
       } 
       // ^^^--- added by mkl 
      } 
     } else if (((pixels[j] & 0xffffff) != transparentPixel) && (alpha==0)) { 
      //TB: The above if seems incorrect to me. (EDIT: it was if ((pixels[j] & 0xffffff) != transparentPixel) 
      //As soon as we find any pixel that has differnt color from 
      //transparentPixel-Color and alpha 0% or 100% 
      //switch of binary transparency mode. 
      //IMHO this should only be done if alpha==0! 
      //so the if clause should be 
      //((pixels[j] & 0xffffff) != transparentPixel) && (alpha==0) 
      shades = true; 
     } 
     //TB: Proposed fix: 
     else if ((pixels[j] & 0xffffff) == transparentPixel && alpha!=0) { 
      //switch of binary transparency mode, if we find any pixel with the transparentPixel-Color, 
      //but which is not transparent 
      shades = true; 
     }      
    } 
    ... 
} 
+0

你可以提交此作爲GitHub回購拉請求?這是提交您的補丁的推薦位置。 http://github.com/itext/itextpdf –

+0

也就是說,解決方案並不完整。 – mkl

+1

在評論(!)正確地提出了'阿爾法== 0'和'阿爾法== -1'情況進行區分,但它並沒有檢查'transparentPixel'尚未使用之前* *'transparentPixel'提案被確定。 – mkl