/* * Geotoolkit - An Open Source Java GIS Toolkit * http://www.geotoolkit.org * * (C) 2011, Geomatys * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. */ package org.geotoolkit.report.graphic.map; import java.awt.AlphaComposite; import java.awt.Color; import java.awt.Composite; import java.awt.Font; import java.awt.FontMetrics; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.GraphicsConfiguration; import java.awt.Image; import java.awt.Paint; import java.awt.Rectangle; import java.awt.RenderingHints; import java.awt.RenderingHints.Key; import java.awt.Shape; import java.awt.Stroke; import java.awt.font.FontRenderContext; import java.awt.font.GlyphVector; import java.awt.geom.AffineTransform; import java.awt.image.BufferedImage; import java.awt.image.BufferedImageOp; import java.awt.image.ImageObserver; import java.awt.image.RenderedImage; import java.awt.image.renderable.RenderableImage; import java.text.AttributedCharacterIterator; import java.util.Map; import org.apache.sis.util.collection.WeakHashSet; /** * Itext has several weakness which are fixed in this encapsulation * - does not support composite alpha on image. * Here we override image paint operations. * The composite is multiply directly in the image before drawing. * - is not concurrent * * @author Johann Sorel (Geomatys) * @module */ public class PDFFixGraphics2D extends Graphics2D { private final Graphics2D wrapped; public PDFFixGraphics2D(Graphics2D wrapped) { this.wrapped = wrapped; } @Override public synchronized void draw(Shape s) { wrapped.draw(s); } @Override public synchronized void drawString(String str, int x, int y) { wrapped.drawString(str, x, y); } @Override public synchronized void drawString(String str, float x, float y) { wrapped.drawString(str, x, y); } @Override public synchronized void drawString(AttributedCharacterIterator iterator, int x, int y) { wrapped.drawString(iterator, x, y); } @Override public synchronized void drawString(AttributedCharacterIterator iterator, float x, float y) { wrapped.drawString(iterator, x, y); } @Override public synchronized void drawGlyphVector(GlyphVector g, float x, float y) { wrapped.drawGlyphVector(g, x, y); } @Override public synchronized void fill(Shape s) { wrapped.fill(s); } @Override public synchronized boolean hit(Rectangle rect, Shape s, boolean onStroke) { return wrapped.hit(rect,s,onStroke); } @Override public synchronized GraphicsConfiguration getDeviceConfiguration() { return wrapped.getDeviceConfiguration(); } @Override public synchronized void setComposite(Composite comp) { wrapped.setComposite(comp); } @Override public synchronized void setPaint(Paint paint) { wrapped.setPaint(paint); } @Override public synchronized void setStroke(Stroke s) { wrapped.setStroke(s); } @Override public synchronized void setRenderingHint(Key hintKey, Object hintValue) { wrapped.setRenderingHint(hintKey, hintValue); } @Override public synchronized Object getRenderingHint(Key hintKey) { return wrapped.getRenderingHint(hintKey); } @Override public synchronized void setRenderingHints(Map<?, ?> hints) { wrapped.setRenderingHints(hints); } @Override public synchronized void addRenderingHints(Map<?, ?> hints) { wrapped.addRenderingHints(hints); } @Override public synchronized RenderingHints getRenderingHints() { return wrapped.getRenderingHints(); } @Override public synchronized void translate(int x, int y) { wrapped.translate(x, y); } @Override public synchronized void translate(double tx, double ty) { wrapped.translate(tx, ty); } @Override public synchronized void rotate(double theta) { wrapped.rotate(theta); } @Override public synchronized void rotate(double theta, double x, double y) { wrapped.rotate(theta, x, y); } @Override public synchronized void scale(double sx, double sy) { wrapped.scale(sx, sy); } @Override public synchronized void shear(double shx, double shy) { wrapped.shear(shx, shy); } @Override public synchronized void transform(AffineTransform Tx) { wrapped.transform(Tx); } @Override public synchronized void setTransform(AffineTransform Tx) { wrapped.setTransform(Tx); } @Override public synchronized AffineTransform getTransform() { return wrapped.getTransform(); } @Override public synchronized Paint getPaint() { return wrapped.getPaint(); } @Override public synchronized Composite getComposite() { return wrapped.getComposite(); } @Override public synchronized void setBackground(Color color) { wrapped.setBackground(color); } @Override public synchronized Color getBackground() { return wrapped.getBackground(); } @Override public synchronized Stroke getStroke() { return wrapped.getStroke(); } @Override public synchronized void clip(Shape s) { wrapped.clip(s); } @Override public synchronized FontRenderContext getFontRenderContext() { return wrapped.getFontRenderContext(); } @Override public synchronized Graphics create() { final Graphics2D gr = (Graphics2D) wrapped.create(); return new PDFFixGraphics2D(gr); } @Override public synchronized Color getColor() { return wrapped.getColor(); } @Override public synchronized void setColor(Color c) { wrapped.setColor(c); } @Override public synchronized void setPaintMode() { wrapped.setPaintMode(); } @Override public synchronized void setXORMode(Color c1) { wrapped.setXORMode(c1); } @Override public synchronized Font getFont() { return wrapped.getFont(); } @Override public synchronized void setFont(Font font) { wrapped.setFont(font); } @Override public synchronized FontMetrics getFontMetrics(Font f) { return wrapped.getFontMetrics(f); } @Override public synchronized Rectangle getClipBounds() { return wrapped.getClipBounds(); } @Override public synchronized void clipRect(int x, int y, int width, int height) { wrapped.clipRect(x, y, width, height); } @Override public synchronized void setClip(int x, int y, int width, int height) { wrapped.setClip(x, y, width, height); } @Override public synchronized Shape getClip() { return wrapped.getClip(); } @Override public synchronized void setClip(Shape clip) { wrapped.setClip(clip); } @Override public synchronized void copyArea(int x, int y, int width, int height, int dx, int dy) { wrapped.copyArea(x, y, width, height, dx, dy); } @Override public synchronized void drawLine(int x1, int y1, int x2, int y2) { wrapped.drawLine(x1, y1, x2, y2); } @Override public synchronized void fillRect(int x, int y, int width, int height) { wrapped.fillRect(x, y, width, height); } @Override public synchronized void clearRect(int x, int y, int width, int height) { wrapped.clearRect(x, y, width, height); } @Override public synchronized void drawRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight) { wrapped.drawRoundRect(x, y, width, height, arcWidth, arcHeight); } @Override public synchronized void fillRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight) { wrapped.fillRoundRect(x, y, width, height, arcWidth, arcHeight); } @Override public synchronized void drawOval(int x, int y, int width, int height) { wrapped.drawOval(x, y, width, height); } @Override public synchronized void fillOval(int x, int y, int width, int height) { wrapped.fillOval(x, y, width, height); } @Override public synchronized void drawArc(int x, int y, int width, int height, int startAngle, int arcAngle) { wrapped.drawArc(x, y, width, height, startAngle, arcAngle); } @Override public synchronized void fillArc(int x, int y, int width, int height, int startAngle, int arcAngle) { wrapped.fillArc(x, y, width, height, startAngle, arcAngle); } @Override public synchronized void drawPolyline(int[] xPoints, int[] yPoints, int nPoints) { wrapped.drawPolyline(xPoints, yPoints, nPoints); } @Override public synchronized void drawPolygon(int[] xPoints, int[] yPoints, int nPoints) { wrapped.drawPolygon(xPoints, yPoints, nPoints); } @Override public synchronized void fillPolygon(int[] xPoints, int[] yPoints, int nPoints) { wrapped.fillPolygon(xPoints, yPoints, nPoints); } @Override public synchronized void drawRenderedImage(RenderedImage img, AffineTransform xform) { final BufferedImage cp = new BufferedImage(img.getWidth(), img.getHeight(), BufferedImage.TYPE_INT_ARGB); final Graphics2D g2d = cp.createGraphics(); g2d.drawRenderedImage(img, new AffineTransform()); drawImage(cp, xform, null); } @Override public synchronized void drawRenderableImage(RenderableImage img, AffineTransform xform) { wrapped.drawRenderableImage(img, xform); } @Override public synchronized boolean drawImage(Image img, AffineTransform xform, ImageObserver obs) { img = combineComposite(img); return wrapped.drawImage(img, xform, obs); } @Override public synchronized void drawImage(BufferedImage img, BufferedImageOp op, int x, int y) { img = (BufferedImage) combineComposite(img); wrapped.drawImage(img, op, x, y); } @Override public synchronized boolean drawImage(Image img, int x, int y, ImageObserver observer) { img = combineComposite(img); return wrapped.drawImage(img, x, y, observer); } @Override public synchronized boolean drawImage(Image img, int x, int y, int width, int height, ImageObserver observer) { img = combineComposite(img); return wrapped.drawImage(img, x, y, width, height, observer); } @Override public synchronized boolean drawImage(Image img, int x, int y, Color bgcolor, ImageObserver observer) { img = combineComposite(img); return wrapped.drawImage(img, x, y, bgcolor, observer); } @Override public synchronized boolean drawImage(Image img, int x, int y, int width, int height, Color bgcolor, ImageObserver observer) { img = combineComposite(img); return wrapped.drawImage(img, x, y, width, height, bgcolor, observer); } @Override public synchronized boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2, ImageObserver observer) { img = combineComposite(img); return wrapped.drawImage(img, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, observer); } @Override public synchronized boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2, Color bgcolor, ImageObserver observer) { img = combineComposite(img); return wrapped.drawImage(img, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, bgcolor, observer); } @Override public synchronized void dispose() { wrapped.dispose(); } private final WeakHashSet<BufferedImage> done = new WeakHashSet<BufferedImage>(BufferedImage.class); /** * Itext does not support composite on image. * Here we generate another image with the alpha composite already combine in the image. */ private Image combineComposite(Image img){ if(img == null || done.contains(img)){ //already done return img; } final Composite composite = this.getComposite(); if(composite instanceof AlphaComposite){ final AlphaComposite alphaComposite = (AlphaComposite) composite; if(alphaComposite.getAlpha() != 1){ final BufferedImage buffer = new BufferedImage(img.getWidth(null), img.getHeight(null), BufferedImage.TYPE_INT_ARGB); final Graphics2D g = buffer.createGraphics(); g.setComposite(alphaComposite); g.drawImage(img, 0, 0, null); g.dispose(); done.add(buffer); img = buffer; } } return img; } }