/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* $Id$ */ package org.apache.fop.render.gradient; import java.awt.Color; import java.awt.geom.AffineTransform; import java.awt.geom.Point2D; import java.util.ArrayList; import java.util.List; import org.apache.batik.ext.awt.LinearGradientPaint; import org.apache.batik.ext.awt.MultipleGradientPaint; import org.apache.batik.ext.awt.RadialGradientPaint; import org.apache.xmlgraphics.java2d.color.ColorUtil; import org.apache.fop.pdf.PDFDeviceColorSpace; public final class GradientMaker { public interface DoubleFormatter { String formatDouble(double d); } private GradientMaker() { } public static Pattern makeLinearGradient(LinearGradientPaint gp, AffineTransform baseTransform, AffineTransform transform) { Point2D startPoint = gp.getStartPoint(); Point2D endPoint = gp.getEndPoint(); List coords = new java.util.ArrayList(4); coords.add(Double.valueOf(startPoint.getX())); coords.add(Double.valueOf(startPoint.getY())); coords.add(Double.valueOf(endPoint.getX())); coords.add(Double.valueOf(endPoint.getY())); return makeGradient(gp, coords, baseTransform, transform); } public static Pattern makeRadialGradient(RadialGradientPaint gradient, AffineTransform baseTransform, AffineTransform transform) { double radius = gradient.getRadius(); Point2D center = gradient.getCenterPoint(); Point2D focus = gradient.getFocusPoint(); double dx = focus.getX() - center.getX(); double dy = focus.getY() - center.getY(); double d = Math.sqrt(dx * dx + dy * dy); if (d > radius) { // The center point must be within the circle with // radius radius centered at center so limit it to that. double scale = (radius * .9999) / d; dx *= scale; dy *= scale; } List coords = new java.util.ArrayList(6); coords.add(Double.valueOf(center.getX() + dx)); coords.add(Double.valueOf(center.getY() + dy)); coords.add(Double.valueOf(0)); coords.add(Double.valueOf(center.getX())); coords.add(Double.valueOf(center.getY())); coords.add(Double.valueOf(radius)); return makeGradient(gradient, coords, baseTransform, transform); } private static Pattern makeGradient(MultipleGradientPaint gradient, List coords, AffineTransform baseTransform, AffineTransform transform) { List matrix = makeTransform(gradient, baseTransform, transform); List bounds = makeBounds(gradient); List functions = makeFunctions(gradient); // Gradients are currently restricted to sRGB PDFDeviceColorSpace colorSpace = new PDFDeviceColorSpace(PDFDeviceColorSpace.DEVICE_RGB); Function function = new Function(null, null, functions, bounds, null); int shadingType = gradient instanceof LinearGradientPaint ? 2 : 3; Shading shading = new Shading(shadingType, colorSpace, coords, function); return new Pattern(2, shading, matrix); } private static List makeTransform(MultipleGradientPaint gradient, AffineTransform baseTransform, AffineTransform transform) { AffineTransform gradientTransform = new AffineTransform(baseTransform); gradientTransform.concatenate(transform); gradientTransform.concatenate(gradient.getTransform()); List matrix = new ArrayList(6); double[] m = new double[6]; gradientTransform.getMatrix(m); for (double d : m) { matrix.add(Double.valueOf(d)); } return matrix; } private static Color getsRGBColor(Color c) { // Color space must be consistent, so convert to sRGB if necessary // TODO really? return c.getColorSpace().isCS_sRGB() ? c : ColorUtil.toSRGBColor(c); } private static List makeBounds(MultipleGradientPaint gradient) { float[] fractions = gradient.getFractions(); List bounds = new java.util.ArrayList(fractions.length); for (float offset : fractions) { if (0f < offset && offset < 1f) { bounds.add(offset); } } return bounds; } private static List makeFunctions(MultipleGradientPaint gradient) { List colors = makeColors(gradient); List functions = new ArrayList(); for (int currentPosition = 0, lastPosition = colors.size() - 1; currentPosition < lastPosition; currentPosition++) { Color currentColor = colors.get(currentPosition); Color nextColor = colors.get(currentPosition + 1); float[] c0 = currentColor.getColorComponents(null); float[] c1 = nextColor.getColorComponents(null); Function function = new Function(null, null, c0, c1, 1.0); functions.add(function); } return functions; } private static List makeColors(MultipleGradientPaint gradient) { Color[] svgColors = gradient.getColors(); List gradientColors = new ArrayList(svgColors.length + 2); float[] fractions = gradient.getFractions(); if (fractions[0] > 0f) { gradientColors.add(getsRGBColor(svgColors[0])); } for (Color c : svgColors) { gradientColors.add(getsRGBColor(c)); } if (fractions[fractions.length - 1] < 1f) { gradientColors.add(getsRGBColor(svgColors[svgColors.length - 1])); } return gradientColors; } static void outputDoubles(StringBuilder out, DoubleFormatter doubleFormatter, List numbers) { out.append("[ "); for (Number n : numbers) { out.append(doubleFormatter.formatDouble(n.doubleValue())); out.append(" "); } out.append("]"); } }