001/* 002 * $Id: PdfShading.java 4784 2011-03-15 08:33:00Z blowagie $ 003 * 004 * This file is part of the iText (R) project. 005 * Copyright (c) 1998-2011 1T3XT BVBA 006 * Authors: Bruno Lowagie, Paulo Soares, et al. 007 * 008 * This program is free software; you can redistribute it and/or modify 009 * it under the terms of the GNU Affero General Public License version 3 010 * as published by the Free Software Foundation with the addition of the 011 * following permission added to Section 15 as permitted in Section 7(a): 012 * FOR ANY PART OF THE COVERED WORK IN WHICH THE COPYRIGHT IS OWNED BY 1T3XT, 013 * 1T3XT DISCLAIMS THE WARRANTY OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. 014 * 015 * This program is distributed in the hope that it will be useful, but 016 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 017 * or FITNESS FOR A PARTICULAR PURPOSE. 018 * See the GNU Affero General Public License for more details. 019 * You should have received a copy of the GNU Affero General Public License 020 * along with this program; if not, see http://www.gnu.org/licenses or write to 021 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 022 * Boston, MA, 02110-1301 USA, or download the license from the following URL: 023 * http://itextpdf.com/terms-of-use/ 024 * 025 * The interactive user interfaces in modified source and object code versions 026 * of this program must display Appropriate Legal Notices, as required under 027 * Section 5 of the GNU Affero General Public License. 028 * 029 * In accordance with Section 7(b) of the GNU Affero General Public License, 030 * a covered work must retain the producer line in every PDF that is created 031 * or manipulated using iText. 032 * 033 * You can be released from the requirements of the license by purchasing 034 * a commercial license. Buying such a license is mandatory as soon as you 035 * develop commercial activities involving the iText software without 036 * disclosing the source code of your own applications. 037 * These activities include: offering paid services to customers as an ASP, 038 * serving PDFs on the fly in a web application, shipping iText with a closed 039 * source product. 040 * 041 * For more information, please contact iText Software Corp. at this 042 * address: sales@itextpdf.com 043 */ 044package com.itextpdf.text.pdf; 045 046import java.io.IOException; 047import com.itextpdf.text.error_messages.MessageLocalization; 048import com.itextpdf.text.BaseColor; 049/** Implements the shading dictionary (or stream). 050 * 051 * @author Paulo Soares 052 */ 053public class PdfShading { 054 055 protected PdfDictionary shading; 056 057 protected PdfWriter writer; 058 059 protected int shadingType; 060 061 protected ColorDetails colorDetails; 062 063 protected PdfName shadingName; 064 065 protected PdfIndirectReference shadingReference; 066 067 private BaseColor cspace; 068 069 /** Holds value of property bBox. */ 070 protected float[] bBox; 071 072 /** Holds value of property antiAlias. */ 073 protected boolean antiAlias = false; 074 075 /** Creates new PdfShading */ 076 protected PdfShading(PdfWriter writer) { 077 this.writer = writer; 078 } 079 080 protected void setColorSpace(BaseColor color) { 081 cspace = color; 082 int type = ExtendedColor.getType(color); 083 PdfObject colorSpace = null; 084 switch (type) { 085 case ExtendedColor.TYPE_GRAY: { 086 colorSpace = PdfName.DEVICEGRAY; 087 break; 088 } 089 case ExtendedColor.TYPE_CMYK: { 090 colorSpace = PdfName.DEVICECMYK; 091 break; 092 } 093 case ExtendedColor.TYPE_SEPARATION: { 094 SpotColor spot = (SpotColor)color; 095 colorDetails = writer.addSimple(spot.getPdfSpotColor()); 096 colorSpace = colorDetails.getIndirectReference(); 097 break; 098 } 099 case ExtendedColor.TYPE_PATTERN: 100 case ExtendedColor.TYPE_SHADING: { 101 throwColorSpaceError(); 102 } 103 default: 104 colorSpace = PdfName.DEVICERGB; 105 break; 106 } 107 shading.put(PdfName.COLORSPACE, colorSpace); 108 } 109 110 public BaseColor getColorSpace() { 111 return cspace; 112 } 113 114 public static void throwColorSpaceError() { 115 throw new IllegalArgumentException(MessageLocalization.getComposedMessage("a.tiling.or.shading.pattern.cannot.be.used.as.a.color.space.in.a.shading.pattern")); 116 } 117 118 public static void checkCompatibleColors(BaseColor c1, BaseColor c2) { 119 int type1 = ExtendedColor.getType(c1); 120 int type2 = ExtendedColor.getType(c2); 121 if (type1 != type2) 122 throw new IllegalArgumentException(MessageLocalization.getComposedMessage("both.colors.must.be.of.the.same.type")); 123 if (type1 == ExtendedColor.TYPE_SEPARATION && ((SpotColor)c1).getPdfSpotColor() != ((SpotColor)c2).getPdfSpotColor()) 124 throw new IllegalArgumentException(MessageLocalization.getComposedMessage("the.spot.color.must.be.the.same.only.the.tint.can.vary")); 125 if (type1 == ExtendedColor.TYPE_PATTERN || type1 == ExtendedColor.TYPE_SHADING) 126 throwColorSpaceError(); 127 } 128 129 public static float[] getColorArray(BaseColor color) { 130 int type = ExtendedColor.getType(color); 131 switch (type) { 132 case ExtendedColor.TYPE_GRAY: { 133 return new float[]{((GrayColor)color).getGray()}; 134 } 135 case ExtendedColor.TYPE_CMYK: { 136 CMYKColor cmyk = (CMYKColor)color; 137 return new float[]{cmyk.getCyan(), cmyk.getMagenta(), cmyk.getYellow(), cmyk.getBlack()}; 138 } 139 case ExtendedColor.TYPE_SEPARATION: { 140 return new float[]{((SpotColor)color).getTint()}; 141 } 142 case ExtendedColor.TYPE_RGB: { 143 return new float[]{color.getRed() / 255f, color.getGreen() / 255f, color.getBlue() / 255f}; 144 } 145 } 146 throwColorSpaceError(); 147 return null; 148 } 149 150 public static PdfShading type1(PdfWriter writer, BaseColor colorSpace, float domain[], float tMatrix[], PdfFunction function) { 151 PdfShading sp = new PdfShading(writer); 152 sp.shading = new PdfDictionary(); 153 sp.shadingType = 1; 154 sp.shading.put(PdfName.SHADINGTYPE, new PdfNumber(sp.shadingType)); 155 sp.setColorSpace(colorSpace); 156 if (domain != null) 157 sp.shading.put(PdfName.DOMAIN, new PdfArray(domain)); 158 if (tMatrix != null) 159 sp.shading.put(PdfName.MATRIX, new PdfArray(tMatrix)); 160 sp.shading.put(PdfName.FUNCTION, function.getReference()); 161 return sp; 162 } 163 164 public static PdfShading type2(PdfWriter writer, BaseColor colorSpace, float coords[], float domain[], PdfFunction function, boolean extend[]) { 165 PdfShading sp = new PdfShading(writer); 166 sp.shading = new PdfDictionary(); 167 sp.shadingType = 2; 168 sp.shading.put(PdfName.SHADINGTYPE, new PdfNumber(sp.shadingType)); 169 sp.setColorSpace(colorSpace); 170 sp.shading.put(PdfName.COORDS, new PdfArray(coords)); 171 if (domain != null) 172 sp.shading.put(PdfName.DOMAIN, new PdfArray(domain)); 173 sp.shading.put(PdfName.FUNCTION, function.getReference()); 174 if (extend != null && (extend[0] || extend[1])) { 175 PdfArray array = new PdfArray(extend[0] ? PdfBoolean.PDFTRUE : PdfBoolean.PDFFALSE); 176 array.add(extend[1] ? PdfBoolean.PDFTRUE : PdfBoolean.PDFFALSE); 177 sp.shading.put(PdfName.EXTEND, array); 178 } 179 return sp; 180 } 181 182 public static PdfShading type3(PdfWriter writer, BaseColor colorSpace, float coords[], float domain[], PdfFunction function, boolean extend[]) { 183 PdfShading sp = type2(writer, colorSpace, coords, domain, function, extend); 184 sp.shadingType = 3; 185 sp.shading.put(PdfName.SHADINGTYPE, new PdfNumber(sp.shadingType)); 186 return sp; 187 } 188 189 public static PdfShading simpleAxial(PdfWriter writer, float x0, float y0, float x1, float y1, BaseColor startColor, BaseColor endColor, boolean extendStart, boolean extendEnd) { 190 checkCompatibleColors(startColor, endColor); 191 PdfFunction function = PdfFunction.type2(writer, new float[]{0, 1}, null, getColorArray(startColor), 192 getColorArray(endColor), 1); 193 return type2(writer, startColor, new float[]{x0, y0, x1, y1}, null, function, new boolean[]{extendStart, extendEnd}); 194 } 195 196 public static PdfShading simpleAxial(PdfWriter writer, float x0, float y0, float x1, float y1, BaseColor startColor, BaseColor endColor) { 197 return simpleAxial(writer, x0, y0, x1, y1, startColor, endColor, true, true); 198 } 199 200 public static PdfShading simpleRadial(PdfWriter writer, float x0, float y0, float r0, float x1, float y1, float r1, BaseColor startColor, BaseColor endColor, boolean extendStart, boolean extendEnd) { 201 checkCompatibleColors(startColor, endColor); 202 PdfFunction function = PdfFunction.type2(writer, new float[]{0, 1}, null, getColorArray(startColor), 203 getColorArray(endColor), 1); 204 return type3(writer, startColor, new float[]{x0, y0, r0, x1, y1, r1}, null, function, new boolean[]{extendStart, extendEnd}); 205 } 206 207 public static PdfShading simpleRadial(PdfWriter writer, float x0, float y0, float r0, float x1, float y1, float r1, BaseColor startColor, BaseColor endColor) { 208 return simpleRadial(writer, x0, y0, r0, x1, y1, r1, startColor, endColor, true, true); 209 } 210 211 PdfName getShadingName() { 212 return shadingName; 213 } 214 215 PdfIndirectReference getShadingReference() { 216 if (shadingReference == null) 217 shadingReference = writer.getPdfIndirectReference(); 218 return shadingReference; 219 } 220 221 void setName(int number) { 222 shadingName = new PdfName("Sh" + number); 223 } 224 225 void addToBody() throws IOException { 226 if (bBox != null) 227 shading.put(PdfName.BBOX, new PdfArray(bBox)); 228 if (antiAlias) 229 shading.put(PdfName.ANTIALIAS, PdfBoolean.PDFTRUE); 230 writer.addToBody(shading, getShadingReference()); 231 } 232 233 PdfWriter getWriter() { 234 return writer; 235 } 236 237 ColorDetails getColorDetails() { 238 return colorDetails; 239 } 240 241 public float[] getBBox() { 242 return bBox; 243 } 244 245 public void setBBox(float[] bBox) { 246 if (bBox.length != 4) 247 throw new IllegalArgumentException(MessageLocalization.getComposedMessage("bbox.must.be.a.4.element.array")); 248 this.bBox = bBox; 249 } 250 251 public boolean isAntiAlias() { 252 return antiAlias; 253 } 254 255 public void setAntiAlias(boolean antiAlias) { 256 this.antiAlias = antiAlias; 257 } 258 259}