/* * 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<Double> coords = new java.util.ArrayList<Double>(4); coords.add(startPoint.getX()); coords.add(startPoint.getY()); coords.add(endPoint.getX()); coords.add(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 focal 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<Double> coords = new java.util.ArrayList<Double>(6); coords.add(center.getX() + dx); coords.add(center.getY() + dy); coords.add(0d); coords.add(center.getX()); coords.add(center.getY()); coords.add(radius); return makeGradient(gradient, coords, baseTransform, transform); } private static Pattern makeGradient(MultipleGradientPaint gradient, List<Double> coords, AffineTransform baseTransform, AffineTransform transform) { List<Double> matrix = makeTransform(gradient, baseTransform, transform); List<Float> bounds = makeBounds(gradient); List<Function> 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<Double> makeTransform(MultipleGradientPaint gradient, AffineTransform baseTransform, AffineTransform transform) { AffineTransform gradientTransform = new AffineTransform(baseTransform); gradientTransform.concatenate(transform); gradientTransform.concatenate(gradient.getTransform()); List<Double> matrix = new ArrayList<Double>(6); double[] m = new double[6]; gradientTransform.getMatrix(m); for (double d : m) { matrix.add(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<Float> makeBounds(MultipleGradientPaint gradient) { float[] fractions = gradient.getFractions(); List<Float> bounds = new java.util.ArrayList<Float>(fractions.length); for (float offset : fractions) { if (0f < offset && offset < 1f) { bounds.add(offset); } } return bounds; } private static List<Function> makeFunctions(MultipleGradientPaint gradient) { List<Color> colors = makeColors(gradient); List<Function> functions = new ArrayList<Function>(); 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<Color> makeColors(MultipleGradientPaint gradient) { Color[] svgColors = gradient.getColors(); List<Color> gradientColors = new ArrayList<Color>(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<? extends Number> numbers) { out.append("[ "); for (Number n : numbers) { out.append(doubleFormatter.formatDouble(n.doubleValue())); out.append(" "); } out.append("]"); } }