You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@pdfbox.apache.org by ti...@apache.org on 2014/05/06 18:11:01 UTC

svn commit: r1592793 - in /pdfbox/branches/1.8/pdfbox/src: main/java/org/apache/pdfbox/pdmodel/graphics/xobject/PDPixelMap.java test/java/org/apache/pdfbox/pdmodel/graphics/xobject/PDPixelMapTest.java

Author: tilman
Date: Tue May  6 16:11:01 2014
New Revision: 1592793

URL: http://svn.apache.org/r1592793
Log:
PDFBOX-2057: fix masks for TYPE_4BYTE_ABGR and TYPE_INT_ARGB, improve grayscale images, more tests

Modified:
    pdfbox/branches/1.8/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/xobject/PDPixelMap.java
    pdfbox/branches/1.8/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/graphics/xobject/PDPixelMapTest.java

Modified: pdfbox/branches/1.8/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/xobject/PDPixelMap.java
URL: http://svn.apache.org/viewvc/pdfbox/branches/1.8/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/xobject/PDPixelMap.java?rev=1592793&r1=1592792&r2=1592793&view=diff
==============================================================================
--- pdfbox/branches/1.8/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/xobject/PDPixelMap.java (original)
+++ pdfbox/branches/1.8/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/xobject/PDPixelMap.java Tue May  6 16:11:01 2014
@@ -16,21 +16,21 @@
  */
 package org.apache.pdfbox.pdmodel.graphics.xobject;
 
-import java.awt.AlphaComposite;
 import java.awt.Color;
-import java.awt.Graphics2D;
 import java.awt.Transparency;
 import java.awt.color.ColorSpace;
-import java.awt.image.ComponentColorModel;
 import java.awt.image.DataBuffer;
 import java.awt.image.DataBufferByte;
 import java.awt.image.BufferedImage;
 import java.awt.image.ColorModel;
+import java.awt.image.ComponentColorModel;
+import java.awt.image.DataBufferInt;
 import java.awt.image.IndexColorModel;
 import java.awt.image.WritableRaster;
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.OutputStream;
+import java.nio.ByteOrder;
 import javax.imageio.stream.MemoryCacheImageOutputStream;
 
 import org.apache.commons.logging.Log;
@@ -97,14 +97,14 @@ public class PDPixelMap extends PDXObjec
      * 
      * @param doc The PDF document to embed the image in.
      * @param bi The image to read data from.
-     * @param mask true if this is a mask, false if not.
+     * @param isMask true if this is a mask, false if not.
      *
      * @throws IOException If there is an error while embedding this image.
      */
-    private PDPixelMap(PDDocument doc, BufferedImage bi, boolean mask) throws IOException
+    private PDPixelMap(PDDocument doc, BufferedImage bi, boolean isMask) throws IOException
     {
         super(doc, PNG);
-        createImageStream(doc, bi, mask);
+        createImageStream(doc, bi, isMask);
     }
 
     /**
@@ -112,29 +112,68 @@ public class PDPixelMap extends PDXObjec
      * 
      * @param doc The PDF document to embed the image in.
      * @param bi The image to read data from.
-     * @param mask true if this is a mask, false if not. If true, the image
+     * @param isMask true if this is a mask, false if not. If true, the image
      * stream will be forced to be DeviceGray.
      * 
      * @throws IOException If there is an error while embedding this image.
      */
-    private void createImageStream(PDDocument doc, BufferedImage bi, boolean mask) throws IOException
+    private void createImageStream(PDDocument doc, BufferedImage bi, boolean isMask) throws IOException
     {
         BufferedImage alphaImage = null;
-        BufferedImage rgbImage = null;
+        BufferedImage rgbImage;
         int width = bi.getWidth();
         int height = bi.getHeight();
         if (bi.getColorModel().hasAlpha())
         {
             // extract the alpha information
             WritableRaster alphaRaster = bi.getAlphaRaster();
-            ColorModel cm = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_GRAY), 
-                    false, false, Transparency.OPAQUE, DataBuffer.TYPE_BYTE);
-            alphaImage = new BufferedImage(cm, alphaRaster, false, null);
-            // create a RGB image without alpha
+            DataBuffer dbSrc = alphaRaster.getDataBuffer();
+            if (dbSrc instanceof DataBufferInt)
+            {
+                // PDFBOX-2057, handle TYPE_INT_A... types
+                // See also
+                // http://bugs.java.com/bugdatabase/view_bug.do?bug_id=4243485
+
+                alphaImage = new BufferedImage(width, height, BufferedImage.TYPE_BYTE_GRAY);
+                DataBuffer dbDst = alphaImage.getRaster().getDataBuffer();
+                // alpha value is in the highest byte
+                for (int i = 0; i < dbSrc.getSize(); ++i)
+                {
+                    dbDst.setElem(i, dbSrc.getElem(i) >>> 24);
+                }
+            }
+            else if (dbSrc instanceof DataBufferByte)
+            {
+                alphaImage = new BufferedImage(width, height, BufferedImage.TYPE_BYTE_GRAY);
+                DataBuffer dbDst = alphaImage.getRaster().getDataBuffer();
+                // alpha value is at bytes 0...4...8...
+                for (int i = 0; i < dbDst.getSize(); ++i)
+                {
+                    dbDst.setElem(i, dbSrc.getElem(i << 2));
+                }
+            }
+            else
+            {
+                // fallback to old solution. 
+                // This didn't work for INT types, see PDFBOX-2057.
+                ColorModel cm = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_GRAY),
+                        false, false, Transparency.OPAQUE, DataBuffer.TYPE_BYTE);
+                alphaImage = new BufferedImage(cm, alphaRaster, false, null);
+            }
+
+            // create RGB image without alpha
+            //BEWARE: the previous solution in the history 
+            // g.setComposite(AlphaComposite.Src) and g.drawImage()
+            // didn't work properly for TYPE_4BYTE_ABGR.
+            // alpha values of 0 result in a black dest pixel!!!
             rgbImage = new BufferedImage(width, height, BufferedImage.TYPE_3BYTE_BGR);
-            Graphics2D g = rgbImage.createGraphics();
-            g.setComposite(AlphaComposite.Src);
-            g.drawImage(bi, 0, 0, null);
+            for (int x = 0; x < width; ++x)
+            {
+                for (int y = 0; y < height; ++y)
+                {
+                    rgbImage.setRGB(x, y, bi.getRGB(x, y) & 0xFFFFFF);
+                }
+            }
         }
         else
         {
@@ -148,35 +187,55 @@ public class PDPixelMap extends PDXObjec
             {
                 throw new IllegalStateException();
             }
- 
+
             int bpc;
-            ByteArrayOutputStream bos = new ByteArrayOutputStream();
 
-            //TODO: activate this when DeviceGray tests work
-//            if (((mask || bi.getType() == BufferedImage.TYPE_BYTE_GRAY) ||
-//                    || bi.getType() == BufferedImage.TYPE_BYTE_BINARY)
-//                    && bi.getColorModel().getPixelSize() <= 8)
-            if (mask || // PDFBOX-2057 force masks to be gray
-                    (bi.getType() == BufferedImage.TYPE_BYTE_BINARY
-                    && bi.getColorModel().getPixelSize() <= 8))
+            // use FlateDecode compression
+            getPDStream().addCompression();
+            os = getCOSStream().createUnfilteredStream();
+
+            if (((isMask
+                    || bi.getType() == BufferedImage.TYPE_BYTE_GRAY)
+                    || bi.getType() == BufferedImage.TYPE_BYTE_BINARY)
+                    && bi.getColorModel().getPixelSize() <= 8)
             {
                 setColorSpace(new PDDeviceGray());
-                MemoryCacheImageOutputStream mcios = new MemoryCacheImageOutputStream(bos);
-
-                // grayscale images need one color per sample
-                bpc = bi.getColorModel().getPixelSize();
                 int h = rgbImage.getHeight();
                 int w = rgbImage.getWidth();
-                for (int y = 0; y < h; ++y)
+                bpc = bi.getColorModel().getPixelSize();
+                if (bpc < 8)
                 {
-                    for (int x = 0; x < w; ++x)
+                    MemoryCacheImageOutputStream mcios = new MemoryCacheImageOutputStream(os);
+                    for (int y = 0; y < h; ++y)
+                    {
+                        for (int x = 0; x < w; ++x)
+                        {
+                            // grayscale images need one color per sample
+                            mcios.writeBits(bi.getRGB(x, y) & 0xFF, bpc);
+                        }
+                    }
+                    // padding
+                    while (mcios.getBitOffset() != 0)
                     {
-                        mcios.writeBits(rgbImage.getRGB(x, y), bpc);
+                        mcios.writeBit(0);
+                    }
+                    mcios.flush();
+                    mcios.close();
+                }
+                else
+                {
+                    //BEWARE: the gray values must be extracted from raster
+                    // and not from getRGB or the TYPE_BYTE_GRAY tests will fail
+                    DataBuffer dataBuffer = rgbImage.getData().getDataBuffer();
+                    for (int y = 0; y < h; ++y)
+                    {
+                        for (int x = 0; x < w; ++x)
+                        {
+                            // grayscale images need one color per sample
+                            os.write(dataBuffer.getElem(y * w + x));
+                        }
                     }
                 }
-                mcios.writeBits(0, 7); // padding
-                mcios.flush();
-                mcios.close();
             }
             else
             {
@@ -189,31 +248,26 @@ public class PDPixelMap extends PDXObjec
                 {
                     for (int x = 0; x < w; ++x)
                     {
+                        // rgb images need three colors per sample
                         Color color = new Color(rgbImage.getRGB(x, y));
-                        bos.write(color.getRed());
-                        bos.write(color.getGreen());
-                        bos.write(color.getBlue());
+                        os.write(color.getRed());
+                        os.write(color.getGreen());
+                        os.write(color.getBlue());
                     }
                 }
-            }           
-            
-            // add FlateDecode compression
-            getPDStream().addCompression();
-            os = getCOSStream().createUnfilteredStream();
-            os.write(bos.toByteArray());
-            
+            }
             COSDictionary dic = getCOSStream();
-            dic.setItem( COSName.FILTER, COSName.FLATE_DECODE );
-            dic.setItem( COSName.SUBTYPE, COSName.IMAGE);
-            dic.setItem( COSName.TYPE, COSName.XOBJECT );
-            if(alphaImage != null)
+            dic.setItem(COSName.FILTER, COSName.FLATE_DECODE);
+            dic.setItem(COSName.SUBTYPE, COSName.IMAGE);
+            dic.setItem(COSName.TYPE, COSName.XOBJECT);
+            if (alphaImage != null)
             {
                 PDPixelMap smask = new PDPixelMap(doc, alphaImage, true);
                 dic.setItem(COSName.SMASK, smask);
             }
-            setBitsPerComponent( bpc );
-            setHeight( height );
-            setWidth( width );
+            setBitsPerComponent(bpc);
+            setHeight(height);
+            setWidth(width);
         }
         finally
         {

Modified: pdfbox/branches/1.8/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/graphics/xobject/PDPixelMapTest.java
URL: http://svn.apache.org/viewvc/pdfbox/branches/1.8/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/graphics/xobject/PDPixelMapTest.java?rev=1592793&r1=1592792&r2=1592793&view=diff
==============================================================================
--- pdfbox/branches/1.8/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/graphics/xobject/PDPixelMapTest.java (original)
+++ pdfbox/branches/1.8/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/graphics/xobject/PDPixelMapTest.java Tue May  6 16:11:01 2014
@@ -13,14 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
 package org.apache.pdfbox.pdmodel.graphics.xobject;
 
 import java.awt.Color;
 import java.awt.Graphics;
 import java.awt.image.BufferedImage;
 import java.io.File;
+import java.io.FileInputStream;
 import java.io.IOException;
+import java.net.URL;
 import javax.imageio.ImageIO;
 import junit.framework.TestCase;
 import org.apache.pdfbox.exceptions.COSVisitorException;
@@ -37,7 +38,7 @@ import org.apache.pdfbox.util.ImageIOUti
  */
 public class PDPixelMapTest extends TestCase
 {
-    private final File testResultsDir = new File("target/test-output");
+    private final File testResultsDir = new File("target/test-output/graphics");
 
     @Override
     protected void setUp() throws Exception
@@ -57,7 +58,7 @@ public class PDPixelMapTest extends Test
         BufferedImage image = ImageIO.read(this.getClass().getResourceAsStream("png.png"));
 
         PDXObjectImage ximage = new PDPixelMap(document, image);
-        validate(ximage, 8, 344, 287, "png", PDDeviceRGB.NAME);
+        validate(ximage, 8, image.getWidth(), image.getHeight(), "png", PDDeviceRGB.NAME);
         checkIdent(image, ximage.getRGBImage());
 
         // Create a grayscale image
@@ -67,7 +68,7 @@ public class PDPixelMapTest extends Test
         g.dispose();
 
         ximage = new PDPixelMap(document, grayImage);
-        validate(ximage, 8, 344, 287, "png", PDDeviceRGB.NAME);
+        validate(ximage, 8, grayImage.getWidth(), grayImage.getHeight(), "png", PDDeviceGray.NAME);
         checkIdent(grayImage, ximage.getRGBImage());
 
         // Create a bitonal image
@@ -78,7 +79,28 @@ public class PDPixelMapTest extends Test
 
         ximage = new PDPixelMap(document, bitonalImage);
         checkIdent(bitonalImage, ximage.getRGBImage());
-        validate(ximage, 1, 344, 287, "png", PDDeviceGray.NAME);
+        validate(ximage, 1, bitonalImage.getWidth(), bitonalImage.getHeight(), "png", PDDeviceGray.NAME);
+        document.close();
+    }
+
+    public void testCreateLosslessFromImageGray() throws IOException
+    {
+        PDDocument document = new PDDocument();
+        BufferedImage image = new BufferedImage(256, 256, BufferedImage.TYPE_BYTE_GRAY);
+        int w = image.getWidth();
+        int h = image.getHeight();
+        for (int x = 0; x < w; ++x)
+        {
+            for (int y = 0; y < h; ++y)
+            {
+                int color = ((x + y) / 2) & 0xFF;
+                color += (color << 8) + (color << 16);
+                image.setRGB(x, y, color);
+            }
+        }
+        PDXObjectImage ximage = new PDPixelMap(document, image);
+        validate(ximage, 8, w, h, "png", PDDeviceGray.NAME);
+        checkIdent(image, ximage.getRGBImage());
         document.close();
     }
 
@@ -94,7 +116,7 @@ public class PDPixelMapTest extends Test
 
         PDXObjectImage ximage = new PDPixelMap(document, imageFromBitonalGif);
         checkIdent(imageFromBitonalGif, ximage.getRGBImage());
-        validate(ximage, 1, 344, 287, "png", PDDeviceGray.NAME);
+        validate(ximage, 1, imageFromBitonalGif.getWidth(), imageFromBitonalGif.getHeight(), "png", PDDeviceGray.NAME);
         document.close();
     }
 
@@ -102,29 +124,24 @@ public class PDPixelMapTest extends Test
      * Tests RGB PDPixelMapTest() with TYPE_4BYTE_ABGR image.
      *
      * @throws java.io.IOException
+     * @throws org.apache.pdfbox.exceptions.COSVisitorException
      */
     public void testCreateLossless4BYTE_ABGR() throws IOException, COSVisitorException
     {
         PDDocument document = new PDDocument();
-        BufferedImage awtImage = new BufferedImage(300, 300, BufferedImage.TYPE_4BYTE_ABGR);
+        BufferedImage awtImage = createInterestingImage(BufferedImage.TYPE_4BYTE_ABGR);
 
-        // draw something
-        Graphics g = awtImage.getGraphics();
-        g.setColor(Color.blue);
-        g.fillRect(0, 0, 100, 300);
-        g.setColor(Color.white);
-        g.fillRect(100, 0, 100, 300);
-        g.setColor(Color.red);
-        g.fillRect(200, 0, 100, 300);
-        g.setColor(Color.black);
-        g.drawRect(0, 0, 299, 299);
-        g.dispose();
+        for (int x = 0; x < awtImage.getWidth(); ++x)
+        {
+            for (int y = 0; y < awtImage.getHeight(); ++y)
+            {
+                awtImage.setRGB(x, y, (awtImage.getRGB(x, y) & 0xFFFFFF) | ((y / 10 * 10) << 24));
+            }
+        }
 
         PDPixelMap ximage = new PDPixelMap(document, awtImage);
-        validate(ximage, 8, 300, 300, "png", PDDeviceRGB.NAME);
-        validate(ximage.getSMaskImage(), 8, 300, 300, "png", PDDeviceGray.NAME);
-        assertEquals(ximage.getColorSpace().getName(), PDDeviceRGB.NAME);
-        assertEquals(ximage.getSMaskImage().getColorSpace().getName(), PDDeviceGray.NAME);
+        validate(ximage, 8, awtImage.getWidth(), awtImage.getHeight(), "png", PDDeviceRGB.NAME);
+        validate(ximage.getSMaskImage(), 8, awtImage.getWidth(), awtImage.getHeight(), "png", PDDeviceGray.NAME);
         checkIdent(awtImage, ximage.getRGBImage());
 
         // This part isn't really needed because this test doesn't break
@@ -132,8 +149,9 @@ public class PDPixelMapTest extends Test
         // if something goes wrong in the future and we want to have a PDF to open.
         PDPage page = new PDPage();
         document.addPage(page);
-        PDPageContentStream contentStream = new PDPageContentStream(document, page);
+        PDPageContentStream contentStream = new PDPageContentStream(document, page, true, false);
         contentStream.drawXObject(ximage, 150, 300, ximage.getWidth(), ximage.getHeight());
+        contentStream.drawXObject(ximage, 200, 350, ximage.getWidth(), ximage.getHeight());
         contentStream.close();
         File pdfFile = new File(testResultsDir, "4babgr.pdf");
         document.save(pdfFile);
@@ -143,6 +161,110 @@ public class PDPixelMapTest extends Test
     }
 
     /**
+     * Tests RGB PDPixelMapTest() with TYPE_INT_ARGB image.
+     *
+     * @throws java.io.IOException
+     * @throws org.apache.pdfbox.exceptions.COSVisitorException
+     */
+    public void testCreateLosslessINT_ARGB() throws IOException, COSVisitorException
+    {
+        PDDocument document = new PDDocument();
+        BufferedImage awtImage = createInterestingImage(BufferedImage.TYPE_INT_ARGB);
+
+        for (int x = 0; x < awtImage.getWidth(); ++x)
+        {
+            for (int y = 0; y < awtImage.getHeight(); ++y)
+            {
+                awtImage.setRGB(x, y, (awtImage.getRGB(x, y) & 0xFFFFFF) | ((y / 10 * 10) << 24));
+            }
+        }
+
+        PDPixelMap ximage = new PDPixelMap(document, awtImage);
+        validate(ximage, 8, awtImage.getWidth(), awtImage.getHeight(), "png", PDDeviceRGB.NAME);
+        validate(ximage.getSMaskImage(), 8, awtImage.getWidth(), awtImage.getHeight(), "png", PDDeviceGray.NAME);
+        checkIdent(awtImage, ximage.getRGBImage());
+
+        // This part isn't really needed because this test doesn't break
+        // if the mask has the wrong colorspace (PDFBOX-2057), but it is still useful
+        // if something goes wrong in the future and we want to have a PDF to open.
+        PDPage page = new PDPage();
+        document.addPage(page);
+        PDPageContentStream contentStream = new PDPageContentStream(document, page, true, false);
+        contentStream.drawXObject(ximage, 150, 300, ximage.getWidth(), ximage.getHeight());
+        contentStream.drawXObject(ximage, 200, 350, ximage.getWidth(), ximage.getHeight());
+        contentStream.close();
+        File pdfFile = new File(testResultsDir, "intargb.pdf");
+        document.save(pdfFile);
+        document.close();
+        document = PDDocument.loadNonSeq(pdfFile, null);
+        document.close();
+    }
+
+    /**
+     * Tests RGB PDPixelMapTest() with TYPE_INT_RGB image.
+     *
+     * @throws java.io.IOException
+     * @throws org.apache.pdfbox.exceptions.COSVisitorException
+     */
+    public void testCreateLosslessINT_RGB() throws IOException, COSVisitorException
+    {
+        PDDocument document = new PDDocument();
+        BufferedImage awtImage = createInterestingImage(BufferedImage.TYPE_INT_RGB);
+
+        PDPixelMap ximage = new PDPixelMap(document, awtImage);
+        validate(ximage, 8, awtImage.getWidth(), awtImage.getHeight(), "png", PDDeviceRGB.NAME);
+        assertNull(ximage.getSMaskImage());
+        checkIdent(awtImage, ximage.getRGBImage());
+
+        // This part isn't really needed because this test doesn't break
+        // if the mask has the wrong colorspace (PDFBOX-2057), but it is still useful
+        // if something goes wrong in the future and we want to have a PDF to open.
+        PDPage page = new PDPage();
+        document.addPage(page);
+        PDPageContentStream contentStream = new PDPageContentStream(document, page, true, false);
+        contentStream.drawXObject(ximage, 150, 300, ximage.getWidth(), ximage.getHeight());
+        contentStream.drawXObject(ximage, 200, 350, ximage.getWidth(), ximage.getHeight());
+        contentStream.close();
+        File pdfFile = new File(testResultsDir, "intrgb.pdf");
+        document.save(pdfFile);
+        document.close();
+        document = PDDocument.loadNonSeq(pdfFile, null);
+        document.close();
+    }
+
+    /**
+     * Tests RGB PDPixelMapTest() with TYPE_INT_BGR image.
+     *
+     * @throws java.io.IOException
+     * @throws org.apache.pdfbox.exceptions.COSVisitorException
+     */
+    public void testCreateLosslessINT_BGR() throws IOException, COSVisitorException
+    {
+        PDDocument document = new PDDocument();
+        BufferedImage awtImage = createInterestingImage(BufferedImage.TYPE_INT_BGR);
+
+        PDPixelMap ximage = new PDPixelMap(document, awtImage);
+        validate(ximage, 8, awtImage.getWidth(), awtImage.getHeight(), "png", PDDeviceRGB.NAME);
+        assertNull(ximage.getSMaskImage());
+        checkIdent(awtImage, ximage.getRGBImage());
+
+        // This part isn't really needed because this test doesn't break
+        // if the mask has the wrong colorspace (PDFBOX-2057), but it is still useful
+        // if something goes wrong in the future and we want to have a PDF to open.
+        PDPage page = new PDPage();
+        document.addPage(page);
+        PDPageContentStream contentStream = new PDPageContentStream(document, page, true, false);
+        contentStream.drawXObject(ximage, 150, 300, ximage.getWidth(), ximage.getHeight());
+        contentStream.drawXObject(ximage, 200, 350, ximage.getWidth(), ximage.getHeight());
+        contentStream.close();
+        File pdfFile = new File(testResultsDir, "intbgr.pdf");
+        document.save(pdfFile);
+        document.close();
+        document = PDDocument.loadNonSeq(pdfFile, null);
+        document.close();
+    }
+    
+    /**
      * Tests RGB PDPixelMapTest() with image from a color GIF
      *
      * @throws java.io.IOException
@@ -202,4 +324,21 @@ public class PDPixelMapTest extends Test
             }
         }
     }
+
+    private BufferedImage createInterestingImage(int type)
+    {
+        BufferedImage awtImage = new BufferedImage(256, 256, type);
+        Graphics g = awtImage.getGraphics();
+        g.setColor(Color.blue);
+        g.fillRect(0, 0, awtImage.getWidth() / 3, awtImage.getHeight() - 1);
+        g.setColor(Color.white);
+        g.fillRect(awtImage.getWidth() / 3, 0, awtImage.getWidth() / 3, awtImage.getHeight() - 1);
+        g.setColor(Color.red);
+        g.fillRect(awtImage.getWidth() / 3 * 2, 0, awtImage.getWidth() / 3, awtImage.getHeight() - 1);
+        g.setColor(Color.black);
+        g.drawRect(0, 0, awtImage.getWidth() - 1, awtImage.getHeight() - 1);
+        g.dispose();
+        return awtImage;
+    }
+
 }