Source Code Cross Referenced for PdfContentByte.java in  » PDF » pdf-itext » com » lowagie » text » pdf » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » PDF » pdf itext » com.lowagie.text.pdf 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * $Id: PdfContentByte.java 2752 2007-05-15 14:58:33Z blowagie $
0003:         * $Name$
0004:         *
0005:         * Copyright 1999, 2000, 2001, 2002 Bruno Lowagie
0006:         *
0007:         * The contents of this file are subject to the Mozilla Public License Version 1.1
0008:         * (the "License"); you may not use this file except in compliance with the License.
0009:         * You may obtain a copy of the License at http://www.mozilla.org/MPL/
0010:         *
0011:         * Software distributed under the License is distributed on an "AS IS" basis,
0012:         * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
0013:         * for the specific language governing rights and limitations under the License.
0014:         *
0015:         * The Original Code is 'iText, a free JAVA-PDF library'.
0016:         *
0017:         * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by
0018:         * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie.
0019:         * All Rights Reserved.
0020:         * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer
0021:         * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved.
0022:         *
0023:         * Contributor(s): all the names of the contributors are added in the source code
0024:         * where applicable.
0025:         *
0026:         * Alternatively, the contents of this file may be used under the terms of the
0027:         * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the
0028:         * provisions of LGPL are applicable instead of those above.  If you wish to
0029:         * allow use of your version of this file only under the terms of the LGPL
0030:         * License and not to allow others to use your version of this file under
0031:         * the MPL, indicate your decision by deleting the provisions above and
0032:         * replace them with the notice and other provisions required by the LGPL.
0033:         * If you do not delete the provisions above, a recipient may use your version
0034:         * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE.
0035:         *
0036:         * This library is free software; you can redistribute it and/or modify it
0037:         * under the terms of the MPL as stated above or under the terms of the GNU
0038:         * Library General Public License as published by the Free Software Foundation;
0039:         * either version 2 of the License, or any later version.
0040:         *
0041:         * This library is distributed in the hope that it will be useful, but WITHOUT
0042:         * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
0043:         * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more
0044:         * details.
0045:         *
0046:         * If you didn't download this code from the following link, you should check if
0047:         * you aren't using an obsolete version:
0048:         * http://www.lowagie.com/iText/
0049:         */
0050:
0051:        package com.lowagie.text.pdf;
0052:
0053:        import java.awt.Color;
0054:        import java.awt.geom.AffineTransform;
0055:        import java.awt.print.PrinterJob;
0056:        import java.util.ArrayList;
0057:        import java.util.HashMap;
0058:        import java.util.Iterator;
0059:
0060:        import com.lowagie.text.Annotation;
0061:        import com.lowagie.text.DocumentException;
0062:        import com.lowagie.text.Element;
0063:        import com.lowagie.text.ExceptionConverter;
0064:        import com.lowagie.text.Image;
0065:        import com.lowagie.text.Rectangle;
0066:        import com.lowagie.text.pdf.internal.PdfAnnotationsImp;
0067:        import com.lowagie.text.pdf.internal.PdfXConformanceImp;
0068:
0069:        /**
0070:         * <CODE>PdfContentByte</CODE> is an object containing the user positioned
0071:         * text and graphic contents of a page. It knows how to apply the proper
0072:         * font encoding.
0073:         */
0074:
0075:        public class PdfContentByte {
0076:
0077:            /**
0078:             * This class keeps the graphic state of the current page
0079:             */
0080:
0081:            static class GraphicState {
0082:
0083:                /** This is the font in use */
0084:                FontDetails fontDetails;
0085:
0086:                /** This is the color in use */
0087:                ColorDetails colorDetails;
0088:
0089:                /** This is the font size in use */
0090:                float size;
0091:
0092:                /** The x position of the text line matrix. */
0093:                protected float xTLM = 0;
0094:                /** The y position of the text line matrix. */
0095:                protected float yTLM = 0;
0096:
0097:                /** The current text leading. */
0098:                protected float leading = 0;
0099:
0100:                /** The current horizontal scaling */
0101:                protected float scale = 100;
0102:
0103:                /** The current character spacing */
0104:                protected float charSpace = 0;
0105:
0106:                /** The current word spacing */
0107:                protected float wordSpace = 0;
0108:
0109:                GraphicState() {
0110:                }
0111:
0112:                GraphicState(GraphicState cp) {
0113:                    fontDetails = cp.fontDetails;
0114:                    colorDetails = cp.colorDetails;
0115:                    size = cp.size;
0116:                    xTLM = cp.xTLM;
0117:                    yTLM = cp.yTLM;
0118:                    leading = cp.leading;
0119:                    scale = cp.scale;
0120:                    charSpace = cp.charSpace;
0121:                    wordSpace = cp.wordSpace;
0122:                }
0123:            }
0124:
0125:            /** The alignement is center */
0126:            public static final int ALIGN_CENTER = Element.ALIGN_CENTER;
0127:
0128:            /** The alignement is left */
0129:            public static final int ALIGN_LEFT = Element.ALIGN_LEFT;
0130:
0131:            /** The alignement is right */
0132:            public static final int ALIGN_RIGHT = Element.ALIGN_RIGHT;
0133:
0134:            /** A possible line cap value */
0135:            public static final int LINE_CAP_BUTT = 0;
0136:            /** A possible line cap value */
0137:            public static final int LINE_CAP_ROUND = 1;
0138:            /** A possible line cap value */
0139:            public static final int LINE_CAP_PROJECTING_SQUARE = 2;
0140:
0141:            /** A possible line join value */
0142:            public static final int LINE_JOIN_MITER = 0;
0143:            /** A possible line join value */
0144:            public static final int LINE_JOIN_ROUND = 1;
0145:            /** A possible line join value */
0146:            public static final int LINE_JOIN_BEVEL = 2;
0147:
0148:            /** A possible text rendering value */
0149:            public static final int TEXT_RENDER_MODE_FILL = 0;
0150:            /** A possible text rendering value */
0151:            public static final int TEXT_RENDER_MODE_STROKE = 1;
0152:            /** A possible text rendering value */
0153:            public static final int TEXT_RENDER_MODE_FILL_STROKE = 2;
0154:            /** A possible text rendering value */
0155:            public static final int TEXT_RENDER_MODE_INVISIBLE = 3;
0156:            /** A possible text rendering value */
0157:            public static final int TEXT_RENDER_MODE_FILL_CLIP = 4;
0158:            /** A possible text rendering value */
0159:            public static final int TEXT_RENDER_MODE_STROKE_CLIP = 5;
0160:            /** A possible text rendering value */
0161:            public static final int TEXT_RENDER_MODE_FILL_STROKE_CLIP = 6;
0162:            /** A possible text rendering value */
0163:            public static final int TEXT_RENDER_MODE_CLIP = 7;
0164:
0165:            private static final float[] unitRect = { 0, 0, 0, 1, 1, 0, 1, 1 };
0166:            // membervariables
0167:
0168:            /** This is the actual content */
0169:            protected ByteBuffer content = new ByteBuffer();
0170:
0171:            /** This is the writer */
0172:            protected PdfWriter writer;
0173:
0174:            /** This is the PdfDocument */
0175:            protected PdfDocument pdf;
0176:
0177:            /** This is the GraphicState in use */
0178:            protected GraphicState state = new GraphicState();
0179:
0180:            /** The list were we save/restore the state */
0181:            protected ArrayList stateList = new ArrayList();
0182:
0183:            /** The list were we save/restore the layer depth */
0184:            protected ArrayList layerDepth;
0185:
0186:            /** The separator between commands.
0187:             */
0188:            protected int separator = '\n';
0189:
0190:            private static HashMap abrev = new HashMap();
0191:
0192:            static {
0193:                abrev.put(PdfName.BITSPERCOMPONENT, "/BPC ");
0194:                abrev.put(PdfName.COLORSPACE, "/CS ");
0195:                abrev.put(PdfName.DECODE, "/D ");
0196:                abrev.put(PdfName.DECODEPARMS, "/DP ");
0197:                abrev.put(PdfName.FILTER, "/F ");
0198:                abrev.put(PdfName.HEIGHT, "/H ");
0199:                abrev.put(PdfName.IMAGEMASK, "/IM ");
0200:                abrev.put(PdfName.INTENT, "/Intent ");
0201:                abrev.put(PdfName.INTERPOLATE, "/I ");
0202:                abrev.put(PdfName.WIDTH, "/W ");
0203:            }
0204:
0205:            // constructors
0206:
0207:            /**
0208:             * Constructs a new <CODE>PdfContentByte</CODE>-object.
0209:             *
0210:             * @param wr the writer associated to this content
0211:             */
0212:
0213:            public PdfContentByte(PdfWriter wr) {
0214:                if (wr != null) {
0215:                    writer = wr;
0216:                    pdf = writer.getPdfDocument();
0217:                }
0218:            }
0219:
0220:            // methods to get the content of this object
0221:
0222:            /**
0223:             * Returns the <CODE>String</CODE> representation of this <CODE>PdfContentByte</CODE>-object.
0224:             *
0225:             * @return      a <CODE>String</CODE>
0226:             */
0227:
0228:            public String toString() {
0229:                return content.toString();
0230:            }
0231:
0232:            /**
0233:             * Gets the internal buffer.
0234:             * @return the internal buffer
0235:             */
0236:            public ByteBuffer getInternalBuffer() {
0237:                return content;
0238:            }
0239:
0240:            /** Returns the PDF representation of this <CODE>PdfContentByte</CODE>-object.
0241:             *
0242:             * @param writer the <CODE>PdfWriter</CODE>
0243:             * @return a <CODE>byte</CODE> array with the representation
0244:             */
0245:
0246:            public byte[] toPdf(PdfWriter writer) {
0247:                return content.toByteArray();
0248:            }
0249:
0250:            // methods to add graphical content
0251:
0252:            /**
0253:             * Adds the content of another <CODE>PdfContent</CODE>-object to this object.
0254:             *
0255:             * @param       other       another <CODE>PdfByteContent</CODE>-object
0256:             */
0257:
0258:            public void add(PdfContentByte other) {
0259:                if (other.writer != null && writer != other.writer)
0260:                    throw new RuntimeException(
0261:                            "Inconsistent writers. Are you mixing two documents?");
0262:                content.append(other.content);
0263:            }
0264:
0265:            /**
0266:             * Gets the x position of the text line matrix.
0267:             *
0268:             * @return the x position of the text line matrix
0269:             */
0270:            public float getXTLM() {
0271:                return state.xTLM;
0272:            }
0273:
0274:            /**
0275:             * Gets the y position of the text line matrix.
0276:             *
0277:             * @return the y position of the text line matrix
0278:             */
0279:            public float getYTLM() {
0280:                return state.yTLM;
0281:            }
0282:
0283:            /**
0284:             * Gets the current text leading.
0285:             *
0286:             * @return the current text leading
0287:             */
0288:            public float getLeading() {
0289:                return state.leading;
0290:            }
0291:
0292:            /**
0293:             * Gets the current character spacing.
0294:             *
0295:             * @return the current character spacing
0296:             */
0297:            public float getCharacterSpacing() {
0298:                return state.charSpace;
0299:            }
0300:
0301:            /**
0302:             * Gets the current word spacing.
0303:             *
0304:             * @return the current word spacing
0305:             */
0306:            public float getWordSpacing() {
0307:                return state.wordSpace;
0308:            }
0309:
0310:            /**
0311:             * Gets the current character spacing.
0312:             *
0313:             * @return the current character spacing
0314:             */
0315:            public float getHorizontalScaling() {
0316:                return state.scale;
0317:            }
0318:
0319:            /**
0320:             * Changes the <VAR>Flatness</VAR>.
0321:             * <P>
0322:             * <VAR>Flatness</VAR> sets the maximum permitted distance in device pixels between the
0323:             * mathematically correct path and an approximation constructed from straight line segments.<BR>
0324:             *
0325:             * @param       flatness        a value
0326:             */
0327:
0328:            public void setFlatness(float flatness) {
0329:                if (flatness >= 0 && flatness <= 100) {
0330:                    content.append(flatness).append(" i").append_i(separator);
0331:                }
0332:            }
0333:
0334:            /**
0335:             * Changes the <VAR>Line cap style</VAR>.
0336:             * <P>
0337:             * The <VAR>line cap style</VAR> specifies the shape to be used at the end of open subpaths
0338:             * when they are stroked.<BR>
0339:             * Allowed values are LINE_CAP_BUTT, LINE_CAP_ROUND and LINE_CAP_PROJECTING_SQUARE.<BR>
0340:             *
0341:             * @param       style       a value
0342:             */
0343:
0344:            public void setLineCap(int style) {
0345:                if (style >= 0 && style <= 2) {
0346:                    content.append(style).append(" J").append_i(separator);
0347:                }
0348:            }
0349:
0350:            /**
0351:             * Changes the value of the <VAR>line dash pattern</VAR>.
0352:             * <P>
0353:             * The line dash pattern controls the pattern of dashes and gaps used to stroke paths.
0354:             * It is specified by an <I>array</I> and a <I>phase</I>. The array specifies the length
0355:             * of the alternating dashes and gaps. The phase specifies the distance into the dash
0356:             * pattern to start the dash.<BR>
0357:             *
0358:             * @param       phase       the value of the phase
0359:             */
0360:
0361:            public void setLineDash(float phase) {
0362:                content.append("[] ").append(phase).append(" d").append_i(
0363:                        separator);
0364:            }
0365:
0366:            /**
0367:             * Changes the value of the <VAR>line dash pattern</VAR>.
0368:             * <P>
0369:             * The line dash pattern controls the pattern of dashes and gaps used to stroke paths.
0370:             * It is specified by an <I>array</I> and a <I>phase</I>. The array specifies the length
0371:             * of the alternating dashes and gaps. The phase specifies the distance into the dash
0372:             * pattern to start the dash.<BR>
0373:             *
0374:             * @param       phase       the value of the phase
0375:             * @param       unitsOn     the number of units that must be 'on' (equals the number of units that must be 'off').
0376:             */
0377:
0378:            public void setLineDash(float unitsOn, float phase) {
0379:                content.append("[").append(unitsOn).append("] ").append(phase)
0380:                        .append(" d").append_i(separator);
0381:            }
0382:
0383:            /**
0384:             * Changes the value of the <VAR>line dash pattern</VAR>.
0385:             * <P>
0386:             * The line dash pattern controls the pattern of dashes and gaps used to stroke paths.
0387:             * It is specified by an <I>array</I> and a <I>phase</I>. The array specifies the length
0388:             * of the alternating dashes and gaps. The phase specifies the distance into the dash
0389:             * pattern to start the dash.<BR>
0390:             *
0391:             * @param       phase       the value of the phase
0392:             * @param       unitsOn     the number of units that must be 'on'
0393:             * @param       unitsOff    the number of units that must be 'off'
0394:             */
0395:
0396:            public void setLineDash(float unitsOn, float unitsOff, float phase) {
0397:                content.append("[").append(unitsOn).append(' ')
0398:                        .append(unitsOff).append("] ").append(phase).append(
0399:                                " d").append_i(separator);
0400:            }
0401:
0402:            /**
0403:             * Changes the value of the <VAR>line dash pattern</VAR>.
0404:             * <P>
0405:             * The line dash pattern controls the pattern of dashes and gaps used to stroke paths.
0406:             * It is specified by an <I>array</I> and a <I>phase</I>. The array specifies the length
0407:             * of the alternating dashes and gaps. The phase specifies the distance into the dash
0408:             * pattern to start the dash.<BR>
0409:             *
0410:             * @param       array       length of the alternating dashes and gaps
0411:             * @param       phase       the value of the phase
0412:             */
0413:
0414:            public final void setLineDash(float[] array, float phase) {
0415:                content.append("[");
0416:                for (int i = 0; i < array.length; i++) {
0417:                    content.append(array[i]);
0418:                    if (i < array.length - 1)
0419:                        content.append(' ');
0420:                }
0421:                content.append("] ").append(phase).append(" d").append_i(
0422:                        separator);
0423:            }
0424:
0425:            /**
0426:             * Changes the <VAR>Line join style</VAR>.
0427:             * <P>
0428:             * The <VAR>line join style</VAR> specifies the shape to be used at the corners of paths
0429:             * that are stroked.<BR>
0430:             * Allowed values are LINE_JOIN_MITER (Miter joins), LINE_JOIN_ROUND (Round joins) and LINE_JOIN_BEVEL (Bevel joins).<BR>
0431:             *
0432:             * @param       style       a value
0433:             */
0434:
0435:            public void setLineJoin(int style) {
0436:                if (style >= 0 && style <= 2) {
0437:                    content.append(style).append(" j").append_i(separator);
0438:                }
0439:            }
0440:
0441:            /**
0442:             * Changes the <VAR>line width</VAR>.
0443:             * <P>
0444:             * The line width specifies the thickness of the line used to stroke a path and is measured
0445:             * in user space units.<BR>
0446:             *
0447:             * @param       w           a width
0448:             */
0449:
0450:            public void setLineWidth(float w) {
0451:                content.append(w).append(" w").append_i(separator);
0452:            }
0453:
0454:            /**
0455:             * Changes the <VAR>Miter limit</VAR>.
0456:             * <P>
0457:             * When two line segments meet at a sharp angle and mitered joins have been specified as the
0458:             * line join style, it is possible for the miter to extend far beyond the thickness of the line
0459:             * stroking path. The miter limit imposes a maximum on the ratio of the miter length to the line
0460:             * witdh. When the limit is exceeded, the join is converted from a miter to a bevel.<BR>
0461:             *
0462:             * @param       miterLimit      a miter limit
0463:             */
0464:
0465:            public void setMiterLimit(float miterLimit) {
0466:                if (miterLimit > 1) {
0467:                    content.append(miterLimit).append(" M").append_i(separator);
0468:                }
0469:            }
0470:
0471:            /**
0472:             * Modify the current clipping path by intersecting it with the current path, using the
0473:             * nonzero winding number rule to determine which regions lie inside the clipping
0474:             * path.
0475:             */
0476:
0477:            public void clip() {
0478:                content.append("W").append_i(separator);
0479:            }
0480:
0481:            /**
0482:             * Modify the current clipping path by intersecting it with the current path, using the
0483:             * even-odd rule to determine which regions lie inside the clipping path.
0484:             */
0485:
0486:            public void eoClip() {
0487:                content.append("W*").append_i(separator);
0488:            }
0489:
0490:            /**
0491:             * Changes the currentgray tint for filling paths (device dependent colors!).
0492:             * <P>
0493:             * Sets the color space to <B>DeviceGray</B> (or the <B>DefaultGray</B> color space),
0494:             * and sets the gray tint to use for filling paths.</P>
0495:             *
0496:             * @param   gray    a value between 0 (black) and 1 (white)
0497:             */
0498:
0499:            public void setGrayFill(float gray) {
0500:                content.append(gray).append(" g").append_i(separator);
0501:            }
0502:
0503:            /**
0504:             * Changes the current gray tint for filling paths to black.
0505:             */
0506:
0507:            public void resetGrayFill() {
0508:                content.append("0 g").append_i(separator);
0509:            }
0510:
0511:            /**
0512:             * Changes the currentgray tint for stroking paths (device dependent colors!).
0513:             * <P>
0514:             * Sets the color space to <B>DeviceGray</B> (or the <B>DefaultGray</B> color space),
0515:             * and sets the gray tint to use for stroking paths.</P>
0516:             *
0517:             * @param   gray    a value between 0 (black) and 1 (white)
0518:             */
0519:
0520:            public void setGrayStroke(float gray) {
0521:                content.append(gray).append(" G").append_i(separator);
0522:            }
0523:
0524:            /**
0525:             * Changes the current gray tint for stroking paths to black.
0526:             */
0527:
0528:            public void resetGrayStroke() {
0529:                content.append("0 G").append_i(separator);
0530:            }
0531:
0532:            /**
0533:             * Helper to validate and write the RGB color components
0534:             * @param   red     the intensity of red. A value between 0 and 1
0535:             * @param   green   the intensity of green. A value between 0 and 1
0536:             * @param   blue    the intensity of blue. A value between 0 and 1
0537:             */
0538:            private void HelperRGB(float red, float green, float blue) {
0539:                PdfXConformanceImp.checkPDFXConformance(writer,
0540:                        PdfXConformanceImp.PDFXKEY_RGB, null);
0541:                if (red < 0)
0542:                    red = 0.0f;
0543:                else if (red > 1.0f)
0544:                    red = 1.0f;
0545:                if (green < 0)
0546:                    green = 0.0f;
0547:                else if (green > 1.0f)
0548:                    green = 1.0f;
0549:                if (blue < 0)
0550:                    blue = 0.0f;
0551:                else if (blue > 1.0f)
0552:                    blue = 1.0f;
0553:                content.append(red).append(' ').append(green).append(' ')
0554:                        .append(blue);
0555:            }
0556:
0557:            /**
0558:             * Changes the current color for filling paths (device dependent colors!).
0559:             * <P>
0560:             * Sets the color space to <B>DeviceRGB</B> (or the <B>DefaultRGB</B> color space),
0561:             * and sets the color to use for filling paths.</P>
0562:             * <P>
0563:             * Following the PDF manual, each operand must be a number between 0 (minimum intensity) and
0564:             * 1 (maximum intensity).</P>
0565:             *
0566:             * @param   red     the intensity of red. A value between 0 and 1
0567:             * @param   green   the intensity of green. A value between 0 and 1
0568:             * @param   blue    the intensity of blue. A value between 0 and 1
0569:             */
0570:
0571:            public void setRGBColorFillF(float red, float green, float blue) {
0572:                HelperRGB(red, green, blue);
0573:                content.append(" rg").append_i(separator);
0574:            }
0575:
0576:            /**
0577:             * Changes the current color for filling paths to black.
0578:             */
0579:
0580:            public void resetRGBColorFill() {
0581:                content.append("0 g").append_i(separator);
0582:            }
0583:
0584:            /**
0585:             * Changes the current color for stroking paths (device dependent colors!).
0586:             * <P>
0587:             * Sets the color space to <B>DeviceRGB</B> (or the <B>DefaultRGB</B> color space),
0588:             * and sets the color to use for stroking paths.</P>
0589:             * <P>
0590:             * Following the PDF manual, each operand must be a number between 0 (miniumum intensity) and
0591:             * 1 (maximum intensity).
0592:             *
0593:             * @param   red     the intensity of red. A value between 0 and 1
0594:             * @param   green   the intensity of green. A value between 0 and 1
0595:             * @param   blue    the intensity of blue. A value between 0 and 1
0596:             */
0597:
0598:            public void setRGBColorStrokeF(float red, float green, float blue) {
0599:                HelperRGB(red, green, blue);
0600:                content.append(" RG").append_i(separator);
0601:            }
0602:
0603:            /**
0604:             * Changes the current color for stroking paths to black.
0605:             *
0606:             */
0607:
0608:            public void resetRGBColorStroke() {
0609:                content.append("0 G").append_i(separator);
0610:            }
0611:
0612:            /**
0613:             * Helper to validate and write the CMYK color components.
0614:             *
0615:             * @param   cyan    the intensity of cyan. A value between 0 and 1
0616:             * @param   magenta the intensity of magenta. A value between 0 and 1
0617:             * @param   yellow  the intensity of yellow. A value between 0 and 1
0618:             * @param   black   the intensity of black. A value between 0 and 1
0619:             */
0620:            private void HelperCMYK(float cyan, float magenta, float yellow,
0621:                    float black) {
0622:                if (cyan < 0)
0623:                    cyan = 0.0f;
0624:                else if (cyan > 1.0f)
0625:                    cyan = 1.0f;
0626:                if (magenta < 0)
0627:                    magenta = 0.0f;
0628:                else if (magenta > 1.0f)
0629:                    magenta = 1.0f;
0630:                if (yellow < 0)
0631:                    yellow = 0.0f;
0632:                else if (yellow > 1.0f)
0633:                    yellow = 1.0f;
0634:                if (black < 0)
0635:                    black = 0.0f;
0636:                else if (black > 1.0f)
0637:                    black = 1.0f;
0638:                content.append(cyan).append(' ').append(magenta).append(' ')
0639:                        .append(yellow).append(' ').append(black);
0640:            }
0641:
0642:            /**
0643:             * Changes the current color for filling paths (device dependent colors!).
0644:             * <P>
0645:             * Sets the color space to <B>DeviceCMYK</B> (or the <B>DefaultCMYK</B> color space),
0646:             * and sets the color to use for filling paths.</P>
0647:             * <P>
0648:             * Following the PDF manual, each operand must be a number between 0 (no ink) and
0649:             * 1 (maximum ink).</P>
0650:             *
0651:             * @param   cyan    the intensity of cyan. A value between 0 and 1
0652:             * @param   magenta the intensity of magenta. A value between 0 and 1
0653:             * @param   yellow  the intensity of yellow. A value between 0 and 1
0654:             * @param   black   the intensity of black. A value between 0 and 1
0655:             */
0656:
0657:            public void setCMYKColorFillF(float cyan, float magenta,
0658:                    float yellow, float black) {
0659:                HelperCMYK(cyan, magenta, yellow, black);
0660:                content.append(" k").append_i(separator);
0661:            }
0662:
0663:            /**
0664:             * Changes the current color for filling paths to black.
0665:             *
0666:             */
0667:
0668:            public void resetCMYKColorFill() {
0669:                content.append("0 0 0 1 k").append_i(separator);
0670:            }
0671:
0672:            /**
0673:             * Changes the current color for stroking paths (device dependent colors!).
0674:             * <P>
0675:             * Sets the color space to <B>DeviceCMYK</B> (or the <B>DefaultCMYK</B> color space),
0676:             * and sets the color to use for stroking paths.</P>
0677:             * <P>
0678:             * Following the PDF manual, each operand must be a number between 0 (miniumum intensity) and
0679:             * 1 (maximum intensity).
0680:             *
0681:             * @param   cyan    the intensity of cyan. A value between 0 and 1
0682:             * @param   magenta the intensity of magenta. A value between 0 and 1
0683:             * @param   yellow  the intensity of yellow. A value between 0 and 1
0684:             * @param   black   the intensity of black. A value between 0 and 1
0685:             */
0686:
0687:            public void setCMYKColorStrokeF(float cyan, float magenta,
0688:                    float yellow, float black) {
0689:                HelperCMYK(cyan, magenta, yellow, black);
0690:                content.append(" K").append_i(separator);
0691:            }
0692:
0693:            /**
0694:             * Changes the current color for stroking paths to black.
0695:             *
0696:             */
0697:
0698:            public void resetCMYKColorStroke() {
0699:                content.append("0 0 0 1 K").append_i(separator);
0700:            }
0701:
0702:            /**
0703:             * Move the current point <I>(x, y)</I>, omitting any connecting line segment.
0704:             *
0705:             * @param       x               new x-coordinate
0706:             * @param       y               new y-coordinate
0707:             */
0708:
0709:            public void moveTo(float x, float y) {
0710:                content.append(x).append(' ').append(y).append(" m").append_i(
0711:                        separator);
0712:            }
0713:
0714:            /**
0715:             * Appends a straight line segment from the current point <I>(x, y)</I>. The new current
0716:             * point is <I>(x, y)</I>.
0717:             *
0718:             * @param       x               new x-coordinate
0719:             * @param       y               new y-coordinate
0720:             */
0721:
0722:            public void lineTo(float x, float y) {
0723:                content.append(x).append(' ').append(y).append(" l").append_i(
0724:                        separator);
0725:            }
0726:
0727:            /**
0728:             * Appends a B&#xea;zier curve to the path, starting from the current point.
0729:             *
0730:             * @param       x1      x-coordinate of the first control point
0731:             * @param       y1      y-coordinate of the first control point
0732:             * @param       x2      x-coordinate of the second control point
0733:             * @param       y2      y-coordinate of the second control point
0734:             * @param       x3      x-coordinaat of the ending point (= new current point)
0735:             * @param       y3      y-coordinaat of the ending point (= new current point)
0736:             */
0737:
0738:            public void curveTo(float x1, float y1, float x2, float y2,
0739:                    float x3, float y3) {
0740:                content.append(x1).append(' ').append(y1).append(' ')
0741:                        .append(x2).append(' ').append(y2).append(' ').append(
0742:                                x3).append(' ').append(y3).append(" c")
0743:                        .append_i(separator);
0744:            }
0745:
0746:            /**
0747:             * Appends a B&#xea;zier curve to the path, starting from the current point.
0748:             *
0749:             * @param       x2      x-coordinate of the second control point
0750:             * @param       y2      y-coordinate of the second control point
0751:             * @param       x3      x-coordinaat of the ending point (= new current point)
0752:             * @param       y3      y-coordinaat of the ending point (= new current point)
0753:             */
0754:
0755:            public void curveTo(float x2, float y2, float x3, float y3) {
0756:                content.append(x2).append(' ').append(y2).append(' ')
0757:                        .append(x3).append(' ').append(y3).append(" v")
0758:                        .append_i(separator);
0759:            }
0760:
0761:            /**
0762:             * Appends a B&#xea;zier curve to the path, starting from the current point.
0763:             *
0764:             * @param       x1      x-coordinate of the first control point
0765:             * @param       y1      y-coordinate of the first control point
0766:             * @param       x3      x-coordinaat of the ending point (= new current point)
0767:             * @param       y3      y-coordinaat of the ending point (= new current point)
0768:             */
0769:
0770:            public void curveFromTo(float x1, float y1, float x3, float y3) {
0771:                content.append(x1).append(' ').append(y1).append(' ')
0772:                        .append(x3).append(' ').append(y3).append(" y")
0773:                        .append_i(separator);
0774:            }
0775:
0776:            /** Draws a circle. The endpoint will (x+r, y).
0777:             *
0778:             * @param x x center of circle
0779:             * @param y y center of circle
0780:             * @param r radius of circle
0781:             */
0782:            public void circle(float x, float y, float r) {
0783:                float b = 0.5523f;
0784:                moveTo(x + r, y);
0785:                curveTo(x + r, y + r * b, x + r * b, y + r, x, y + r);
0786:                curveTo(x - r * b, y + r, x - r, y + r * b, x - r, y);
0787:                curveTo(x - r, y - r * b, x - r * b, y - r, x, y - r);
0788:                curveTo(x + r * b, y - r, x + r, y - r * b, x + r, y);
0789:            }
0790:
0791:            /**
0792:             * Adds a rectangle to the current path.
0793:             *
0794:             * @param       x       x-coordinate of the starting point
0795:             * @param       y       y-coordinate of the starting point
0796:             * @param       w       width
0797:             * @param       h       height
0798:             */
0799:
0800:            public void rectangle(float x, float y, float w, float h) {
0801:                content.append(x).append(' ').append(y).append(' ').append(w)
0802:                        .append(' ').append(h).append(" re")
0803:                        .append_i(separator);
0804:            }
0805:
0806:            private boolean compareColors(Color c1, Color c2) {
0807:                if (c1 == null && c2 == null)
0808:                    return true;
0809:                if (c1 == null || c2 == null)
0810:                    return false;
0811:                if (c1 instanceof  ExtendedColor)
0812:                    return c1.equals(c2);
0813:                return c2.equals(c1);
0814:            }
0815:
0816:            /**
0817:             * Adds a variable width border to the current path.
0818:             * Only use if {@link com.lowagie.text.Rectangle#isUseVariableBorders() Rectangle.isUseVariableBorders}
0819:             * = true.
0820:             * @param rect a <CODE>Rectangle</CODE>
0821:             */
0822:            public void variableRectangle(Rectangle rect) {
0823:                float t = rect.getTop();
0824:                float b = rect.getBottom();
0825:                float r = rect.getRight();
0826:                float l = rect.getLeft();
0827:                float wt = rect.getBorderWidthTop();
0828:                float wb = rect.getBorderWidthBottom();
0829:                float wr = rect.getBorderWidthRight();
0830:                float wl = rect.getBorderWidthLeft();
0831:                Color ct = rect.getBorderColorTop();
0832:                Color cb = rect.getBorderColorBottom();
0833:                Color cr = rect.getBorderColorRight();
0834:                Color cl = rect.getBorderColorLeft();
0835:                saveState();
0836:                setLineCap(PdfContentByte.LINE_CAP_BUTT);
0837:                setLineJoin(PdfContentByte.LINE_JOIN_MITER);
0838:                float clw = 0;
0839:                boolean cdef = false;
0840:                Color ccol = null;
0841:                boolean cdefi = false;
0842:                Color cfil = null;
0843:                // draw top
0844:                if (wt > 0) {
0845:                    setLineWidth(clw = wt);
0846:                    cdef = true;
0847:                    if (ct == null)
0848:                        resetRGBColorStroke();
0849:                    else
0850:                        setColorStroke(ct);
0851:                    ccol = ct;
0852:                    moveTo(l, t - wt / 2f);
0853:                    lineTo(r, t - wt / 2f);
0854:                    stroke();
0855:                }
0856:
0857:                // Draw bottom
0858:                if (wb > 0) {
0859:                    if (wb != clw)
0860:                        setLineWidth(clw = wb);
0861:                    if (!cdef || !compareColors(ccol, cb)) {
0862:                        cdef = true;
0863:                        if (cb == null)
0864:                            resetRGBColorStroke();
0865:                        else
0866:                            setColorStroke(cb);
0867:                        ccol = cb;
0868:                    }
0869:                    moveTo(r, b + wb / 2f);
0870:                    lineTo(l, b + wb / 2f);
0871:                    stroke();
0872:                }
0873:
0874:                // Draw right
0875:                if (wr > 0) {
0876:                    if (wr != clw)
0877:                        setLineWidth(clw = wr);
0878:                    if (!cdef || !compareColors(ccol, cr)) {
0879:                        cdef = true;
0880:                        if (cr == null)
0881:                            resetRGBColorStroke();
0882:                        else
0883:                            setColorStroke(cr);
0884:                        ccol = cr;
0885:                    }
0886:                    boolean bt = compareColors(ct, cr);
0887:                    boolean bb = compareColors(cb, cr);
0888:                    moveTo(r - wr / 2f, bt ? t : t - wt);
0889:                    lineTo(r - wr / 2f, bb ? b : b + wb);
0890:                    stroke();
0891:                    if (!bt || !bb) {
0892:                        cdefi = true;
0893:                        if (cr == null)
0894:                            resetRGBColorFill();
0895:                        else
0896:                            setColorFill(cr);
0897:                        cfil = cr;
0898:                        if (!bt) {
0899:                            moveTo(r, t);
0900:                            lineTo(r, t - wt);
0901:                            lineTo(r - wr, t - wt);
0902:                            fill();
0903:                        }
0904:                        if (!bb) {
0905:                            moveTo(r, b);
0906:                            lineTo(r, b + wb);
0907:                            lineTo(r - wr, b + wb);
0908:                            fill();
0909:                        }
0910:                    }
0911:                }
0912:
0913:                // Draw Left
0914:                if (wl > 0) {
0915:                    if (wl != clw)
0916:                        setLineWidth(wl);
0917:                    if (!cdef || !compareColors(ccol, cl)) {
0918:                        if (cl == null)
0919:                            resetRGBColorStroke();
0920:                        else
0921:                            setColorStroke(cl);
0922:                    }
0923:                    boolean bt = compareColors(ct, cl);
0924:                    boolean bb = compareColors(cb, cl);
0925:                    moveTo(l + wl / 2f, bt ? t : t - wt);
0926:                    lineTo(l + wl / 2f, bb ? b : b + wb);
0927:                    stroke();
0928:                    if (!bt || !bb) {
0929:                        if (!cdefi || !compareColors(cfil, cl)) {
0930:                            if (cl == null)
0931:                                resetRGBColorFill();
0932:                            else
0933:                                setColorFill(cl);
0934:                        }
0935:                        if (!bt) {
0936:                            moveTo(l, t);
0937:                            lineTo(l, t - wt);
0938:                            lineTo(l + wl, t - wt);
0939:                            fill();
0940:                        }
0941:                        if (!bb) {
0942:                            moveTo(l, b);
0943:                            lineTo(l, b + wb);
0944:                            lineTo(l + wl, b + wb);
0945:                            fill();
0946:                        }
0947:                    }
0948:                }
0949:                restoreState();
0950:            }
0951:
0952:            /**
0953:             * Adds a border (complete or partially) to the current path..
0954:             *
0955:             * @param       rectangle       a <CODE>Rectangle</CODE>
0956:             */
0957:
0958:            public void rectangle(Rectangle rectangle) {
0959:                // the coordinates of the border are retrieved
0960:                float x1 = rectangle.getLeft();
0961:                float y1 = rectangle.getBottom();
0962:                float x2 = rectangle.getRight();
0963:                float y2 = rectangle.getTop();
0964:
0965:                // the backgroundcolor is set
0966:                Color background = rectangle.getBackgroundColor();
0967:                if (background != null) {
0968:                    setColorFill(background);
0969:                    rectangle(x1, y1, x2 - x1, y2 - y1);
0970:                    fill();
0971:                    resetRGBColorFill();
0972:                }
0973:
0974:                // if the element hasn't got any borders, nothing is added
0975:                if (!rectangle.hasBorders()) {
0976:                    return;
0977:                }
0978:
0979:                // if any of the individual border colors are set
0980:                // we draw the borders all around using the
0981:                // different colors
0982:                if (rectangle.isUseVariableBorders()) {
0983:                    variableRectangle(rectangle);
0984:                } else {
0985:                    // the width is set to the width of the element
0986:                    if (rectangle.getBorderWidth() != Rectangle.UNDEFINED) {
0987:                        setLineWidth(rectangle.getBorderWidth());
0988:                    }
0989:
0990:                    // the color is set to the color of the element
0991:                    Color color = rectangle.getBorderColor();
0992:                    if (color != null) {
0993:                        setColorStroke(color);
0994:                    }
0995:
0996:                    // if the box is a rectangle, it is added as a rectangle
0997:                    if (rectangle.hasBorder(Rectangle.BOX)) {
0998:                        rectangle(x1, y1, x2 - x1, y2 - y1);
0999:                    }
1000:                    // if the border isn't a rectangle, the different sides are added apart
1001:                    else {
1002:                        if (rectangle.hasBorder(Rectangle.RIGHT)) {
1003:                            moveTo(x2, y1);
1004:                            lineTo(x2, y2);
1005:                        }
1006:                        if (rectangle.hasBorder(Rectangle.LEFT)) {
1007:                            moveTo(x1, y1);
1008:                            lineTo(x1, y2);
1009:                        }
1010:                        if (rectangle.hasBorder(Rectangle.BOTTOM)) {
1011:                            moveTo(x1, y1);
1012:                            lineTo(x2, y1);
1013:                        }
1014:                        if (rectangle.hasBorder(Rectangle.TOP)) {
1015:                            moveTo(x1, y2);
1016:                            lineTo(x2, y2);
1017:                        }
1018:                    }
1019:
1020:                    stroke();
1021:
1022:                    if (color != null) {
1023:                        resetRGBColorStroke();
1024:                    }
1025:                }
1026:            }
1027:
1028:            /**
1029:             * Closes the current subpath by appending a straight line segment from the current point
1030:             * to the starting point of the subpath.
1031:             */
1032:
1033:            public void closePath() {
1034:                content.append("h").append_i(separator);
1035:            }
1036:
1037:            /**
1038:             * Ends the path without filling or stroking it.
1039:             */
1040:
1041:            public void newPath() {
1042:                content.append("n").append_i(separator);
1043:            }
1044:
1045:            /**
1046:             * Strokes the path.
1047:             */
1048:
1049:            public void stroke() {
1050:                content.append("S").append_i(separator);
1051:            }
1052:
1053:            /**
1054:             * Closes the path and strokes it.
1055:             */
1056:
1057:            public void closePathStroke() {
1058:                content.append("s").append_i(separator);
1059:            }
1060:
1061:            /**
1062:             * Fills the path, using the non-zero winding number rule to determine the region to fill.
1063:             */
1064:
1065:            public void fill() {
1066:                content.append("f").append_i(separator);
1067:            }
1068:
1069:            /**
1070:             * Fills the path, using the even-odd rule to determine the region to fill.
1071:             */
1072:
1073:            public void eoFill() {
1074:                content.append("f*").append_i(separator);
1075:            }
1076:
1077:            /**
1078:             * Fills the path using the non-zero winding number rule to determine the region to fill and strokes it.
1079:             */
1080:
1081:            public void fillStroke() {
1082:                content.append("B").append_i(separator);
1083:            }
1084:
1085:            /**
1086:             * Closes the path, fills it using the non-zero winding number rule to determine the region to fill and strokes it.
1087:             */
1088:
1089:            public void closePathFillStroke() {
1090:                content.append("b").append_i(separator);
1091:            }
1092:
1093:            /**
1094:             * Fills the path, using the even-odd rule to determine the region to fill and strokes it.
1095:             */
1096:
1097:            public void eoFillStroke() {
1098:                content.append("B*").append_i(separator);
1099:            }
1100:
1101:            /**
1102:             * Closes the path, fills it using the even-odd rule to determine the region to fill and strokes it.
1103:             */
1104:
1105:            public void closePathEoFillStroke() {
1106:                content.append("b*").append_i(separator);
1107:            }
1108:
1109:            /**
1110:             * Adds an <CODE>Image</CODE> to the page. The <CODE>Image</CODE> must have
1111:             * absolute positioning.
1112:             * @param image the <CODE>Image</CODE> object
1113:             * @throws DocumentException if the <CODE>Image</CODE> does not have absolute positioning
1114:             */
1115:            public void addImage(Image image) throws DocumentException {
1116:                addImage(image, false);
1117:            }
1118:
1119:            /**
1120:             * Adds an <CODE>Image</CODE> to the page. The <CODE>Image</CODE> must have
1121:             * absolute positioning. The image can be placed inline.
1122:             * @param image the <CODE>Image</CODE> object
1123:             * @param inlineImage <CODE>true</CODE> to place this image inline, <CODE>false</CODE> otherwise
1124:             * @throws DocumentException if the <CODE>Image</CODE> does not have absolute positioning
1125:             */
1126:            public void addImage(Image image, boolean inlineImage)
1127:                    throws DocumentException {
1128:                if (!image.hasAbsoluteY())
1129:                    throw new DocumentException(
1130:                            "The image must have absolute positioning.");
1131:                float matrix[] = image.matrix();
1132:                matrix[Image.CX] = image.getAbsoluteX() - matrix[Image.CX];
1133:                matrix[Image.CY] = image.getAbsoluteY() - matrix[Image.CY];
1134:                addImage(image, matrix[0], matrix[1], matrix[2], matrix[3],
1135:                        matrix[4], matrix[5], inlineImage);
1136:            }
1137:
1138:            /**
1139:             * Adds an <CODE>Image</CODE> to the page. The positioning of the <CODE>Image</CODE>
1140:             * is done with the transformation matrix. To position an <CODE>image</CODE> at (x,y)
1141:             * use addImage(image, image_width, 0, 0, image_height, x, y).
1142:             * @param image the <CODE>Image</CODE> object
1143:             * @param a an element of the transformation matrix
1144:             * @param b an element of the transformation matrix
1145:             * @param c an element of the transformation matrix
1146:             * @param d an element of the transformation matrix
1147:             * @param e an element of the transformation matrix
1148:             * @param f an element of the transformation matrix
1149:             * @throws DocumentException on error
1150:             */
1151:            public void addImage(Image image, float a, float b, float c,
1152:                    float d, float e, float f) throws DocumentException {
1153:                addImage(image, a, b, c, d, e, f, false);
1154:            }
1155:
1156:            /**
1157:             * Adds an <CODE>Image</CODE> to the page. The positioning of the <CODE>Image</CODE>
1158:             * is done with the transformation matrix. To position an <CODE>image</CODE> at (x,y)
1159:             * use addImage(image, image_width, 0, 0, image_height, x, y). The image can be placed inline.
1160:             * @param image the <CODE>Image</CODE> object
1161:             * @param a an element of the transformation matrix
1162:             * @param b an element of the transformation matrix
1163:             * @param c an element of the transformation matrix
1164:             * @param d an element of the transformation matrix
1165:             * @param e an element of the transformation matrix
1166:             * @param f an element of the transformation matrix
1167:             * @param inlineImage <CODE>true</CODE> to place this image inline, <CODE>false</CODE> otherwise
1168:             * @throws DocumentException on error
1169:             */
1170:            public void addImage(Image image, float a, float b, float c,
1171:                    float d, float e, float f, boolean inlineImage)
1172:                    throws DocumentException {
1173:                try {
1174:                    if (image.getLayer() != null)
1175:                        beginLayer(image.getLayer());
1176:                    if (image.isImgTemplate()) {
1177:                        writer.addDirectImageSimple(image);
1178:                        PdfTemplate template = image.getTemplateData();
1179:                        float w = template.getWidth();
1180:                        float h = template.getHeight();
1181:                        addTemplate(template, a / w, b / w, c / h, d / h, e, f);
1182:                    } else {
1183:                        content.append("q ");
1184:                        content.append(a).append(' ');
1185:                        content.append(b).append(' ');
1186:                        content.append(c).append(' ');
1187:                        content.append(d).append(' ');
1188:                        content.append(e).append(' ');
1189:                        content.append(f).append(" cm");
1190:                        if (inlineImage) {
1191:                            content.append("\nBI\n");
1192:                            PdfImage pimage = new PdfImage(image, "", null);
1193:                            for (Iterator it = pimage.getKeys().iterator(); it
1194:                                    .hasNext();) {
1195:                                PdfName key = (PdfName) it.next();
1196:                                PdfObject value = pimage.get(key);
1197:                                String s = (String) abrev.get(key);
1198:                                if (s == null)
1199:                                    continue;
1200:                                content.append(s);
1201:                                boolean check = true;
1202:                                if (key.equals(PdfName.COLORSPACE)
1203:                                        && value.isArray()) {
1204:                                    ArrayList ar = ((PdfArray) value)
1205:                                            .getArrayList();
1206:                                    if (ar.size() == 4
1207:                                            && PdfName.INDEXED
1208:                                                    .equals(ar.get(0))
1209:                                            && ((PdfObject) ar.get(1)).isName()
1210:                                            && ((PdfObject) ar.get(2))
1211:                                                    .isNumber()
1212:                                            && ((PdfObject) ar.get(3))
1213:                                                    .isString()) {
1214:                                        check = false;
1215:                                    }
1216:
1217:                                }
1218:                                if (check && key.equals(PdfName.COLORSPACE)
1219:                                        && !value.isName()) {
1220:                                    PdfName cs = writer.getColorspaceName();
1221:                                    PageResources prs = getPageResources();
1222:                                    prs.addColor(cs, writer.addToBody(value)
1223:                                            .getIndirectReference());
1224:                                    value = cs;
1225:                                }
1226:                                value.toPdf(null, content);
1227:                                content.append('\n');
1228:                            }
1229:                            content.append("ID\n");
1230:                            pimage.writeContent(content);
1231:                            content.append("\nEI\nQ").append_i(separator);
1232:                        } else {
1233:                            PdfName name;
1234:                            PageResources prs = getPageResources();
1235:                            Image maskImage = image.getImageMask();
1236:                            if (maskImage != null) {
1237:                                name = writer.addDirectImageSimple(maskImage);
1238:                                prs.addXObject(name, writer
1239:                                        .getImageReference(name));
1240:                            }
1241:                            name = writer.addDirectImageSimple(image);
1242:                            name = prs.addXObject(name, writer
1243:                                    .getImageReference(name));
1244:                            content.append(' ').append(name.getBytes()).append(
1245:                                    " Do Q").append_i(separator);
1246:                        }
1247:                    }
1248:                    if (image.hasBorders()) {
1249:                        saveState();
1250:                        float w = image.getWidth();
1251:                        float h = image.getHeight();
1252:                        concatCTM(a / w, b / w, c / h, d / h, e, f);
1253:                        rectangle(image);
1254:                        restoreState();
1255:                    }
1256:                    if (image.getLayer() != null)
1257:                        endLayer();
1258:                    Annotation annot = image.getAnnotation();
1259:                    if (annot == null)
1260:                        return;
1261:                    float[] r = new float[unitRect.length];
1262:                    for (int k = 0; k < unitRect.length; k += 2) {
1263:                        r[k] = a * unitRect[k] + c * unitRect[k + 1] + e;
1264:                        r[k + 1] = b * unitRect[k] + d * unitRect[k + 1] + f;
1265:                    }
1266:                    float llx = r[0];
1267:                    float lly = r[1];
1268:                    float urx = llx;
1269:                    float ury = lly;
1270:                    for (int k = 2; k < r.length; k += 2) {
1271:                        llx = Math.min(llx, r[k]);
1272:                        lly = Math.min(lly, r[k + 1]);
1273:                        urx = Math.max(urx, r[k]);
1274:                        ury = Math.max(ury, r[k + 1]);
1275:                    }
1276:                    annot = new Annotation(annot);
1277:                    annot.setDimensions(llx, lly, urx, ury);
1278:                    PdfAnnotation an = PdfAnnotationsImp.convertAnnotation(
1279:                            writer, annot, new Rectangle(llx, lly, urx, ury));
1280:                    if (an == null)
1281:                        return;
1282:                    addAnnotation(an);
1283:                } catch (Exception ee) {
1284:                    throw new DocumentException(ee);
1285:                }
1286:            }
1287:
1288:            /**
1289:             * Makes this <CODE>PdfContentByte</CODE> empty.
1290:             */
1291:            public void reset() {
1292:                content.reset();
1293:                stateList.clear();
1294:                state = new GraphicState();
1295:            }
1296:
1297:            /**
1298:             * Starts the writing of text.
1299:             */
1300:            public void beginText() {
1301:                state.xTLM = 0;
1302:                state.yTLM = 0;
1303:                content.append("BT").append_i(separator);
1304:            }
1305:
1306:            /**
1307:             * Ends the writing of text and makes the current font invalid.
1308:             */
1309:            public void endText() {
1310:                content.append("ET").append_i(separator);
1311:            }
1312:
1313:            /**
1314:             * Saves the graphic state. <CODE>saveState</CODE> and
1315:             * <CODE>restoreState</CODE> must be balanced.
1316:             */
1317:            public void saveState() {
1318:                content.append("q").append_i(separator);
1319:                stateList.add(new GraphicState(state));
1320:            }
1321:
1322:            /**
1323:             * Restores the graphic state. <CODE>saveState</CODE> and
1324:             * <CODE>restoreState</CODE> must be balanced.
1325:             */
1326:            public void restoreState() {
1327:                content.append("Q").append_i(separator);
1328:                int idx = stateList.size() - 1;
1329:                if (idx < 0)
1330:                    throw new RuntimeException(
1331:                            "Unbalanced save/restore state operators.");
1332:                state = (GraphicState) stateList.get(idx);
1333:                stateList.remove(idx);
1334:            }
1335:
1336:            /**
1337:             * Sets the character spacing parameter.
1338:             *
1339:             * @param       charSpace           a parameter
1340:             */
1341:            public void setCharacterSpacing(float charSpace) {
1342:                state.charSpace = charSpace;
1343:                content.append(charSpace).append(" Tc").append_i(separator);
1344:            }
1345:
1346:            /**
1347:             * Sets the word spacing parameter.
1348:             *
1349:             * @param       wordSpace           a parameter
1350:             */
1351:            public void setWordSpacing(float wordSpace) {
1352:                state.wordSpace = wordSpace;
1353:                content.append(wordSpace).append(" Tw").append_i(separator);
1354:            }
1355:
1356:            /**
1357:             * Sets the horizontal scaling parameter.
1358:             *
1359:             * @param       scale               a parameter
1360:             */
1361:            public void setHorizontalScaling(float scale) {
1362:                state.scale = scale;
1363:                content.append(scale).append(" Tz").append_i(separator);
1364:            }
1365:
1366:            /**
1367:             * Sets the text leading parameter.
1368:             * <P>
1369:             * The leading parameter is measured in text space units. It specifies the vertical distance
1370:             * between the baselines of adjacent lines of text.</P>
1371:             *
1372:             * @param       leading         the new leading
1373:             */
1374:            public void setLeading(float leading) {
1375:                state.leading = leading;
1376:                content.append(leading).append(" TL").append_i(separator);
1377:            }
1378:
1379:            /**
1380:             * Set the font and the size for the subsequent text writing.
1381:             *
1382:             * @param bf the font
1383:             * @param size the font size in points
1384:             */
1385:            public void setFontAndSize(BaseFont bf, float size) {
1386:                checkWriter();
1387:                state.size = size;
1388:                state.fontDetails = writer.addSimple(bf);
1389:                PageResources prs = getPageResources();
1390:                PdfName name = state.fontDetails.getFontName();
1391:                name = prs.addFont(name, state.fontDetails
1392:                        .getIndirectReference());
1393:                content.append(name.getBytes()).append(' ').append(size)
1394:                        .append(" Tf").append_i(separator);
1395:            }
1396:
1397:            /**
1398:             * Sets the text rendering parameter.
1399:             *
1400:             * @param       rendering               a parameter
1401:             */
1402:            public void setTextRenderingMode(int rendering) {
1403:                content.append(rendering).append(" Tr").append_i(separator);
1404:            }
1405:
1406:            /**
1407:             * Sets the text rise parameter.
1408:             * <P>
1409:             * This allows to write text in subscript or superscript mode.</P>
1410:             *
1411:             * @param       rise                a parameter
1412:             */
1413:            public void setTextRise(float rise) {
1414:                content.append(rise).append(" Ts").append_i(separator);
1415:            }
1416:
1417:            /**
1418:             * A helper to insert into the content stream the <CODE>text</CODE>
1419:             * converted to bytes according to the font's encoding.
1420:             *
1421:             * @param text the text to write
1422:             */
1423:            private void showText2(String text) {
1424:                if (state.fontDetails == null)
1425:                    throw new NullPointerException(
1426:                            "Font and size must be set before writing any text");
1427:                byte b[] = state.fontDetails.convertToBytes(text);
1428:                escapeString(b, content);
1429:            }
1430:
1431:            /**
1432:             * Shows the <CODE>text</CODE>.
1433:             *
1434:             * @param text the text to write
1435:             */
1436:            public void showText(String text) {
1437:                showText2(text);
1438:                content.append("Tj").append_i(separator);
1439:            }
1440:
1441:            /**
1442:             * Constructs a kern array for a text in a certain font
1443:             * @param text the text
1444:             * @param font the font
1445:             * @return a PdfTextArray
1446:             */
1447:            public static PdfTextArray getKernArray(String text, BaseFont font) {
1448:                PdfTextArray pa = new PdfTextArray();
1449:                StringBuffer acc = new StringBuffer();
1450:                int len = text.length() - 1;
1451:                char c[] = text.toCharArray();
1452:                if (len >= 0)
1453:                    acc.append(c, 0, 1);
1454:                for (int k = 0; k < len; ++k) {
1455:                    char c2 = c[k + 1];
1456:                    int kern = font.getKerning(c[k], c2);
1457:                    if (kern == 0) {
1458:                        acc.append(c2);
1459:                    } else {
1460:                        pa.add(acc.toString());
1461:                        acc.setLength(0);
1462:                        acc.append(c, k + 1, 1);
1463:                        pa.add(-kern);
1464:                    }
1465:                }
1466:                pa.add(acc.toString());
1467:                return pa;
1468:            }
1469:
1470:            /**
1471:             * Shows the <CODE>text</CODE> kerned.
1472:             *
1473:             * @param text the text to write
1474:             */
1475:            public void showTextKerned(String text) {
1476:                if (state.fontDetails == null)
1477:                    throw new NullPointerException(
1478:                            "Font and size must be set before writing any text");
1479:                BaseFont bf = state.fontDetails.getBaseFont();
1480:                if (bf.hasKernPairs())
1481:                    showText(getKernArray(text, bf));
1482:                else
1483:                    showText(text);
1484:            }
1485:
1486:            /**
1487:             * Moves to the next line and shows <CODE>text</CODE>.
1488:             *
1489:             * @param text the text to write
1490:             */
1491:            public void newlineShowText(String text) {
1492:                state.yTLM -= state.leading;
1493:                showText2(text);
1494:                content.append("'").append_i(separator);
1495:            }
1496:
1497:            /**
1498:             * Moves to the next line and shows text string, using the given values of the character and word spacing parameters.
1499:             *
1500:             * @param       wordSpacing     a parameter
1501:             * @param       charSpacing     a parameter
1502:             * @param text the text to write
1503:             */
1504:            public void newlineShowText(float wordSpacing, float charSpacing,
1505:                    String text) {
1506:                state.yTLM -= state.leading;
1507:                content.append(wordSpacing).append(' ').append(charSpacing);
1508:                showText2(text);
1509:                content.append("\"").append_i(separator);
1510:
1511:                // The " operator sets charSpace and wordSpace into graphics state
1512:                // (cfr PDF reference v1.6, table 5.6)
1513:                state.charSpace = charSpacing;
1514:                state.wordSpace = wordSpacing;
1515:            }
1516:
1517:            /**
1518:             * Changes the text matrix.
1519:             * <P>
1520:             * Remark: this operation also initializes the current point position.</P>
1521:             *
1522:             * @param       a           operand 1,1 in the matrix
1523:             * @param       b           operand 1,2 in the matrix
1524:             * @param       c           operand 2,1 in the matrix
1525:             * @param       d           operand 2,2 in the matrix
1526:             * @param       x           operand 3,1 in the matrix
1527:             * @param       y           operand 3,2 in the matrix
1528:             */
1529:            public void setTextMatrix(float a, float b, float c, float d,
1530:                    float x, float y) {
1531:                state.xTLM = x;
1532:                state.yTLM = y;
1533:                content.append(a).append(' ').append(b).append_i(' ').append(c)
1534:                        .append_i(' ').append(d).append_i(' ').append(x)
1535:                        .append_i(' ').append(y).append(" Tm").append_i(
1536:                                separator);
1537:            }
1538:
1539:            /**
1540:             * Changes the text matrix. The first four parameters are {1,0,0,1}.
1541:             * <P>
1542:             * Remark: this operation also initializes the current point position.</P>
1543:             *
1544:             * @param       x           operand 3,1 in the matrix
1545:             * @param       y           operand 3,2 in the matrix
1546:             */
1547:            public void setTextMatrix(float x, float y) {
1548:                setTextMatrix(1, 0, 0, 1, x, y);
1549:            }
1550:
1551:            /**
1552:             * Moves to the start of the next line, offset from the start of the current line.
1553:             *
1554:             * @param       x           x-coordinate of the new current point
1555:             * @param       y           y-coordinate of the new current point
1556:             */
1557:            public void moveText(float x, float y) {
1558:                state.xTLM += x;
1559:                state.yTLM += y;
1560:                content.append(x).append(' ').append(y).append(" Td").append_i(
1561:                        separator);
1562:            }
1563:
1564:            /**
1565:             * Moves to the start of the next line, offset from the start of the current line.
1566:             * <P>
1567:             * As a side effect, this sets the leading parameter in the text state.</P>
1568:             *
1569:             * @param       x           offset of the new current point
1570:             * @param       y           y-coordinate of the new current point
1571:             */
1572:            public void moveTextWithLeading(float x, float y) {
1573:                state.xTLM += x;
1574:                state.yTLM += y;
1575:                state.leading = -y;
1576:                content.append(x).append(' ').append(y).append(" TD").append_i(
1577:                        separator);
1578:            }
1579:
1580:            /**
1581:             * Moves to the start of the next line.
1582:             */
1583:            public void newlineText() {
1584:                state.yTLM -= state.leading;
1585:                content.append("T*").append_i(separator);
1586:            }
1587:
1588:            /**
1589:             * Gets the size of this content.
1590:             *
1591:             * @return the size of the content
1592:             */
1593:            int size() {
1594:                return content.size();
1595:            }
1596:
1597:            /**
1598:             * Escapes a <CODE>byte</CODE> array according to the PDF conventions.
1599:             *
1600:             * @param b the <CODE>byte</CODE> array to escape
1601:             * @return an escaped <CODE>byte</CODE> array
1602:             */
1603:            static byte[] escapeString(byte b[]) {
1604:                ByteBuffer content = new ByteBuffer();
1605:                escapeString(b, content);
1606:                return content.toByteArray();
1607:            }
1608:
1609:            /**
1610:             * Escapes a <CODE>byte</CODE> array according to the PDF conventions.
1611:             *
1612:             * @param b the <CODE>byte</CODE> array to escape
1613:             * @param content the content
1614:             */
1615:            static void escapeString(byte b[], ByteBuffer content) {
1616:                content.append_i('(');
1617:                for (int k = 0; k < b.length; ++k) {
1618:                    byte c = b[k];
1619:                    switch ((int) c) {
1620:                    case '\r':
1621:                        content.append("\\r");
1622:                        break;
1623:                    case '\n':
1624:                        content.append("\\n");
1625:                        break;
1626:                    case '\t':
1627:                        content.append("\\t");
1628:                        break;
1629:                    case '\b':
1630:                        content.append("\\b");
1631:                        break;
1632:                    case '\f':
1633:                        content.append("\\f");
1634:                        break;
1635:                    case '(':
1636:                    case ')':
1637:                    case '\\':
1638:                        content.append_i('\\').append_i(c);
1639:                        break;
1640:                    default:
1641:                        content.append_i(c);
1642:                    }
1643:                }
1644:                content.append(")");
1645:            }
1646:
1647:            /**
1648:             * Adds an outline to the document.
1649:             *
1650:             * @param outline the outline
1651:             * @deprecated not needed anymore. The outlines are extracted
1652:             * from the root outline
1653:             */
1654:            public void addOutline(PdfOutline outline) {
1655:                // for compatibility
1656:            }
1657:
1658:            /**
1659:             * Adds a named outline to the document.
1660:             *
1661:             * @param outline the outline
1662:             * @param name the name for the local destination
1663:             */
1664:            public void addOutline(PdfOutline outline, String name) {
1665:                checkWriter();
1666:                pdf.addOutline(outline, name);
1667:            }
1668:
1669:            /**
1670:             * Gets the root outline.
1671:             *
1672:             * @return the root outline
1673:             */
1674:            public PdfOutline getRootOutline() {
1675:                checkWriter();
1676:                return pdf.getRootOutline();
1677:            }
1678:
1679:            /**
1680:             * Computes the width of the given string taking in account
1681:             * the current values of "Character spacing", "Word Spacing"
1682:             * and "Horizontal Scaling".
1683:             * The additional spacing is not computed for the last character
1684:             * of the string.
1685:             * @param text the string to get width of
1686:             * @param kerned the kerning option
1687:             * @return the width
1688:             */
1689:
1690:            public float getEffectiveStringWidth(String text, boolean kerned) {
1691:                BaseFont bf = state.fontDetails.getBaseFont();
1692:
1693:                float w;
1694:                if (kerned)
1695:                    w = bf.getWidthPointKerned(text, state.size);
1696:                else
1697:                    w = bf.getWidthPoint(text, state.size);
1698:
1699:                if (state.charSpace != 0.0f && text.length() > 1) {
1700:                    w += state.charSpace * (text.length() - 1);
1701:                }
1702:
1703:                int ft = bf.getFontType();
1704:                if (state.wordSpace != 0.0f
1705:                        && (ft == BaseFont.FONT_TYPE_T1
1706:                                || ft == BaseFont.FONT_TYPE_TT || ft == BaseFont.FONT_TYPE_T3)) {
1707:                    for (int i = 0; i < (text.length() - 1); i++) {
1708:                        if (text.charAt(i) == ' ')
1709:                            w += state.wordSpace;
1710:                    }
1711:                }
1712:                if (state.scale != 100.0)
1713:                    w = (w * state.scale) / 100.0f;
1714:
1715:                //System.out.println("String width = " + Float.toString(w));
1716:                return w;
1717:            }
1718:
1719:            /**
1720:             * Shows text right, left or center aligned with rotation.
1721:             * @param alignment the alignment can be ALIGN_CENTER, ALIGN_RIGHT or ALIGN_LEFT
1722:             * @param text the text to show
1723:             * @param x the x pivot position
1724:             * @param y the y pivot position
1725:             * @param rotation the rotation to be applied in degrees counterclockwise
1726:             */
1727:            public void showTextAligned(int alignment, String text, float x,
1728:                    float y, float rotation) {
1729:                showTextAligned(alignment, text, x, y, rotation, false);
1730:            }
1731:
1732:            private void showTextAligned(int alignment, String text, float x,
1733:                    float y, float rotation, boolean kerned) {
1734:                if (state.fontDetails == null)
1735:                    throw new NullPointerException(
1736:                            "Font and size must be set before writing any text");
1737:                if (rotation == 0) {
1738:                    switch (alignment) {
1739:                    case ALIGN_CENTER:
1740:                        x -= getEffectiveStringWidth(text, kerned) / 2;
1741:                        break;
1742:                    case ALIGN_RIGHT:
1743:                        x -= getEffectiveStringWidth(text, kerned);
1744:                        break;
1745:                    }
1746:                    setTextMatrix(x, y);
1747:                    if (kerned)
1748:                        showTextKerned(text);
1749:                    else
1750:                        showText(text);
1751:                } else {
1752:                    double alpha = rotation * Math.PI / 180.0;
1753:                    float cos = (float) Math.cos(alpha);
1754:                    float sin = (float) Math.sin(alpha);
1755:                    float len;
1756:                    switch (alignment) {
1757:                    case ALIGN_CENTER:
1758:                        len = getEffectiveStringWidth(text, kerned) / 2;
1759:                        x -= len * cos;
1760:                        y -= len * sin;
1761:                        break;
1762:                    case ALIGN_RIGHT:
1763:                        len = getEffectiveStringWidth(text, kerned);
1764:                        x -= len * cos;
1765:                        y -= len * sin;
1766:                        break;
1767:                    }
1768:                    setTextMatrix(cos, sin, -sin, cos, x, y);
1769:                    if (kerned)
1770:                        showTextKerned(text);
1771:                    else
1772:                        showText(text);
1773:                    setTextMatrix(0f, 0f);
1774:                }
1775:            }
1776:
1777:            /**
1778:             * Shows text kerned right, left or center aligned with rotation.
1779:             * @param alignment the alignment can be ALIGN_CENTER, ALIGN_RIGHT or ALIGN_LEFT
1780:             * @param text the text to show
1781:             * @param x the x pivot position
1782:             * @param y the y pivot position
1783:             * @param rotation the rotation to be applied in degrees counterclockwise
1784:             */
1785:            public void showTextAlignedKerned(int alignment, String text,
1786:                    float x, float y, float rotation) {
1787:                showTextAligned(alignment, text, x, y, rotation, true);
1788:            }
1789:
1790:            /**
1791:             * Concatenate a matrix to the current transformation matrix.
1792:             * @param a an element of the transformation matrix
1793:             * @param b an element of the transformation matrix
1794:             * @param c an element of the transformation matrix
1795:             * @param d an element of the transformation matrix
1796:             * @param e an element of the transformation matrix
1797:             * @param f an element of the transformation matrix
1798:             **/
1799:            public void concatCTM(float a, float b, float c, float d, float e,
1800:                    float f) {
1801:                content.append(a).append(' ').append(b).append(' ').append(c)
1802:                        .append(' ');
1803:                content.append(d).append(' ').append(e).append(' ').append(f)
1804:                        .append(" cm").append_i(separator);
1805:            }
1806:
1807:            /**
1808:             * Generates an array of bezier curves to draw an arc.
1809:             * <P>
1810:             * (x1, y1) and (x2, y2) are the corners of the enclosing rectangle.
1811:             * Angles, measured in degrees, start with 0 to the right (the positive X
1812:             * axis) and increase counter-clockwise.  The arc extends from startAng
1813:             * to startAng+extent.  I.e. startAng=0 and extent=180 yields an openside-down
1814:             * semi-circle.
1815:             * <P>
1816:             * The resulting coordinates are of the form float[]{x1,y1,x2,y2,x3,y3, x4,y4}
1817:             * such that the curve goes from (x1, y1) to (x4, y4) with (x2, y2) and
1818:             * (x3, y3) as their respective Bezier control points.
1819:             * <P>
1820:             * Note: this code was taken from ReportLab (www.reportlab.org), an excelent
1821:             * PDF generator for Python (BSD license: http://www.reportlab.org/devfaq.html#1.3 ).
1822:             *
1823:             * @param x1 a corner of the enclosing rectangle
1824:             * @param y1 a corner of the enclosing rectangle
1825:             * @param x2 a corner of the enclosing rectangle
1826:             * @param y2 a corner of the enclosing rectangle
1827:             * @param startAng starting angle in degrees
1828:             * @param extent angle extent in degrees
1829:             * @return a list of float[] with the bezier curves
1830:             */
1831:            public static ArrayList bezierArc(float x1, float y1, float x2,
1832:                    float y2, float startAng, float extent) {
1833:                float tmp;
1834:                if (x1 > x2) {
1835:                    tmp = x1;
1836:                    x1 = x2;
1837:                    x2 = tmp;
1838:                }
1839:                if (y2 > y1) {
1840:                    tmp = y1;
1841:                    y1 = y2;
1842:                    y2 = tmp;
1843:                }
1844:
1845:                float fragAngle;
1846:                int Nfrag;
1847:                if (Math.abs(extent) <= 90f) {
1848:                    fragAngle = extent;
1849:                    Nfrag = 1;
1850:                } else {
1851:                    Nfrag = (int) (Math.ceil(Math.abs(extent) / 90f));
1852:                    fragAngle = extent / Nfrag;
1853:                }
1854:                float x_cen = (x1 + x2) / 2f;
1855:                float y_cen = (y1 + y2) / 2f;
1856:                float rx = (x2 - x1) / 2f;
1857:                float ry = (y2 - y1) / 2f;
1858:                float halfAng = (float) (fragAngle * Math.PI / 360.);
1859:                float kappa = (float) (Math.abs(4. / 3.
1860:                        * (1. - Math.cos(halfAng)) / Math.sin(halfAng)));
1861:                ArrayList pointList = new ArrayList();
1862:                for (int i = 0; i < Nfrag; ++i) {
1863:                    float theta0 = (float) ((startAng + i * fragAngle)
1864:                            * Math.PI / 180.);
1865:                    float theta1 = (float) ((startAng + (i + 1) * fragAngle)
1866:                            * Math.PI / 180.);
1867:                    float cos0 = (float) Math.cos(theta0);
1868:                    float cos1 = (float) Math.cos(theta1);
1869:                    float sin0 = (float) Math.sin(theta0);
1870:                    float sin1 = (float) Math.sin(theta1);
1871:                    if (fragAngle > 0f) {
1872:                        pointList.add(new float[] { x_cen + rx * cos0,
1873:                                y_cen - ry * sin0,
1874:                                x_cen + rx * (cos0 - kappa * sin0),
1875:                                y_cen - ry * (sin0 + kappa * cos0),
1876:                                x_cen + rx * (cos1 + kappa * sin1),
1877:                                y_cen - ry * (sin1 - kappa * cos1),
1878:                                x_cen + rx * cos1, y_cen - ry * sin1 });
1879:                    } else {
1880:                        pointList.add(new float[] { x_cen + rx * cos0,
1881:                                y_cen - ry * sin0,
1882:                                x_cen + rx * (cos0 + kappa * sin0),
1883:                                y_cen - ry * (sin0 - kappa * cos0),
1884:                                x_cen + rx * (cos1 - kappa * sin1),
1885:                                y_cen - ry * (sin1 + kappa * cos1),
1886:                                x_cen + rx * cos1, y_cen - ry * sin1 });
1887:                    }
1888:                }
1889:                return pointList;
1890:            }
1891:
1892:            /**
1893:             * Draws a partial ellipse inscribed within the rectangle x1,y1,x2,y2,
1894:             * starting at startAng degrees and covering extent degrees. Angles
1895:             * start with 0 to the right (+x) and increase counter-clockwise.
1896:             *
1897:             * @param x1 a corner of the enclosing rectangle
1898:             * @param y1 a corner of the enclosing rectangle
1899:             * @param x2 a corner of the enclosing rectangle
1900:             * @param y2 a corner of the enclosing rectangle
1901:             * @param startAng starting angle in degrees
1902:             * @param extent angle extent in degrees
1903:             */
1904:            public void arc(float x1, float y1, float x2, float y2,
1905:                    float startAng, float extent) {
1906:                ArrayList ar = bezierArc(x1, y1, x2, y2, startAng, extent);
1907:                if (ar.isEmpty())
1908:                    return;
1909:                float pt[] = (float[]) ar.get(0);
1910:                moveTo(pt[0], pt[1]);
1911:                for (int k = 0; k < ar.size(); ++k) {
1912:                    pt = (float[]) ar.get(k);
1913:                    curveTo(pt[2], pt[3], pt[4], pt[5], pt[6], pt[7]);
1914:                }
1915:            }
1916:
1917:            /**
1918:             * Draws an ellipse inscribed within the rectangle x1,y1,x2,y2.
1919:             *
1920:             * @param x1 a corner of the enclosing rectangle
1921:             * @param y1 a corner of the enclosing rectangle
1922:             * @param x2 a corner of the enclosing rectangle
1923:             * @param y2 a corner of the enclosing rectangle
1924:             */
1925:            public void ellipse(float x1, float y1, float x2, float y2) {
1926:                arc(x1, y1, x2, y2, 0f, 360f);
1927:            }
1928:
1929:            /**
1930:             * Create a new colored tiling pattern.
1931:             *
1932:             * @param width the width of the pattern
1933:             * @param height the height of the pattern
1934:             * @param xstep the desired horizontal spacing between pattern cells.
1935:             * May be either positive or negative, but not zero.
1936:             * @param ystep the desired vertical spacing between pattern cells.
1937:             * May be either positive or negative, but not zero.
1938:             * @return the <CODE>PdfPatternPainter</CODE> where the pattern will be created
1939:             */
1940:            public PdfPatternPainter createPattern(float width, float height,
1941:                    float xstep, float ystep) {
1942:                checkWriter();
1943:                if (xstep == 0.0f || ystep == 0.0f)
1944:                    throw new RuntimeException(
1945:                            "XStep or YStep can not be ZERO.");
1946:                PdfPatternPainter painter = new PdfPatternPainter(writer);
1947:                painter.setWidth(width);
1948:                painter.setHeight(height);
1949:                painter.setXStep(xstep);
1950:                painter.setYStep(ystep);
1951:                writer.addSimplePattern(painter);
1952:                return painter;
1953:            }
1954:
1955:            /**
1956:             * Create a new colored tiling pattern. Variables xstep and ystep are set to the same values
1957:             * of width and height.
1958:             * @param width the width of the pattern
1959:             * @param height the height of the pattern
1960:             * @return the <CODE>PdfPatternPainter</CODE> where the pattern will be created
1961:             */
1962:            public PdfPatternPainter createPattern(float width, float height) {
1963:                return createPattern(width, height, width, height);
1964:            }
1965:
1966:            /**
1967:             * Create a new uncolored tiling pattern.
1968:             *
1969:             * @param width the width of the pattern
1970:             * @param height the height of the pattern
1971:             * @param xstep the desired horizontal spacing between pattern cells.
1972:             * May be either positive or negative, but not zero.
1973:             * @param ystep the desired vertical spacing between pattern cells.
1974:             * May be either positive or negative, but not zero.
1975:             * @param color the default color. Can be <CODE>null</CODE>
1976:             * @return the <CODE>PdfPatternPainter</CODE> where the pattern will be created
1977:             */
1978:            public PdfPatternPainter createPattern(float width, float height,
1979:                    float xstep, float ystep, Color color) {
1980:                checkWriter();
1981:                if (xstep == 0.0f || ystep == 0.0f)
1982:                    throw new RuntimeException(
1983:                            "XStep or YStep can not be ZERO.");
1984:                PdfPatternPainter painter = new PdfPatternPainter(writer, color);
1985:                painter.setWidth(width);
1986:                painter.setHeight(height);
1987:                painter.setXStep(xstep);
1988:                painter.setYStep(ystep);
1989:                writer.addSimplePattern(painter);
1990:                return painter;
1991:            }
1992:
1993:            /**
1994:             * Create a new uncolored tiling pattern.
1995:             * Variables xstep and ystep are set to the same values
1996:             * of width and height.
1997:             * @param width the width of the pattern
1998:             * @param height the height of the pattern
1999:             * @param color the default color. Can be <CODE>null</CODE>
2000:             * @return the <CODE>PdfPatternPainter</CODE> where the pattern will be created
2001:             */
2002:            public PdfPatternPainter createPattern(float width, float height,
2003:                    Color color) {
2004:                return createPattern(width, height, width, height, color);
2005:            }
2006:
2007:            /**
2008:             * Creates a new template.
2009:             * <P>
2010:             * Creates a new template that is nothing more than a form XObject. This template can be included
2011:             * in this <CODE>PdfContentByte</CODE> or in another template. Templates are only written
2012:             * to the output when the document is closed permitting things like showing text in the first page
2013:             * that is only defined in the last page.
2014:             *
2015:             * @param width the bounding box width
2016:             * @param height the bounding box height
2017:             * @return the templated created
2018:             */
2019:            public PdfTemplate createTemplate(float width, float height) {
2020:                return createTemplate(width, height, null);
2021:            }
2022:
2023:            PdfTemplate createTemplate(float width, float height,
2024:                    PdfName forcedName) {
2025:                checkWriter();
2026:                PdfTemplate template = new PdfTemplate(writer);
2027:                template.setWidth(width);
2028:                template.setHeight(height);
2029:                writer.addDirectTemplateSimple(template, forcedName);
2030:                return template;
2031:            }
2032:
2033:            /**
2034:             * Creates a new appearance to be used with form fields.
2035:             *
2036:             * @param width the bounding box width
2037:             * @param height the bounding box height
2038:             * @return the appearance created
2039:             */
2040:            public PdfAppearance createAppearance(float width, float height) {
2041:                return createAppearance(width, height, null);
2042:            }
2043:
2044:            PdfAppearance createAppearance(float width, float height,
2045:                    PdfName forcedName) {
2046:                checkWriter();
2047:                PdfAppearance template = new PdfAppearance(writer);
2048:                template.setWidth(width);
2049:                template.setHeight(height);
2050:                writer.addDirectTemplateSimple(template, forcedName);
2051:                return template;
2052:            }
2053:
2054:            /**
2055:             * Adds a PostScript XObject to this content.
2056:             *
2057:             * @param psobject the object
2058:             */
2059:            public void addPSXObject(PdfPSXObject psobject) {
2060:                checkWriter();
2061:                PdfName name = writer.addDirectTemplateSimple(psobject, null);
2062:                PageResources prs = getPageResources();
2063:                name = prs.addXObject(name, psobject.getIndirectReference());
2064:                content.append(name.getBytes()).append(" Do").append_i(
2065:                        separator);
2066:            }
2067:
2068:            /**
2069:             * Adds a template to this content.
2070:             *
2071:             * @param template the template
2072:             * @param a an element of the transformation matrix
2073:             * @param b an element of the transformation matrix
2074:             * @param c an element of the transformation matrix
2075:             * @param d an element of the transformation matrix
2076:             * @param e an element of the transformation matrix
2077:             * @param f an element of the transformation matrix
2078:             */
2079:            public void addTemplate(PdfTemplate template, float a, float b,
2080:                    float c, float d, float e, float f) {
2081:                checkWriter();
2082:                checkNoPattern(template);
2083:                PdfName name = writer.addDirectTemplateSimple(template, null);
2084:                PageResources prs = getPageResources();
2085:                name = prs.addXObject(name, template.getIndirectReference());
2086:                content.append("q ");
2087:                content.append(a).append(' ');
2088:                content.append(b).append(' ');
2089:                content.append(c).append(' ');
2090:                content.append(d).append(' ');
2091:                content.append(e).append(' ');
2092:                content.append(f).append(" cm ");
2093:                content.append(name.getBytes()).append(" Do Q").append_i(
2094:                        separator);
2095:            }
2096:
2097:            void addTemplateReference(PdfIndirectReference template,
2098:                    PdfName name, float a, float b, float c, float d, float e,
2099:                    float f) {
2100:                checkWriter();
2101:                PageResources prs = getPageResources();
2102:                name = prs.addXObject(name, template);
2103:                content.append("q ");
2104:                content.append(a).append(' ');
2105:                content.append(b).append(' ');
2106:                content.append(c).append(' ');
2107:                content.append(d).append(' ');
2108:                content.append(e).append(' ');
2109:                content.append(f).append(" cm ");
2110:                content.append(name.getBytes()).append(" Do Q").append_i(
2111:                        separator);
2112:            }
2113:
2114:            /**
2115:             * Adds a template to this content.
2116:             *
2117:             * @param template the template
2118:             * @param x the x location of this template
2119:             * @param y the y location of this template
2120:             */
2121:            public void addTemplate(PdfTemplate template, float x, float y) {
2122:                addTemplate(template, 1, 0, 0, 1, x, y);
2123:            }
2124:
2125:            /**
2126:             * Changes the current color for filling paths (device dependent colors!).
2127:             * <P>
2128:             * Sets the color space to <B>DeviceCMYK</B> (or the <B>DefaultCMYK</B> color space),
2129:             * and sets the color to use for filling paths.</P>
2130:             * <P>
2131:             * This method is described in the 'Portable Document Format Reference Manual version 1.3'
2132:             * section 8.5.2.1 (page 331).</P>
2133:             * <P>
2134:             * Following the PDF manual, each operand must be a number between 0 (no ink) and
2135:             * 1 (maximum ink). This method however accepts only integers between 0x00 and 0xFF.</P>
2136:             *
2137:             * @param cyan the intensity of cyan
2138:             * @param magenta the intensity of magenta
2139:             * @param yellow the intensity of yellow
2140:             * @param black the intensity of black
2141:             */
2142:
2143:            public void setCMYKColorFill(int cyan, int magenta, int yellow,
2144:                    int black) {
2145:                content.append((float) (cyan & 0xFF) / 0xFF);
2146:                content.append(' ');
2147:                content.append((float) (magenta & 0xFF) / 0xFF);
2148:                content.append(' ');
2149:                content.append((float) (yellow & 0xFF) / 0xFF);
2150:                content.append(' ');
2151:                content.append((float) (black & 0xFF) / 0xFF);
2152:                content.append(" k").append_i(separator);
2153:            }
2154:
2155:            /**
2156:             * Changes the current color for stroking paths (device dependent colors!).
2157:             * <P>
2158:             * Sets the color space to <B>DeviceCMYK</B> (or the <B>DefaultCMYK</B> color space),
2159:             * and sets the color to use for stroking paths.</P>
2160:             * <P>
2161:             * This method is described in the 'Portable Document Format Reference Manual version 1.3'
2162:             * section 8.5.2.1 (page 331).</P>
2163:             * Following the PDF manual, each operand must be a number between 0 (miniumum intensity) and
2164:             * 1 (maximum intensity). This method however accepts only integers between 0x00 and 0xFF.
2165:             *
2166:             * @param cyan the intensity of red
2167:             * @param magenta the intensity of green
2168:             * @param yellow the intensity of blue
2169:             * @param black the intensity of black
2170:             */
2171:
2172:            public void setCMYKColorStroke(int cyan, int magenta, int yellow,
2173:                    int black) {
2174:                content.append((float) (cyan & 0xFF) / 0xFF);
2175:                content.append(' ');
2176:                content.append((float) (magenta & 0xFF) / 0xFF);
2177:                content.append(' ');
2178:                content.append((float) (yellow & 0xFF) / 0xFF);
2179:                content.append(' ');
2180:                content.append((float) (black & 0xFF) / 0xFF);
2181:                content.append(" K").append_i(separator);
2182:            }
2183:
2184:            /**
2185:             * Changes the current color for filling paths (device dependent colors!).
2186:             * <P>
2187:             * Sets the color space to <B>DeviceRGB</B> (or the <B>DefaultRGB</B> color space),
2188:             * and sets the color to use for filling paths.</P>
2189:             * <P>
2190:             * This method is described in the 'Portable Document Format Reference Manual version 1.3'
2191:             * section 8.5.2.1 (page 331).</P>
2192:             * <P>
2193:             * Following the PDF manual, each operand must be a number between 0 (miniumum intensity) and
2194:             * 1 (maximum intensity). This method however accepts only integers between 0x00 and 0xFF.</P>
2195:             *
2196:             * @param red the intensity of red
2197:             * @param green the intensity of green
2198:             * @param blue the intensity of blue
2199:             */
2200:
2201:            public void setRGBColorFill(int red, int green, int blue) {
2202:                HelperRGB((float) (red & 0xFF) / 0xFF,
2203:                        (float) (green & 0xFF) / 0xFF,
2204:                        (float) (blue & 0xFF) / 0xFF);
2205:                content.append(" rg").append_i(separator);
2206:            }
2207:
2208:            /**
2209:             * Changes the current color for stroking paths (device dependent colors!).
2210:             * <P>
2211:             * Sets the color space to <B>DeviceRGB</B> (or the <B>DefaultRGB</B> color space),
2212:             * and sets the color to use for stroking paths.</P>
2213:             * <P>
2214:             * This method is described in the 'Portable Document Format Reference Manual version 1.3'
2215:             * section 8.5.2.1 (page 331).</P>
2216:             * Following the PDF manual, each operand must be a number between 0 (miniumum intensity) and
2217:             * 1 (maximum intensity). This method however accepts only integers between 0x00 and 0xFF.
2218:             *
2219:             * @param red the intensity of red
2220:             * @param green the intensity of green
2221:             * @param blue the intensity of blue
2222:             */
2223:
2224:            public void setRGBColorStroke(int red, int green, int blue) {
2225:                HelperRGB((float) (red & 0xFF) / 0xFF,
2226:                        (float) (green & 0xFF) / 0xFF,
2227:                        (float) (blue & 0xFF) / 0xFF);
2228:                content.append(" RG").append_i(separator);
2229:            }
2230:
2231:            /** Sets the stroke color. <CODE>color</CODE> can be an
2232:             * <CODE>ExtendedColor</CODE>.
2233:             * @param color the color
2234:             */
2235:            public void setColorStroke(Color color) {
2236:                PdfXConformanceImp.checkPDFXConformance(writer,
2237:                        PdfXConformanceImp.PDFXKEY_COLOR, color);
2238:                int type = ExtendedColor.getType(color);
2239:                switch (type) {
2240:                case ExtendedColor.TYPE_GRAY: {
2241:                    setGrayStroke(((GrayColor) color).getGray());
2242:                    break;
2243:                }
2244:                case ExtendedColor.TYPE_CMYK: {
2245:                    CMYKColor cmyk = (CMYKColor) color;
2246:                    setCMYKColorStrokeF(cmyk.getCyan(), cmyk.getMagenta(), cmyk
2247:                            .getYellow(), cmyk.getBlack());
2248:                    break;
2249:                }
2250:                case ExtendedColor.TYPE_SEPARATION: {
2251:                    SpotColor spot = (SpotColor) color;
2252:                    setColorStroke(spot.getPdfSpotColor(), spot.getTint());
2253:                    break;
2254:                }
2255:                case ExtendedColor.TYPE_PATTERN: {
2256:                    PatternColor pat = (PatternColor) color;
2257:                    setPatternStroke(pat.getPainter());
2258:                    break;
2259:                }
2260:                case ExtendedColor.TYPE_SHADING: {
2261:                    ShadingColor shading = (ShadingColor) color;
2262:                    setShadingStroke(shading.getPdfShadingPattern());
2263:                    break;
2264:                }
2265:                default:
2266:                    setRGBColorStroke(color.getRed(), color.getGreen(), color
2267:                            .getBlue());
2268:                }
2269:            }
2270:
2271:            /** Sets the fill color. <CODE>color</CODE> can be an
2272:             * <CODE>ExtendedColor</CODE>.
2273:             * @param color the color
2274:             */
2275:            public void setColorFill(Color color) {
2276:                PdfXConformanceImp.checkPDFXConformance(writer,
2277:                        PdfXConformanceImp.PDFXKEY_COLOR, color);
2278:                int type = ExtendedColor.getType(color);
2279:                switch (type) {
2280:                case ExtendedColor.TYPE_GRAY: {
2281:                    setGrayFill(((GrayColor) color).getGray());
2282:                    break;
2283:                }
2284:                case ExtendedColor.TYPE_CMYK: {
2285:                    CMYKColor cmyk = (CMYKColor) color;
2286:                    setCMYKColorFillF(cmyk.getCyan(), cmyk.getMagenta(), cmyk
2287:                            .getYellow(), cmyk.getBlack());
2288:                    break;
2289:                }
2290:                case ExtendedColor.TYPE_SEPARATION: {
2291:                    SpotColor spot = (SpotColor) color;
2292:                    setColorFill(spot.getPdfSpotColor(), spot.getTint());
2293:                    break;
2294:                }
2295:                case ExtendedColor.TYPE_PATTERN: {
2296:                    PatternColor pat = (PatternColor) color;
2297:                    setPatternFill(pat.getPainter());
2298:                    break;
2299:                }
2300:                case ExtendedColor.TYPE_SHADING: {
2301:                    ShadingColor shading = (ShadingColor) color;
2302:                    setShadingFill(shading.getPdfShadingPattern());
2303:                    break;
2304:                }
2305:                default:
2306:                    setRGBColorFill(color.getRed(), color.getGreen(), color
2307:                            .getBlue());
2308:                }
2309:            }
2310:
2311:            /** Sets the fill color to a spot color.
2312:             * @param sp the spot color
2313:             * @param tint the tint for the spot color. 0 is no color and 1
2314:             * is 100% color
2315:             */
2316:            public void setColorFill(PdfSpotColor sp, float tint) {
2317:                checkWriter();
2318:                state.colorDetails = writer.addSimple(sp);
2319:                PageResources prs = getPageResources();
2320:                PdfName name = state.colorDetails.getColorName();
2321:                name = prs.addColor(name, state.colorDetails
2322:                        .getIndirectReference());
2323:                content.append(name.getBytes()).append(" cs ").append(tint)
2324:                        .append(" scn").append_i(separator);
2325:            }
2326:
2327:            /** Sets the stroke color to a spot color.
2328:             * @param sp the spot color
2329:             * @param tint the tint for the spot color. 0 is no color and 1
2330:             * is 100% color
2331:             */
2332:            public void setColorStroke(PdfSpotColor sp, float tint) {
2333:                checkWriter();
2334:                state.colorDetails = writer.addSimple(sp);
2335:                PageResources prs = getPageResources();
2336:                PdfName name = state.colorDetails.getColorName();
2337:                name = prs.addColor(name, state.colorDetails
2338:                        .getIndirectReference());
2339:                content.append(name.getBytes()).append(" CS ").append(tint)
2340:                        .append(" SCN").append_i(separator);
2341:            }
2342:
2343:            /** Sets the fill color to a pattern. The pattern can be
2344:             * colored or uncolored.
2345:             * @param p the pattern
2346:             */
2347:            public void setPatternFill(PdfPatternPainter p) {
2348:                if (p.isStencil()) {
2349:                    setPatternFill(p, p.getDefaultColor());
2350:                    return;
2351:                }
2352:                checkWriter();
2353:                PageResources prs = getPageResources();
2354:                PdfName name = writer.addSimplePattern(p);
2355:                name = prs.addPattern(name, p.getIndirectReference());
2356:                content.append(PdfName.PATTERN.getBytes()).append(" cs ")
2357:                        .append(name.getBytes()).append(" scn").append_i(
2358:                                separator);
2359:            }
2360:
2361:            /** Outputs the color values to the content.
2362:             * @param color The color
2363:             * @param tint the tint if it is a spot color, ignored otherwise
2364:             */
2365:            void outputColorNumbers(Color color, float tint) {
2366:                PdfXConformanceImp.checkPDFXConformance(writer,
2367:                        PdfXConformanceImp.PDFXKEY_COLOR, color);
2368:                int type = ExtendedColor.getType(color);
2369:                switch (type) {
2370:                case ExtendedColor.TYPE_RGB:
2371:                    content.append((float) (color.getRed()) / 0xFF);
2372:                    content.append(' ');
2373:                    content.append((float) (color.getGreen()) / 0xFF);
2374:                    content.append(' ');
2375:                    content.append((float) (color.getBlue()) / 0xFF);
2376:                    break;
2377:                case ExtendedColor.TYPE_GRAY:
2378:                    content.append(((GrayColor) color).getGray());
2379:                    break;
2380:                case ExtendedColor.TYPE_CMYK: {
2381:                    CMYKColor cmyk = (CMYKColor) color;
2382:                    content.append(cmyk.getCyan()).append(' ').append(
2383:                            cmyk.getMagenta());
2384:                    content.append(' ').append(cmyk.getYellow()).append(' ')
2385:                            .append(cmyk.getBlack());
2386:                    break;
2387:                }
2388:                case ExtendedColor.TYPE_SEPARATION:
2389:                    content.append(tint);
2390:                    break;
2391:                default:
2392:                    throw new RuntimeException("Invalid color type.");
2393:                }
2394:            }
2395:
2396:            /** Sets the fill color to an uncolored pattern.
2397:             * @param p the pattern
2398:             * @param color the color of the pattern
2399:             */
2400:            public void setPatternFill(PdfPatternPainter p, Color color) {
2401:                if (ExtendedColor.getType(color) == ExtendedColor.TYPE_SEPARATION)
2402:                    setPatternFill(p, color, ((SpotColor) color).getTint());
2403:                else
2404:                    setPatternFill(p, color, 0);
2405:            }
2406:
2407:            /** Sets the fill color to an uncolored pattern.
2408:             * @param p the pattern
2409:             * @param color the color of the pattern
2410:             * @param tint the tint if the color is a spot color, ignored otherwise
2411:             */
2412:            public void setPatternFill(PdfPatternPainter p, Color color,
2413:                    float tint) {
2414:                checkWriter();
2415:                if (!p.isStencil())
2416:                    throw new RuntimeException(
2417:                            "An uncolored pattern was expected.");
2418:                PageResources prs = getPageResources();
2419:                PdfName name = writer.addSimplePattern(p);
2420:                name = prs.addPattern(name, p.getIndirectReference());
2421:                ColorDetails csDetail = writer
2422:                        .addSimplePatternColorspace(color);
2423:                PdfName cName = prs.addColor(csDetail.getColorName(), csDetail
2424:                        .getIndirectReference());
2425:                content.append(cName.getBytes()).append(" cs").append_i(
2426:                        separator);
2427:                outputColorNumbers(color, tint);
2428:                content.append(' ').append(name.getBytes()).append(" scn")
2429:                        .append_i(separator);
2430:            }
2431:
2432:            /** Sets the stroke color to an uncolored pattern.
2433:             * @param p the pattern
2434:             * @param color the color of the pattern
2435:             */
2436:            public void setPatternStroke(PdfPatternPainter p, Color color) {
2437:                if (ExtendedColor.getType(color) == ExtendedColor.TYPE_SEPARATION)
2438:                    setPatternStroke(p, color, ((SpotColor) color).getTint());
2439:                else
2440:                    setPatternStroke(p, color, 0);
2441:            }
2442:
2443:            /** Sets the stroke color to an uncolored pattern.
2444:             * @param p the pattern
2445:             * @param color the color of the pattern
2446:             * @param tint the tint if the color is a spot color, ignored otherwise
2447:             */
2448:            public void setPatternStroke(PdfPatternPainter p, Color color,
2449:                    float tint) {
2450:                checkWriter();
2451:                if (!p.isStencil())
2452:                    throw new RuntimeException(
2453:                            "An uncolored pattern was expected.");
2454:                PageResources prs = getPageResources();
2455:                PdfName name = writer.addSimplePattern(p);
2456:                name = prs.addPattern(name, p.getIndirectReference());
2457:                ColorDetails csDetail = writer
2458:                        .addSimplePatternColorspace(color);
2459:                PdfName cName = prs.addColor(csDetail.getColorName(), csDetail
2460:                        .getIndirectReference());
2461:                content.append(cName.getBytes()).append(" CS").append_i(
2462:                        separator);
2463:                outputColorNumbers(color, tint);
2464:                content.append(' ').append(name.getBytes()).append(" SCN")
2465:                        .append_i(separator);
2466:            }
2467:
2468:            /** Sets the stroke color to a pattern. The pattern can be
2469:             * colored or uncolored.
2470:             * @param p the pattern
2471:             */
2472:            public void setPatternStroke(PdfPatternPainter p) {
2473:                if (p.isStencil()) {
2474:                    setPatternStroke(p, p.getDefaultColor());
2475:                    return;
2476:                }
2477:                checkWriter();
2478:                PageResources prs = getPageResources();
2479:                PdfName name = writer.addSimplePattern(p);
2480:                name = prs.addPattern(name, p.getIndirectReference());
2481:                content.append(PdfName.PATTERN.getBytes()).append(" CS ")
2482:                        .append(name.getBytes()).append(" SCN").append_i(
2483:                                separator);
2484:            }
2485:
2486:            /**
2487:             * Paints using a shading object. 
2488:             * @param shading the shading object
2489:             */
2490:            public void paintShading(PdfShading shading) {
2491:                writer.addSimpleShading(shading);
2492:                PageResources prs = getPageResources();
2493:                PdfName name = prs.addShading(shading.getShadingName(), shading
2494:                        .getShadingReference());
2495:                content.append(name.getBytes()).append(" sh").append_i(
2496:                        separator);
2497:                ColorDetails details = shading.getColorDetails();
2498:                if (details != null)
2499:                    prs.addColor(details.getColorName(), details
2500:                            .getIndirectReference());
2501:            }
2502:
2503:            /**
2504:             * Paints using a shading pattern. 
2505:             * @param shading the shading pattern
2506:             */
2507:            public void paintShading(PdfShadingPattern shading) {
2508:                paintShading(shading.getShading());
2509:            }
2510:
2511:            /**
2512:             * Sets the shading fill pattern.
2513:             * @param shading the shading pattern
2514:             */
2515:            public void setShadingFill(PdfShadingPattern shading) {
2516:                writer.addSimpleShadingPattern(shading);
2517:                PageResources prs = getPageResources();
2518:                PdfName name = prs.addPattern(shading.getPatternName(), shading
2519:                        .getPatternReference());
2520:                content.append(PdfName.PATTERN.getBytes()).append(" cs ")
2521:                        .append(name.getBytes()).append(" scn").append_i(
2522:                                separator);
2523:                ColorDetails details = shading.getColorDetails();
2524:                if (details != null)
2525:                    prs.addColor(details.getColorName(), details
2526:                            .getIndirectReference());
2527:            }
2528:
2529:            /**
2530:             * Sets the shading stroke pattern
2531:             * @param shading the shading pattern
2532:             */
2533:            public void setShadingStroke(PdfShadingPattern shading) {
2534:                writer.addSimpleShadingPattern(shading);
2535:                PageResources prs = getPageResources();
2536:                PdfName name = prs.addPattern(shading.getPatternName(), shading
2537:                        .getPatternReference());
2538:                content.append(PdfName.PATTERN.getBytes()).append(" CS ")
2539:                        .append(name.getBytes()).append(" SCN").append_i(
2540:                                separator);
2541:                ColorDetails details = shading.getColorDetails();
2542:                if (details != null)
2543:                    prs.addColor(details.getColorName(), details
2544:                            .getIndirectReference());
2545:            }
2546:
2547:            /** Check if we have a valid PdfWriter.
2548:             *
2549:             */
2550:            protected void checkWriter() {
2551:                if (writer == null)
2552:                    throw new NullPointerException(
2553:                            "The writer in PdfContentByte is null.");
2554:            }
2555:
2556:            /**
2557:             * Show an array of text.
2558:             * @param text array of text
2559:             */
2560:            public void showText(PdfTextArray text) {
2561:                if (state.fontDetails == null)
2562:                    throw new NullPointerException(
2563:                            "Font and size must be set before writing any text");
2564:                content.append("[");
2565:                ArrayList arrayList = text.getArrayList();
2566:                boolean lastWasNumber = false;
2567:                for (int k = 0; k < arrayList.size(); ++k) {
2568:                    Object obj = arrayList.get(k);
2569:                    if (obj instanceof  String) {
2570:                        showText2((String) obj);
2571:                        lastWasNumber = false;
2572:                    } else {
2573:                        if (lastWasNumber)
2574:                            content.append(' ');
2575:                        else
2576:                            lastWasNumber = true;
2577:                        content.append(((Float) obj).floatValue());
2578:                    }
2579:                }
2580:                content.append("]TJ").append_i(separator);
2581:            }
2582:
2583:            /**
2584:             * Gets the <CODE>PdfWriter</CODE> in use by this object.
2585:             * @return the <CODE>PdfWriter</CODE> in use by this object
2586:             */
2587:            public PdfWriter getPdfWriter() {
2588:                return writer;
2589:            }
2590:
2591:            /**
2592:             * Gets the <CODE>PdfDocument</CODE> in use by this object.
2593:             * @return the <CODE>PdfDocument</CODE> in use by this object
2594:             */
2595:            public PdfDocument getPdfDocument() {
2596:                return pdf;
2597:            }
2598:
2599:            /**
2600:             * Implements a link to other part of the document. The jump will
2601:             * be made to a local destination with the same name, that must exist.
2602:             * @param name the name for this link
2603:             * @param llx the lower left x corner of the activation area
2604:             * @param lly the lower left y corner of the activation area
2605:             * @param urx the upper right x corner of the activation area
2606:             * @param ury the upper right y corner of the activation area
2607:             */
2608:            public void localGoto(String name, float llx, float lly, float urx,
2609:                    float ury) {
2610:                pdf.localGoto(name, llx, lly, urx, ury);
2611:            }
2612:
2613:            /**
2614:             * The local destination to where a local goto with the same
2615:             * name will jump.
2616:             * @param name the name of this local destination
2617:             * @param destination the <CODE>PdfDestination</CODE> with the jump coordinates
2618:             * @return <CODE>true</CODE> if the local destination was added,
2619:             * <CODE>false</CODE> if a local destination with the same name
2620:             * already exists
2621:             */
2622:            public boolean localDestination(String name,
2623:                    PdfDestination destination) {
2624:                return pdf.localDestination(name, destination);
2625:            }
2626:
2627:            /**
2628:             * Gets a duplicate of this <CODE>PdfContentByte</CODE>. All
2629:             * the members are copied by reference but the buffer stays different.
2630:             *
2631:             * @return a copy of this <CODE>PdfContentByte</CODE>
2632:             */
2633:            public PdfContentByte getDuplicate() {
2634:                return new PdfContentByte(writer);
2635:            }
2636:
2637:            /**
2638:             * Implements a link to another document.
2639:             * @param filename the filename for the remote document
2640:             * @param name the name to jump to
2641:             * @param llx the lower left x corner of the activation area
2642:             * @param lly the lower left y corner of the activation area
2643:             * @param urx the upper right x corner of the activation area
2644:             * @param ury the upper right y corner of the activation area
2645:             */
2646:            public void remoteGoto(String filename, String name, float llx,
2647:                    float lly, float urx, float ury) {
2648:                pdf.remoteGoto(filename, name, llx, lly, urx, ury);
2649:            }
2650:
2651:            /**
2652:             * Implements a link to another document.
2653:             * @param filename the filename for the remote document
2654:             * @param page the page to jump to
2655:             * @param llx the lower left x corner of the activation area
2656:             * @param lly the lower left y corner of the activation area
2657:             * @param urx the upper right x corner of the activation area
2658:             * @param ury the upper right y corner of the activation area
2659:             */
2660:            public void remoteGoto(String filename, int page, float llx,
2661:                    float lly, float urx, float ury) {
2662:                pdf.remoteGoto(filename, page, llx, lly, urx, ury);
2663:            }
2664:
2665:            /**
2666:             * Adds a round rectangle to the current path.
2667:             *
2668:             * @param x x-coordinate of the starting point
2669:             * @param y y-coordinate of the starting point
2670:             * @param w width
2671:             * @param h height
2672:             * @param r radius of the arc corner
2673:             */
2674:            public void roundRectangle(float x, float y, float w, float h,
2675:                    float r) {
2676:                if (w < 0) {
2677:                    x += w;
2678:                    w = -w;
2679:                }
2680:                if (h < 0) {
2681:                    y += h;
2682:                    h = -h;
2683:                }
2684:                if (r < 0)
2685:                    r = -r;
2686:                float b = 0.4477f;
2687:                moveTo(x + r, y);
2688:                lineTo(x + w - r, y);
2689:                curveTo(x + w - r * b, y, x + w, y + r * b, x + w, y + r);
2690:                lineTo(x + w, y + h - r);
2691:                curveTo(x + w, y + h - r * b, x + w - r * b, y + h, x + w - r,
2692:                        y + h);
2693:                lineTo(x + r, y + h);
2694:                curveTo(x + r * b, y + h, x, y + h - r * b, x, y + h - r);
2695:                lineTo(x, y + r);
2696:                curveTo(x, y + r * b, x + r * b, y, x + r, y);
2697:            }
2698:
2699:            /** Implements an action in an area.
2700:             * @param action the <CODE>PdfAction</CODE>
2701:             * @param llx the lower left x corner of the activation area
2702:             * @param lly the lower left y corner of the activation area
2703:             * @param urx the upper right x corner of the activation area
2704:             * @param ury the upper right y corner of the activation area
2705:             */
2706:            public void setAction(PdfAction action, float llx, float lly,
2707:                    float urx, float ury) {
2708:                pdf.setAction(action, llx, lly, urx, ury);
2709:            }
2710:
2711:            /** Outputs a <CODE>String</CODE> directly to the content.
2712:             * @param s the <CODE>String</CODE>
2713:             */
2714:            public void setLiteral(String s) {
2715:                content.append(s);
2716:            }
2717:
2718:            /** Outputs a <CODE>char</CODE> directly to the content.
2719:             * @param c the <CODE>char</CODE>
2720:             */
2721:            public void setLiteral(char c) {
2722:                content.append(c);
2723:            }
2724:
2725:            /** Outputs a <CODE>float</CODE> directly to the content.
2726:             * @param n the <CODE>float</CODE>
2727:             */
2728:            public void setLiteral(float n) {
2729:                content.append(n);
2730:            }
2731:
2732:            /** Throws an error if it is a pattern.
2733:             * @param t the object to check
2734:             */
2735:            void checkNoPattern(PdfTemplate t) {
2736:                if (t.getType() == PdfTemplate.TYPE_PATTERN)
2737:                    throw new RuntimeException(
2738:                            "Invalid use of a pattern. A template was expected.");
2739:            }
2740:
2741:            /**
2742:             * Draws a TextField.
2743:             * @param llx
2744:             * @param lly
2745:             * @param urx
2746:             * @param ury
2747:             * @param on
2748:             */
2749:            public void drawRadioField(float llx, float lly, float urx,
2750:                    float ury, boolean on) {
2751:                if (llx > urx) {
2752:                    float x = llx;
2753:                    llx = urx;
2754:                    urx = x;
2755:                }
2756:                if (lly > ury) {
2757:                    float y = lly;
2758:                    lly = ury;
2759:                    ury = y;
2760:                }
2761:                // silver circle
2762:                setLineWidth(1);
2763:                setLineCap(1);
2764:                setColorStroke(new Color(0xC0, 0xC0, 0xC0));
2765:                arc(llx + 1f, lly + 1f, urx - 1f, ury - 1f, 0f, 360f);
2766:                stroke();
2767:                // gray circle-segment
2768:                setLineWidth(1);
2769:                setLineCap(1);
2770:                setColorStroke(new Color(0xA0, 0xA0, 0xA0));
2771:                arc(llx + 0.5f, lly + 0.5f, urx - 0.5f, ury - 0.5f, 45, 180);
2772:                stroke();
2773:                // black circle-segment
2774:                setLineWidth(1);
2775:                setLineCap(1);
2776:                setColorStroke(new Color(0x00, 0x00, 0x00));
2777:                arc(llx + 1.5f, lly + 1.5f, urx - 1.5f, ury - 1.5f, 45, 180);
2778:                stroke();
2779:                if (on) {
2780:                    // gray circle
2781:                    setLineWidth(1);
2782:                    setLineCap(1);
2783:                    setColorFill(new Color(0x00, 0x00, 0x00));
2784:                    arc(llx + 4f, lly + 4f, urx - 4f, ury - 4f, 0, 360);
2785:                    fill();
2786:                }
2787:            }
2788:
2789:            /**
2790:             * Draws a TextField.
2791:             * @param llx
2792:             * @param lly
2793:             * @param urx
2794:             * @param ury
2795:             */
2796:            public void drawTextField(float llx, float lly, float urx, float ury) {
2797:                if (llx > urx) {
2798:                    float x = llx;
2799:                    llx = urx;
2800:                    urx = x;
2801:                }
2802:                if (lly > ury) {
2803:                    float y = lly;
2804:                    lly = ury;
2805:                    ury = y;
2806:                }
2807:                // silver rectangle not filled
2808:                setColorStroke(new Color(0xC0, 0xC0, 0xC0));
2809:                setLineWidth(1);
2810:                setLineCap(0);
2811:                rectangle(llx, lly, urx - llx, ury - lly);
2812:                stroke();
2813:                // white rectangle filled
2814:                setLineWidth(1);
2815:                setLineCap(0);
2816:                setColorFill(new Color(0xFF, 0xFF, 0xFF));
2817:                rectangle(llx + 0.5f, lly + 0.5f, urx - llx - 1f, ury - lly
2818:                        - 1f);
2819:                fill();
2820:                // silver lines
2821:                setColorStroke(new Color(0xC0, 0xC0, 0xC0));
2822:                setLineWidth(1);
2823:                setLineCap(0);
2824:                moveTo(llx + 1f, lly + 1.5f);
2825:                lineTo(urx - 1.5f, lly + 1.5f);
2826:                lineTo(urx - 1.5f, ury - 1f);
2827:                stroke();
2828:                // gray lines
2829:                setColorStroke(new Color(0xA0, 0xA0, 0xA0));
2830:                setLineWidth(1);
2831:                setLineCap(0);
2832:                moveTo(llx + 1f, lly + 1);
2833:                lineTo(llx + 1f, ury - 1f);
2834:                lineTo(urx - 1f, ury - 1f);
2835:                stroke();
2836:                // black lines
2837:                setColorStroke(new Color(0x00, 0x00, 0x00));
2838:                setLineWidth(1);
2839:                setLineCap(0);
2840:                moveTo(llx + 2f, lly + 2f);
2841:                lineTo(llx + 2f, ury - 2f);
2842:                lineTo(urx - 2f, ury - 2f);
2843:                stroke();
2844:            }
2845:
2846:            /**
2847:             * Draws a button.
2848:             * @param llx
2849:             * @param lly
2850:             * @param urx
2851:             * @param ury
2852:             * @param text
2853:             * @param bf
2854:             * @param size
2855:             */
2856:            public void drawButton(float llx, float lly, float urx, float ury,
2857:                    String text, BaseFont bf, float size) {
2858:                if (llx > urx) {
2859:                    float x = llx;
2860:                    llx = urx;
2861:                    urx = x;
2862:                }
2863:                if (lly > ury) {
2864:                    float y = lly;
2865:                    lly = ury;
2866:                    ury = y;
2867:                }
2868:                // black rectangle not filled
2869:                setColorStroke(new Color(0x00, 0x00, 0x00));
2870:                setLineWidth(1);
2871:                setLineCap(0);
2872:                rectangle(llx, lly, urx - llx, ury - lly);
2873:                stroke();
2874:                // silver rectangle filled
2875:                setLineWidth(1);
2876:                setLineCap(0);
2877:                setColorFill(new Color(0xC0, 0xC0, 0xC0));
2878:                rectangle(llx + 0.5f, lly + 0.5f, urx - llx - 1f, ury - lly
2879:                        - 1f);
2880:                fill();
2881:                // white lines
2882:                setColorStroke(new Color(0xFF, 0xFF, 0xFF));
2883:                setLineWidth(1);
2884:                setLineCap(0);
2885:                moveTo(llx + 1f, lly + 1f);
2886:                lineTo(llx + 1f, ury - 1f);
2887:                lineTo(urx - 1f, ury - 1f);
2888:                stroke();
2889:                // dark grey lines
2890:                setColorStroke(new Color(0xA0, 0xA0, 0xA0));
2891:                setLineWidth(1);
2892:                setLineCap(0);
2893:                moveTo(llx + 1f, lly + 1f);
2894:                lineTo(urx - 1f, lly + 1f);
2895:                lineTo(urx - 1f, ury - 1f);
2896:                stroke();
2897:                // text
2898:                resetRGBColorFill();
2899:                beginText();
2900:                setFontAndSize(bf, size);
2901:                showTextAligned(PdfContentByte.ALIGN_CENTER, text, llx
2902:                        + (urx - llx) / 2, lly + (ury - lly - size) / 2, 0);
2903:                endText();
2904:            }
2905:
2906:            /** Gets a <CODE>Graphics2D</CODE> to write on. The graphics
2907:             * are translated to PDF commands as shapes. No PDF fonts will appear.
2908:             * @param width the width of the panel
2909:             * @param height the height of the panel
2910:             * @return a <CODE>Graphics2D</CODE>
2911:             */
2912:            public java.awt.Graphics2D createGraphicsShapes(float width,
2913:                    float height) {
2914:                return new PdfGraphics2D(this , width, height, null, true,
2915:                        false, 0);
2916:            }
2917:
2918:            /** Gets a <CODE>Graphics2D</CODE> to print on. The graphics
2919:             * are translated to PDF commands as shapes. No PDF fonts will appear.
2920:             * @param width the width of the panel
2921:             * @param height the height of the panel
2922:             * @param printerJob a printer job
2923:             * @return a <CODE>Graphics2D</CODE>
2924:             */
2925:            public java.awt.Graphics2D createPrinterGraphicsShapes(float width,
2926:                    float height, PrinterJob printerJob) {
2927:                return new PdfPrinterGraphics2D(this , width, height, null,
2928:                        true, false, 0, printerJob);
2929:            }
2930:
2931:            /** Gets a <CODE>Graphics2D</CODE> to write on. The graphics
2932:             * are translated to PDF commands.
2933:             * @param width the width of the panel
2934:             * @param height the height of the panel
2935:             * @return a <CODE>Graphics2D</CODE>
2936:             */
2937:            public java.awt.Graphics2D createGraphics(float width, float height) {
2938:                return new PdfGraphics2D(this , width, height, null, false,
2939:                        false, 0);
2940:            }
2941:
2942:            /** Gets a <CODE>Graphics2D</CODE> to print on. The graphics
2943:             * are translated to PDF commands.
2944:             * @param width the width of the panel
2945:             * @param height the height of the panel
2946:             * @param printerJob
2947:             * @return a <CODE>Graphics2D</CODE>
2948:             */
2949:            public java.awt.Graphics2D createPrinterGraphics(float width,
2950:                    float height, PrinterJob printerJob) {
2951:                return new PdfPrinterGraphics2D(this , width, height, null,
2952:                        false, false, 0, printerJob);
2953:            }
2954:
2955:            /** Gets a <CODE>Graphics2D</CODE> to write on. The graphics
2956:             * are translated to PDF commands.
2957:             * @param width the width of the panel
2958:             * @param height the height of the panel
2959:             * @param convertImagesToJPEG
2960:             * @param quality
2961:             * @return a <CODE>Graphics2D</CODE>
2962:             */
2963:            public java.awt.Graphics2D createGraphics(float width,
2964:                    float height, boolean convertImagesToJPEG, float quality) {
2965:                return new PdfGraphics2D(this , width, height, null, false,
2966:                        convertImagesToJPEG, quality);
2967:            }
2968:
2969:            /** Gets a <CODE>Graphics2D</CODE> to print on. The graphics
2970:             * are translated to PDF commands.
2971:             * @param width the width of the panel
2972:             * @param height the height of the panel
2973:             * @param convertImagesToJPEG
2974:             * @param quality
2975:             * @param printerJob
2976:             * @return a <CODE>Graphics2D</CODE>
2977:             */
2978:            public java.awt.Graphics2D createPrinterGraphics(float width,
2979:                    float height, boolean convertImagesToJPEG, float quality,
2980:                    PrinterJob printerJob) {
2981:                return new PdfPrinterGraphics2D(this , width, height, null,
2982:                        false, convertImagesToJPEG, quality, printerJob);
2983:            }
2984:
2985:            /** Gets a <CODE>Graphics2D</CODE> to print on. The graphics
2986:             * are translated to PDF commands.
2987:             * @param width
2988:             * @param height
2989:             * @param convertImagesToJPEG
2990:             * @param quality
2991:             * @return A Graphics2D object
2992:             */
2993:            public java.awt.Graphics2D createGraphicsShapes(float width,
2994:                    float height, boolean convertImagesToJPEG, float quality) {
2995:                return new PdfGraphics2D(this , width, height, null, true,
2996:                        convertImagesToJPEG, quality);
2997:            }
2998:
2999:            /** Gets a <CODE>Graphics2D</CODE> to print on. The graphics
3000:             * are translated to PDF commands.
3001:             * @param width
3002:             * @param height
3003:             * @param convertImagesToJPEG
3004:             * @param quality
3005:             * @param printerJob
3006:             * @return a Graphics2D object
3007:             */
3008:            public java.awt.Graphics2D createPrinterGraphicsShapes(float width,
3009:                    float height, boolean convertImagesToJPEG, float quality,
3010:                    PrinterJob printerJob) {
3011:                return new PdfPrinterGraphics2D(this , width, height, null,
3012:                        true, convertImagesToJPEG, quality, printerJob);
3013:            }
3014:
3015:            /** Gets a <CODE>Graphics2D</CODE> to write on. The graphics
3016:             * are translated to PDF commands.
3017:             * @param width the width of the panel
3018:             * @param height the height of the panel
3019:             * @param fontMapper the mapping from awt fonts to <CODE>BaseFont</CODE>
3020:             * @return a <CODE>Graphics2D</CODE>
3021:             */
3022:            public java.awt.Graphics2D createGraphics(float width,
3023:                    float height, FontMapper fontMapper) {
3024:                return new PdfGraphics2D(this , width, height, fontMapper,
3025:                        false, false, 0);
3026:            }
3027:
3028:            /** Gets a <CODE>Graphics2D</CODE> to print on. The graphics
3029:             * are translated to PDF commands.
3030:             * @param width the width of the panel
3031:             * @param height the height of the panel
3032:             * @param fontMapper the mapping from awt fonts to <CODE>BaseFont</CODE>
3033:             * @param printerJob a printer job
3034:             * @return a <CODE>Graphics2D</CODE>
3035:             */
3036:            public java.awt.Graphics2D createPrinterGraphics(float width,
3037:                    float height, FontMapper fontMapper, PrinterJob printerJob) {
3038:                return new PdfPrinterGraphics2D(this , width, height,
3039:                        fontMapper, false, false, 0, printerJob);
3040:            }
3041:
3042:            /** Gets a <CODE>Graphics2D</CODE> to write on. The graphics
3043:             * are translated to PDF commands.
3044:             * @param width the width of the panel
3045:             * @param height the height of the panel
3046:             * @param fontMapper the mapping from awt fonts to <CODE>BaseFont</CODE>
3047:             * @param convertImagesToJPEG converts awt images to jpeg before inserting in pdf
3048:             * @param quality the quality of the jpeg
3049:             * @return a <CODE>Graphics2D</CODE>
3050:             */
3051:            public java.awt.Graphics2D createGraphics(float width,
3052:                    float height, FontMapper fontMapper,
3053:                    boolean convertImagesToJPEG, float quality) {
3054:                return new PdfGraphics2D(this , width, height, fontMapper,
3055:                        false, convertImagesToJPEG, quality);
3056:            }
3057:
3058:            /** Gets a <CODE>Graphics2D</CODE> to print on. The graphics
3059:             * are translated to PDF commands.
3060:             * @param width the width of the panel
3061:             * @param height the height of the panel
3062:             * @param fontMapper the mapping from awt fonts to <CODE>BaseFont</CODE>
3063:             * @param convertImagesToJPEG converts awt images to jpeg before inserting in pdf
3064:             * @param quality the quality of the jpeg
3065:             * @param printerJob a printer job
3066:             * @return a <CODE>Graphics2D</CODE>
3067:             */
3068:            public java.awt.Graphics2D createPrinterGraphics(float width,
3069:                    float height, FontMapper fontMapper,
3070:                    boolean convertImagesToJPEG, float quality,
3071:                    PrinterJob printerJob) {
3072:                return new PdfPrinterGraphics2D(this , width, height,
3073:                        fontMapper, false, convertImagesToJPEG, quality,
3074:                        printerJob);
3075:            }
3076:
3077:            PageResources getPageResources() {
3078:                return pdf.getPageResources();
3079:            }
3080:
3081:            /** Sets the graphic state
3082:             * @param gstate the graphic state
3083:             */
3084:            public void setGState(PdfGState gstate) {
3085:                PdfObject obj[] = writer.addSimpleExtGState(gstate);
3086:                PageResources prs = getPageResources();
3087:                PdfName name = prs.addExtGState((PdfName) obj[0],
3088:                        (PdfIndirectReference) obj[1]);
3089:                content.append(name.getBytes()).append(" gs").append_i(
3090:                        separator);
3091:            }
3092:
3093:            /**
3094:             * Begins a graphic block whose visibility is controled by the <CODE>layer</CODE>.
3095:             * Blocks can be nested. Each block must be terminated by an {@link #endLayer()}.<p>
3096:             * Note that nested layers with {@link PdfLayer#addChild(PdfLayer)} only require a single
3097:             * call to this method and a single call to {@link #endLayer()}; all the nesting control
3098:             * is built in.
3099:             * @param layer the layer
3100:             */
3101:            public void beginLayer(PdfOCG layer) {
3102:                if ((layer instanceof  PdfLayer)
3103:                        && ((PdfLayer) layer).getTitle() != null)
3104:                    throw new IllegalArgumentException("A title is not a layer");
3105:                if (layerDepth == null)
3106:                    layerDepth = new ArrayList();
3107:                if (layer instanceof  PdfLayerMembership) {
3108:                    layerDepth.add(new Integer(1));
3109:                    beginLayer2(layer);
3110:                    return;
3111:                }
3112:                int n = 0;
3113:                PdfLayer la = (PdfLayer) layer;
3114:                while (la != null) {
3115:                    if (la.getTitle() == null) {
3116:                        beginLayer2(la);
3117:                        ++n;
3118:                    }
3119:                    la = la.getParent();
3120:                }
3121:                layerDepth.add(new Integer(n));
3122:            }
3123:
3124:            private void beginLayer2(PdfOCG layer) {
3125:                PdfName name = (PdfName) writer.addSimpleProperty(layer, layer
3126:                        .getRef())[0];
3127:                PageResources prs = getPageResources();
3128:                name = prs.addProperty(name, layer.getRef());
3129:                content.append("/OC ").append(name.getBytes()).append(" BDC")
3130:                        .append_i(separator);
3131:            }
3132:
3133:            /**
3134:             * Ends a layer controled graphic block. It will end the most recent open block.
3135:             */
3136:            public void endLayer() {
3137:                int n = 1;
3138:                if (layerDepth != null && !layerDepth.isEmpty()) {
3139:                    n = ((Integer) layerDepth.get(layerDepth.size() - 1))
3140:                            .intValue();
3141:                    layerDepth.remove(layerDepth.size() - 1);
3142:                }
3143:                while (n-- > 0)
3144:                    content.append("EMC").append_i(separator);
3145:            }
3146:
3147:            /** Concatenates a transformation to the current transformation
3148:             * matrix.
3149:             * @param af the transformation
3150:             */
3151:            public void transform(AffineTransform af) {
3152:                double arr[] = new double[6];
3153:                af.getMatrix(arr);
3154:                content.append(arr[0]).append(' ').append(arr[1]).append(' ')
3155:                        .append(arr[2]).append(' ');
3156:                content.append(arr[3]).append(' ').append(arr[4]).append(' ')
3157:                        .append(arr[5]).append(" cm").append_i(separator);
3158:            }
3159:
3160:            void addAnnotation(PdfAnnotation annot) {
3161:                writer.addAnnotation(annot);
3162:            }
3163:
3164:            /**
3165:             * Sets the default colorspace.
3166:             * @param name the name of the colorspace. It can be <CODE>PdfName.DEFAULTGRAY</CODE>, <CODE>PdfName.DEFAULTRGB</CODE>
3167:             * or <CODE>PdfName.DEFAULTCMYK</CODE>
3168:             * @param obj the colorspace. A <CODE>null</CODE> or <CODE>PdfNull</CODE> removes any colorspace with the same name
3169:             */
3170:            public void setDefaultColorspace(PdfName name, PdfObject obj) {
3171:                PageResources prs = getPageResources();
3172:                prs.addDefaultColor(name, obj);
3173:            }
3174:
3175:            /**
3176:             * Begins a marked content sequence. This sequence will be tagged with the structure <CODE>struc</CODE>.
3177:             * The same structure can be used several times to connect text that belongs to the same logical segment
3178:             * but is in a different location, like the same paragraph crossing to another page, for example.
3179:             * @param struc the tagging structure
3180:             */
3181:            public void beginMarkedContentSequence(PdfStructureElement struc) {
3182:                PdfObject obj = struc.get(PdfName.K);
3183:                int mark = pdf.getMarkPoint();
3184:                if (obj != null) {
3185:                    PdfArray ar = null;
3186:                    if (obj.isNumber()) {
3187:                        ar = new PdfArray();
3188:                        ar.add(obj);
3189:                        struc.put(PdfName.K, ar);
3190:                    } else if (obj.isArray()) {
3191:                        ar = (PdfArray) obj;
3192:                        if (!((PdfObject) ar.getArrayList().get(0)).isNumber())
3193:                            throw new IllegalArgumentException(
3194:                                    "The structure has kids.");
3195:                    } else
3196:                        throw new IllegalArgumentException(
3197:                                "Unknown object at /K "
3198:                                        + obj.getClass().toString());
3199:                    PdfDictionary dic = new PdfDictionary(PdfName.MCR);
3200:                    dic.put(PdfName.PG, writer.getCurrentPage());
3201:                    dic.put(PdfName.MCID, new PdfNumber(mark));
3202:                    ar.add(dic);
3203:                    struc.setPageMark(writer.getPageNumber() - 1, -1);
3204:                } else {
3205:                    struc.setPageMark(writer.getPageNumber() - 1, mark);
3206:                    struc.put(PdfName.PG, writer.getCurrentPage());
3207:                }
3208:                pdf.incMarkPoint();
3209:                content.append(struc.get(PdfName.S).getBytes()).append(
3210:                        " <</MCID ").append(mark).append(">> BDC").append_i(
3211:                        separator);
3212:            }
3213:
3214:            /**
3215:             * Ends a marked content sequence
3216:             */
3217:            public void endMarkedContentSequence() {
3218:                content.append("EMC").append_i(separator);
3219:            }
3220:
3221:            /**
3222:             * Begins a marked content sequence. If property is <CODE>null</CODE> the mark will be of the type
3223:             * <CODE>BMC</CODE> otherwise it will be <CODE>BDC</CODE>.
3224:             * @param tag the tag
3225:             * @param property the property
3226:             * @param inline <CODE>true</CODE> to include the property in the content or <CODE>false</CODE>
3227:             * to include the property in the resource dictionary with the possibility of reusing
3228:             */
3229:            public void beginMarkedContentSequence(PdfName tag,
3230:                    PdfDictionary property, boolean inline) {
3231:                if (property == null) {
3232:                    content.append(tag.getBytes()).append(" BMC").append_i(
3233:                            separator);
3234:                    return;
3235:                }
3236:                content.append(tag.getBytes()).append(' ');
3237:                if (inline)
3238:                    try {
3239:                        property.toPdf(writer, content);
3240:                    } catch (Exception e) {
3241:                        throw new ExceptionConverter(e);
3242:                    }
3243:                else {
3244:                    PdfObject[] objs;
3245:                    if (writer.propertyExists(property))
3246:                        objs = writer.addSimpleProperty(property, null);
3247:                    else
3248:                        objs = writer.addSimpleProperty(property, writer
3249:                                .getPdfIndirectReference());
3250:                    PdfName name = (PdfName) objs[0];
3251:                    PageResources prs = getPageResources();
3252:                    name = prs
3253:                            .addProperty(name, (PdfIndirectReference) objs[1]);
3254:                    content.append(name.getBytes());
3255:                }
3256:                content.append(" BDC").append_i(separator);
3257:            }
3258:
3259:            /**
3260:             * This is just a shorthand to <CODE>beginMarkedContentSequence(tag, null, false)</CODE>.
3261:             * @param tag the tag
3262:             */
3263:            public void beginMarkedContentSequence(PdfName tag) {
3264:                beginMarkedContentSequence(tag, null, false);
3265:            }
3266:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.