001/*
002 * $Id: PdfXConformanceImp.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.internal;
045
046import com.itextpdf.text.BaseColor;
047import com.itextpdf.text.error_messages.MessageLocalization;
048
049import com.itextpdf.text.pdf.BaseFont;
050import com.itextpdf.text.pdf.ExtendedColor;
051import com.itextpdf.text.pdf.PatternColor;
052import com.itextpdf.text.pdf.PdfArray;
053import com.itextpdf.text.pdf.PdfDictionary;
054import com.itextpdf.text.pdf.PdfGState;
055import com.itextpdf.text.pdf.PdfImage;
056import com.itextpdf.text.pdf.PdfName;
057import com.itextpdf.text.pdf.PdfNumber;
058import com.itextpdf.text.pdf.PdfObject;
059import com.itextpdf.text.pdf.PdfString;
060import com.itextpdf.text.pdf.PdfWriter;
061import com.itextpdf.text.pdf.PdfXConformanceException;
062import com.itextpdf.text.pdf.ShadingColor;
063import com.itextpdf.text.pdf.SpotColor;
064import com.itextpdf.text.pdf.interfaces.PdfXConformance;
065
066public class PdfXConformanceImp implements PdfXConformance {
067
068    /** A key for an aspect that can be checked for PDF/X Conformance. */
069    public static final int PDFXKEY_COLOR = 1;
070    /** A key for an aspect that can be checked for PDF/X Conformance. */
071    public static final int PDFXKEY_CMYK = 2;
072    /** A key for an aspect that can be checked for PDF/X Conformance. */
073    public static final int PDFXKEY_RGB = 3;
074    /** A key for an aspect that can be checked for PDF/X Conformance. */
075    public static final int PDFXKEY_FONT = 4;
076    /** A key for an aspect that can be checked for PDF/X Conformance. */
077    public static final int PDFXKEY_IMAGE = 5;
078    /** A key for an aspect that can be checked for PDF/X Conformance. */
079    public static final int PDFXKEY_GSTATE = 6;
080    /** A key for an aspect that can be checked for PDF/X Conformance. */
081    public static final int PDFXKEY_LAYER = 7;
082    
083    /**
084     * The value indicating if the PDF has to be in conformance with PDF/X.
085     */
086    protected int pdfxConformance = PdfWriter.PDFXNONE;
087    
088    /**
089     * @see com.itextpdf.text.pdf.interfaces.PdfXConformance#setPDFXConformance(int)
090     */
091    public void setPDFXConformance(int pdfxConformance) {
092        this.pdfxConformance = pdfxConformance;
093    }
094
095        /**
096         * @see com.itextpdf.text.pdf.interfaces.PdfXConformance#getPDFXConformance()
097         */
098        public int getPDFXConformance() {
099                return pdfxConformance;
100        }
101    
102    /**
103     * Checks if the PDF/X Conformance is necessary.
104     * @return true if the PDF has to be in conformance with any of the PDF/X specifications
105     */
106    public boolean isPdfX() {
107        return pdfxConformance != PdfWriter.PDFXNONE;
108    }
109    /**
110     * Checks if the PDF has to be in conformance with PDF/X-1a:2001
111     * @return true of the PDF has to be in conformance with PDF/X-1a:2001
112     */
113    public boolean isPdfX1A2001() {
114        return pdfxConformance == PdfWriter.PDFX1A2001;
115    }
116    /**
117     * Checks if the PDF has to be in conformance with PDF/X-3:2002
118     * @return true of the PDF has to be in conformance with PDF/X-3:2002
119     */
120    public boolean isPdfX32002() {
121        return pdfxConformance == PdfWriter.PDFX32002;
122    }
123    
124    /**
125     * Checks if the PDF has to be in conformance with PDFA1
126     * @return true of the PDF has to be in conformance with PDFA1
127     */
128    public boolean isPdfA1() {
129        return pdfxConformance == PdfWriter.PDFA1A || pdfxConformance == PdfWriter.PDFA1B;
130    }
131    
132    /**
133     * Checks if the PDF has to be in conformance with PDFA1A
134     * @return true of the PDF has to be in conformance with PDFA1A
135     */
136    public boolean isPdfA1A() {
137        return pdfxConformance == PdfWriter.PDFA1A;
138    }
139    
140    public void completeInfoDictionary(PdfDictionary info) {
141        if (isPdfX() && !isPdfA1()) {
142            if (info.get(PdfName.GTS_PDFXVERSION) == null) {
143                if (isPdfX1A2001()) {
144                    info.put(PdfName.GTS_PDFXVERSION, new PdfString("PDF/X-1:2001"));
145                    info.put(new PdfName("GTS_PDFXConformance"), new PdfString("PDF/X-1a:2001"));
146                }
147                else if (isPdfX32002())
148                    info.put(PdfName.GTS_PDFXVERSION, new PdfString("PDF/X-3:2002"));
149            }
150            if (info.get(PdfName.TITLE) == null) {
151                info.put(PdfName.TITLE, new PdfString("Pdf document"));
152            }
153            if (info.get(PdfName.CREATOR) == null) {
154                info.put(PdfName.CREATOR, new PdfString("Unknown"));
155            }
156            if (info.get(PdfName.TRAPPED) == null) {
157                info.put(PdfName.TRAPPED, new PdfName("False"));
158            }
159        }
160    }
161    
162    public void completeExtraCatalog(PdfDictionary extraCatalog) {
163        if (isPdfX() && !isPdfA1()) {
164            if (extraCatalog.get(PdfName.OUTPUTINTENTS) == null) {
165                PdfDictionary out = new PdfDictionary(PdfName.OUTPUTINTENT);
166                out.put(PdfName.OUTPUTCONDITION, new PdfString("SWOP CGATS TR 001-1995"));
167                out.put(PdfName.OUTPUTCONDITIONIDENTIFIER, new PdfString("CGATS TR 001"));
168                out.put(PdfName.REGISTRYNAME, new PdfString("http://www.color.org"));
169                out.put(PdfName.INFO, new PdfString(""));
170                out.put(PdfName.S, PdfName.GTS_PDFX);
171                extraCatalog.put(PdfName.OUTPUTINTENTS, new PdfArray(out));
172            }
173        }
174    }
175    
176    /**
177         * Business logic that checks if a certain object is in conformance with PDF/X.
178     * @param writer    the writer that is supposed to write the PDF/X file
179     * @param key               the type of PDF/X conformance that has to be checked
180     * @param obj1              the object that is checked for conformance
181     */
182    public static void checkPDFXConformance(PdfWriter writer, int key, Object obj1) {
183        if (writer == null || !writer.isPdfX())
184            return;
185        int conf = writer.getPDFXConformance();
186        switch (key) {
187            case PDFXKEY_COLOR:
188                switch (conf) {
189                    case PdfWriter.PDFX1A2001:
190                        if (obj1 instanceof ExtendedColor) {
191                            ExtendedColor ec = (ExtendedColor)obj1;
192                            switch (ec.getType()) {
193                                case ExtendedColor.TYPE_CMYK:
194                                case ExtendedColor.TYPE_GRAY:
195                                    return;
196                                case ExtendedColor.TYPE_RGB:
197                                    throw new PdfXConformanceException(MessageLocalization.getComposedMessage("colorspace.rgb.is.not.allowed"));
198                                case ExtendedColor.TYPE_SEPARATION:
199                                    SpotColor sc = (SpotColor)ec;
200                                    checkPDFXConformance(writer, PDFXKEY_COLOR, sc.getPdfSpotColor().getAlternativeCS());
201                                    break;
202                                case ExtendedColor.TYPE_SHADING:
203                                    ShadingColor xc = (ShadingColor)ec;
204                                    checkPDFXConformance(writer, PDFXKEY_COLOR, xc.getPdfShadingPattern().getShading().getColorSpace());
205                                    break;
206                                case ExtendedColor.TYPE_PATTERN:
207                                    PatternColor pc = (PatternColor)ec;
208                                    checkPDFXConformance(writer, PDFXKEY_COLOR, pc.getPainter().getDefaultColor());
209                                    break;
210                            }
211                        }
212                        else if (obj1 instanceof BaseColor)
213                            throw new PdfXConformanceException(MessageLocalization.getComposedMessage("colorspace.rgb.is.not.allowed"));
214                        break;
215                }
216                break;
217            case PDFXKEY_CMYK:
218                break;
219            case PDFXKEY_RGB:
220                if (conf == PdfWriter.PDFX1A2001)
221                    throw new PdfXConformanceException(MessageLocalization.getComposedMessage("colorspace.rgb.is.not.allowed"));
222                break;
223            case PDFXKEY_FONT:
224                if (!((BaseFont)obj1).isEmbedded())
225                    throw new PdfXConformanceException(MessageLocalization.getComposedMessage("all.the.fonts.must.be.embedded.this.one.isn.t.1", ((BaseFont)obj1).getPostscriptFontName()));
226                break;
227            case PDFXKEY_IMAGE:
228                PdfImage image = (PdfImage)obj1;
229                if (image.get(PdfName.SMASK) != null)
230                    throw new PdfXConformanceException(MessageLocalization.getComposedMessage("the.smask.key.is.not.allowed.in.images"));
231                switch (conf) {
232                    case PdfWriter.PDFX1A2001:
233                        PdfObject cs = image.get(PdfName.COLORSPACE);
234                        if (cs == null)
235                            return;
236                        if (cs.isName()) {
237                            if (PdfName.DEVICERGB.equals(cs))
238                                throw new PdfXConformanceException(MessageLocalization.getComposedMessage("colorspace.rgb.is.not.allowed"));
239                        }
240                        else if (cs.isArray()) {
241                            if (PdfName.CALRGB.equals(((PdfArray)cs).getPdfObject(0)))
242                                throw new PdfXConformanceException(MessageLocalization.getComposedMessage("colorspace.calrgb.is.not.allowed"));
243                        }
244                        break;
245                }
246                break;
247            case PDFXKEY_GSTATE:
248                PdfDictionary gs = (PdfDictionary)obj1;
249                PdfObject obj = gs.get(PdfName.BM);
250                if (obj != null && !PdfGState.BM_NORMAL.equals(obj) && !PdfGState.BM_COMPATIBLE.equals(obj))
251                    throw new PdfXConformanceException(MessageLocalization.getComposedMessage("blend.mode.1.not.allowed", obj.toString()));
252                obj = gs.get(PdfName.CA);
253                double v = 0.0;
254                if (obj != null && (v = ((PdfNumber)obj).doubleValue()) != 1.0)
255                    throw new PdfXConformanceException(MessageLocalization.getComposedMessage("transparency.is.not.allowed.ca.eq.1", String.valueOf(v)));
256                obj = gs.get(PdfName.ca);
257                v = 0.0;
258                if (obj != null && (v = ((PdfNumber)obj).doubleValue()) != 1.0)
259                    throw new PdfXConformanceException(MessageLocalization.getComposedMessage("transparency.is.not.allowed.ca.eq.1", String.valueOf(v)));
260                break;
261            case PDFXKEY_LAYER:
262                throw new PdfXConformanceException(MessageLocalization.getComposedMessage("layers.are.not.allowed"));
263        }
264    }
265}