0001: /*
0002: * Copyright (c) 2007, intarsys consulting GmbH
0003: *
0004: * Redistribution and use in source and binary forms, with or without
0005: * modification, are permitted provided that the following conditions are met:
0006: *
0007: * - Redistributions of source code must retain the above copyright notice,
0008: * this list of conditions and the following disclaimer.
0009: *
0010: * - Redistributions in binary form must reproduce the above copyright notice,
0011: * this list of conditions and the following disclaimer in the documentation
0012: * and/or other materials provided with the distribution.
0013: *
0014: * - Neither the name of intarsys nor the names of its contributors may be used
0015: * to endorse or promote products derived from this software without specific
0016: * prior written permission.
0017: *
0018: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0019: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0020: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0021: * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0022: * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0023: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0024: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0025: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0026: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0027: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0028: * POSSIBILITY OF SUCH DAMAGE.
0029: */
0030: package de.intarsys.pdf.content.common;
0031:
0032: import java.awt.geom.AffineTransform;
0033: import java.io.ByteArrayOutputStream;
0034: import java.util.ArrayList;
0035: import java.util.Iterator;
0036: import java.util.List;
0037:
0038: import de.intarsys.pdf.content.CSContent;
0039: import de.intarsys.pdf.content.CSOperation;
0040: import de.intarsys.pdf.content.CSOperators;
0041: import de.intarsys.pdf.content.CSVirtualDevice;
0042: import de.intarsys.pdf.content.ICSInterpreter;
0043: import de.intarsys.pdf.content.IContentStreamProvider;
0044: import de.intarsys.pdf.content.TextState;
0045: import de.intarsys.pdf.cos.COSArray;
0046: import de.intarsys.pdf.cos.COSDictionary;
0047: import de.intarsys.pdf.cos.COSFixed;
0048: import de.intarsys.pdf.cos.COSInteger;
0049: import de.intarsys.pdf.cos.COSName;
0050: import de.intarsys.pdf.cos.COSObject;
0051: import de.intarsys.pdf.cos.COSString;
0052: import de.intarsys.pdf.cos.COSTools;
0053: import de.intarsys.pdf.font.PDFont;
0054: import de.intarsys.pdf.font.PDFontTools;
0055: import de.intarsys.pdf.pd.IResourcesProvider;
0056: import de.intarsys.pdf.pd.PDCSDeviceCMYK;
0057: import de.intarsys.pdf.pd.PDCSDeviceRGB;
0058: import de.intarsys.pdf.pd.PDColorSpace;
0059: import de.intarsys.pdf.pd.PDExtGState;
0060: import de.intarsys.pdf.pd.PDForm;
0061: import de.intarsys.pdf.pd.PDImage;
0062: import de.intarsys.pdf.pd.PDObject;
0063: import de.intarsys.pdf.pd.PDPage;
0064: import de.intarsys.pdf.pd.PDPattern;
0065: import de.intarsys.pdf.pd.PDResources;
0066: import de.intarsys.pdf.pd.PDShading;
0067: import de.intarsys.pdf.pd.PDXObject;
0068:
0069: /**
0070: * An implementation helping to create a PDF content stream using higher level
0071: * abstractions than the PDF operators.
0072: * <p>
0073: * This object deals with two abstractions:
0074: * <p>
0075: * The {@link CSContent}, a sequence of PDF operators. The {@link CSContent}
0076: * can be read from an existing object like a {@link PDPage} or a {@link PDForm}
0077: * or can be newly created, suing the factory methods in {@link CSContent}.
0078: * <p>
0079: * The second abstraction is the {@link IResourcesProvider} for the
0080: * {@link PDResources} like Fonts, XObjects, ... that are referenced in the
0081: * {@link CSContent}. The resources of the provider are not accessed until a
0082: * resource relevant operation is created.
0083: *
0084: * <p>
0085: * This implementation is (nearly, see AffineTransform) independent of AWT or
0086: * any other window toolkit.
0087: *
0088: */
0089: public class CSCreator extends CSVirtualDevice {
0090: /** a constant for the ease of circle creation with beziers */
0091: static public final float KAPPA = 0.5522847498f;
0092:
0093: /** local constants */
0094: private static final float THOUSAND = 1000f;
0095:
0096: static public final int VALUE_COLOR_PRECISION = 3;
0097:
0098: static public final int VALUE_COORDINATE_PRECISION = 3;
0099:
0100: static public final int VALUE_DASH_PRECISION = 2;
0101:
0102: static public final int VALUE_FACTOR_PRECISION = 4;
0103:
0104: static public final int VALUE_FLATNESS_PRECISION = 3;
0105:
0106: static public final int VALUE_FONT_PRECISION = 2;
0107:
0108: static public final int VALUE_GRAY_PRECISION = 3;
0109:
0110: static public final int VALUE_WIDTH_PRECISION = 3;
0111:
0112: /**
0113: * Create a {@link CSCreator} on an existing {@link CSContent}. The content
0114: * may be read from a PDPage or a PDForm or can be completely new.
0115: * <p>
0116: * This is the most basic factory method where you have the freedom to
0117: * decide where the content comes from, where the resources come frome and
0118: * wher the content will be used.
0119: *
0120: * @param content
0121: * The content stream to write to.
0122: * @param resourcesProvider
0123: * The provider for the {@link PDResources} that contain the
0124: * resources referenced in the CSContent.
0125: *
0126: * @return The new {@link CSCreator}
0127: */
0128: static public CSCreator createFromContent(CSContent content,
0129: IResourcesProvider resourcesProvider) {
0130: CSCreator result = new CSCreator(content, null,
0131: resourcesProvider);
0132: return result;
0133: }
0134:
0135: /**
0136: * Create a {@link CSCreator} on a newly created {@link CSContent}. The
0137: * content is linked with the {@link IContentStreamProvider} and flushed to
0138: * it when calling "flush".
0139: *
0140: * @param provider
0141: * The provider whose content stream will be replaced with the
0142: * result of this {@link CSCreator}
0143: *
0144: * @return The new {@link CSCreator}
0145: */
0146: static public CSCreator createNew(IContentStreamProvider provider) {
0147: CSContent content = CSContent.createNew();
0148: CSCreator result = new CSCreator(content, provider, provider);
0149: return result;
0150: }
0151:
0152: /**
0153: * Create a {@link CSCreator} on a newly created {@link CSContent}. The
0154: * content is not linked with the provider, which is only used the a
0155: * {@link IResourcesProvider}. The resulting content can be accessed using
0156: * "getContent".
0157: *
0158: * @param provider
0159: * The provider for resources within the new {@link CSContent}.
0160: *
0161: * @return The new {@link CSCreator}
0162: */
0163: static public CSCreator createNewDetached(
0164: IResourcesProvider provider) {
0165: CSContent content = CSContent.createNew();
0166: CSCreator result = new CSCreator(content, null, provider);
0167: return result;
0168: }
0169:
0170: /**
0171: * Create a {@link CSCreator} on an existing {@link CSContent} that will be
0172: * read from the {@link IContentStreamProvider}. The old contents will be
0173: * preserved, all operations are concatenated. The content is linked with
0174: * the {@link IContentStreamProvider} and flushed to it when calling
0175: * "flush".
0176: *
0177: * @param provider
0178: * The provider whose content stream will be replaced with the
0179: * result of this {@link CSCreator}
0180: *
0181: * @return The new {@link CSCreator}
0182: */
0183: static public CSCreator createFromProvider(
0184: IContentStreamProvider provider) {
0185: CSCreator result = new CSCreator(provider.getContentStream(),
0186: provider, provider);
0187: return result;
0188: }
0189:
0190: /** The underlying content stream represenation. */
0191: private final CSContent content;
0192:
0193: /**
0194: * The resource dictionary for the objects referenced from the content
0195: * stream
0196: */
0197: private PDResources resources;
0198:
0199: /**
0200: * An object that will provide resources for the content stream.
0201: * <p>
0202: * The provider is accessed only if it is needed by kind of operations
0203: * performed, for example "textSetFont".
0204: */
0205: private final IResourcesProvider resourcesProvider;
0206:
0207: /**
0208: * An object that will provide access to the content stream and the
0209: * containing object.
0210: */
0211: private final IContentStreamProvider contentStreamProvider;
0212:
0213: /**
0214: * A temporary buffer for strings to be rendered.
0215: *
0216: * <p>
0217: * String objects are kept here to optimize and use the rendereing of string
0218: * arrays if possible.
0219: * </p>
0220: */
0221: private List strings;
0222:
0223: /**
0224: * A buffer holding text runs that are positioned in continuous sequence so
0225: * that we can optimze and keep the string together.
0226: */
0227: private ByteArrayOutputStream textBuffer;
0228:
0229: /**
0230: * Flag if we a re currently in text mode.
0231: *
0232: * <p>
0233: * Text mode is entered via "textBegin"
0234: * </p>
0235: */
0236: private boolean textMode = false;
0237:
0238: /**
0239: * Create a {@link CSCreator}
0240: *
0241: * @param content
0242: * The content stream to write to.
0243: */
0244: protected CSCreator(CSContent content,
0245: IContentStreamProvider contentStreamProvider,
0246: IResourcesProvider resourcesProvider) {
0247: super ();
0248: this .content = content;
0249: this .contentStreamProvider = contentStreamProvider;
0250: this .resourcesProvider = resourcesProvider;
0251: // open automagically...
0252: open(null);
0253: }
0254:
0255: /*
0256: * (non-Javadoc)
0257: *
0258: * @see de.intarsys.pdf.content.CSVirtualDevice#open(de.intarsys.pdf.content.ICSInterpreter)
0259: */
0260: public void open(ICSInterpreter pInterpreter) {
0261: super .open(pInterpreter);
0262: resetStrings();
0263: }
0264:
0265: /*
0266: * (non-Javadoc)
0267: *
0268: * @see de.intarsys.pdf.content.CSDeviceAdapter#compatibilityBegin()
0269: */
0270: public void compatibilityBegin() {
0271: super .compatibilityBegin();
0272: CSOperation operation = new CSOperation(CSOperators.CSO_BX);
0273: getContent().addOperation(operation);
0274: }
0275:
0276: /*
0277: * (non-Javadoc)
0278: *
0279: * @see de.intarsys.pdf.content.CSDeviceAdapter#compatibilityEnd()
0280: */
0281: public void compatibilityEnd() {
0282: super .compatibilityEnd();
0283: CSOperation operation = new CSOperation(CSOperators.CSO_EX);
0284: getContent().addOperation(operation);
0285: }
0286:
0287: /**
0288: * Copy all operations from <code>otherContent</code> to <code>this</code>.
0289: * <p>
0290: * Currently no resources are copied for <code>otherContent</code>
0291: *
0292: * @param otherContent
0293: * The source of the graphic operations.
0294: */
0295: public void copy(CSContent otherContent) {
0296: int len = otherContent.size();
0297: for (int i = 0; i < len; i++) {
0298: CSOperation operation = otherContent.getOperation(i);
0299: operationAdd(operation);
0300: }
0301: }
0302:
0303: /*
0304: * (non-Javadoc)
0305: *
0306: * @see de.intarsys.pdf.content.CSDeviceAdapter#doShading(de.intarsys.pdf.cos.COSName,
0307: * de.intarsys.pdf.pd.PDShading)
0308: */
0309: public void doShading(COSName name, PDShading shading) {
0310: textEnd();
0311: name = checkResource(PDResources.CN_RT_Shading, PDShading.META,
0312: name, shading);
0313: CSOperation operation = new CSOperation(CSOperators.CSO_sh);
0314: operation.addOperand(name);
0315: getContent().addOperation(operation);
0316: }
0317:
0318: /*
0319: * (non-Javadoc)
0320: *
0321: * @see de.intarsys.pdf.content.CSDeviceAdapter#doXObject(de.intarsys.pdf.cos.COSName,
0322: * de.intarsys.pdf.pd.PDXObject)
0323: */
0324: public void doXObject(COSName name, PDXObject xObject) {
0325: textEnd();
0326: name = checkResource(PDResources.CN_RT_XObject, PDXObject.META,
0327: name, xObject);
0328: // do not call super - this would "expand" the XObject
0329: CSOperation operation = new CSOperation(CSOperators.CSO_Do);
0330: operation.addOperand(name);
0331: getContent().addOperation(operation);
0332: }
0333:
0334: /**
0335: * Flush all pending operations on the stream.
0336: * <p>
0337: * This must be called before the <code>getContent</code> operation is
0338: * valid.
0339: */
0340: public void flush() {
0341: textEnd();
0342: if (getContentStreamProvider() != null) {
0343: getContentStreamProvider().setContentStream(getContent());
0344: }
0345: }
0346:
0347: /*
0348: * (non-Javadoc)
0349: *
0350: * @see de.intarsys.pdf.content.CSDeviceAdapter#close()
0351: */
0352: public void close() {
0353: flush();
0354: super .close();
0355: }
0356:
0357: /**
0358: * The {@link CSContent} we are working on. After calling <code>flush</code>
0359: * the {@link CSContent} contains all operations stemming from calls to
0360: * this.
0361: *
0362: * @return The {@link CSContent} we are working on.
0363: */
0364: public CSContent getContent() {
0365: return content;
0366: }
0367:
0368: protected PDResources getResources() {
0369: if (resources == null) {
0370: resources = getResourcesProvider().getResources();
0371: if (resources == null) {
0372: resources = (PDResources) PDResources.META.createNew();
0373: getResourcesProvider().setResources(resources);
0374: }
0375: }
0376: return resources;
0377: }
0378:
0379: /**
0380: * The {@link IResourcesProvider} associated with this.
0381: *
0382: * @return The {@link IResourcesProvider} associated with this.
0383: */
0384: public IResourcesProvider getResourcesProvider() {
0385: return resourcesProvider;
0386: }
0387:
0388: protected List getStrings() {
0389: return strings;
0390: }
0391:
0392: protected ByteArrayOutputStream getTextBuffer() {
0393: return textBuffer;
0394: }
0395:
0396: /*
0397: * (non-Javadoc)
0398: *
0399: * @see de.intarsys.pdf.content.CSDeviceAdapter#inlineImage(de.intarsys.pdf.pd.PDImage)
0400: */
0401: public void inlineImage(PDImage img) {
0402: // ignore
0403: /*
0404: * CSOperation operationBI = new CSOperation(CSOperators.CSO_BI);
0405: * getContent().addOperation(operationBI); CSOperation operationID = new
0406: * CSOperation(CSOperators.CSO_ID);
0407: * getContent().addOperation(operationID); CSOperation operationEI = new
0408: * CSOperation(CSOperators.CSO_EI);
0409: * operationEI.addOperand(COSString.create(img.cosGetStream()
0410: * .getDecodedBytes())); getContent().addOperation(operationEI);
0411: */
0412: }
0413:
0414: /**
0415: * Answer <code>true</code> if the actual font in the text state is equal
0416: * to <code>queryFont</code> and <code>queryFontSize</code>.
0417: *
0418: * @param queryFont
0419: * The font to query.
0420: * @param queryFontSize
0421: * The font size to query.
0422: *
0423: * @return true if equal
0424: */
0425: protected boolean isFont(PDFont queryFont, float queryFontSize) {
0426: TextState textState = graphicsState.textState;
0427: return ((textState.getFont() != null) && textState.getFont()
0428: .equals(queryFont))
0429: && (textState.getFontSize() == queryFontSize);
0430: }
0431:
0432: protected boolean isNonStrokeCMYKColor(float c, float m, float y,
0433: float k) {
0434: PDColorSpace colorSpace = graphicsState
0435: .getNonStrokeColorSpace();
0436: if (!(colorSpace instanceof PDCSDeviceCMYK)) {
0437: return false;
0438: }
0439: float[] colorValues = graphicsState.getNonStrokeColorValues();
0440: return (colorValues[0] == c) && (colorValues[1] == m)
0441: && (colorValues[2] == y) && (colorValues[3] == k);
0442: }
0443:
0444: protected boolean isNonStrokeRGBColor(float r, float g, float b) {
0445: PDColorSpace colorSpace = graphicsState
0446: .getNonStrokeColorSpace();
0447: if (!(colorSpace instanceof PDCSDeviceRGB)) {
0448: return false;
0449: }
0450: float[] colorValues = graphicsState.getNonStrokeColorValues();
0451: return (colorValues[0] == r) && (colorValues[1] == g)
0452: && (colorValues[2] == b);
0453: }
0454:
0455: protected boolean isStrokeCMYKColor(float c, float m, float y,
0456: float k) {
0457: PDColorSpace colorSpace = graphicsState.getStrokeColorSpace();
0458: if (!(colorSpace instanceof PDCSDeviceCMYK)) {
0459: return false;
0460: }
0461: float[] colorValues = graphicsState.getStrokeColorValues();
0462: return (colorValues[0] == c) && (colorValues[1] == m)
0463: && (colorValues[2] == y) && (colorValues[3] == k);
0464: }
0465:
0466: protected boolean isStrokeRGBColor(float r, float g, float b) {
0467: PDColorSpace colorSpace = graphicsState.getStrokeColorSpace();
0468: if (!(colorSpace instanceof PDCSDeviceRGB)) {
0469: return false;
0470: }
0471: float[] colorValues = graphicsState.getStrokeColorValues();
0472: return (colorValues[0] == r) && (colorValues[1] == g)
0473: && (colorValues[2] == b);
0474: }
0475:
0476: protected boolean isTextMode() {
0477: return textMode;
0478: }
0479:
0480: public void markedContentBegin(COSName tag) {
0481: CSOperation operation = new CSOperation(CSOperators.CSO_BMC);
0482: operation.addOperand(tag.copyOptional());
0483: getContent().addOperation(operation);
0484: }
0485:
0486: public void markedContentBeginProperties(COSName tag,
0487: COSName resourceName, COSDictionary properties) {
0488: // ignore
0489: /*
0490: * CSOperation operation = new CSOperation(CSOperators.CSO_BMC);
0491: * operation.addOperand(tag.copyOptional());
0492: * getContent().addOperation(operation);
0493: */
0494: }
0495:
0496: public void markedContentEnd() {
0497: CSOperation operation = new CSOperation(CSOperators.CSO_EMC);
0498: getContent().addOperation(operation);
0499: }
0500:
0501: public void markedContentPoint(COSName tag) {
0502: CSOperation operation = new CSOperation(CSOperators.CSO_MP);
0503: operation.addOperand(tag.copyOptional());
0504: getContent().addOperation(operation);
0505: }
0506:
0507: public void markedContentPointProperties(COSName tag,
0508: COSName resourceName, COSDictionary properties) {
0509: // ignore
0510: /*
0511: * CSOperation operation = new CSOperation(CSOperators.CSO_BMC);
0512: * operation.addOperand(tag.copyOptional());
0513: * getContent().addOperation(operation);
0514: */
0515: }
0516:
0517: protected void operationAdd(CSOperation operation) {
0518: getContent().addOperation(operation);
0519: }
0520:
0521: /*
0522: * (non-Javadoc)
0523: *
0524: * @see de.intarsys.pdf.content.CSDeviceAdapter#pathClipEvenOdd()
0525: */
0526: public void pathClipEvenOdd() {
0527: textEnd();
0528: CSOperation operation = new CSOperation(CSOperators.CSO_Wstar);
0529: getContent().addOperation(operation);
0530: }
0531:
0532: /*
0533: * (non-Javadoc)
0534: *
0535: * @see de.intarsys.pdf.content.CSDeviceAdapter#pathClipNonZero()
0536: */
0537: public void pathClipNonZero() {
0538: textEnd();
0539: CSOperation operation = new CSOperation(CSOperators.CSO_W);
0540: getContent().addOperation(operation);
0541: }
0542:
0543: /*
0544: * (non-Javadoc)
0545: *
0546: * @see de.intarsys.pdf.content.CSDeviceAdapter#pathClose()
0547: */
0548: public void pathClose() {
0549: textEnd();
0550: CSOperation operation = new CSOperation(CSOperators.CSO_h);
0551: getContent().addOperation(operation);
0552: }
0553:
0554: /*
0555: * (non-Javadoc)
0556: *
0557: * @see de.intarsys.pdf.content.CSDeviceAdapter#pathCloseFillStrokeEvenOdd()
0558: */
0559: public void pathCloseFillStrokeEvenOdd() {
0560: textEnd();
0561: CSOperation operation = new CSOperation(CSOperators.CSO_bstar);
0562: getContent().addOperation(operation);
0563: }
0564:
0565: /*
0566: * (non-Javadoc)
0567: *
0568: * @see de.intarsys.pdf.content.CSDeviceAdapter#pathCloseFillStrokeNonZero()
0569: */
0570: public void pathCloseFillStrokeNonZero() {
0571: textEnd();
0572: CSOperation operation = new CSOperation(CSOperators.CSO_b);
0573: getContent().addOperation(operation);
0574: }
0575:
0576: /*
0577: * (non-Javadoc)
0578: *
0579: * @see de.intarsys.pdf.content.CSDeviceAdapter#pathCloseStroke()
0580: */
0581: public void pathCloseStroke() {
0582: textEnd();
0583: CSOperation operation = new CSOperation(CSOperators.CSO_s);
0584: getContent().addOperation(operation);
0585: }
0586:
0587: /*
0588: * (non-Javadoc)
0589: *
0590: * @see de.intarsys.pdf.content.CSDeviceAdapter#pathEnd()
0591: */
0592: public void pathEnd() {
0593: textEnd();
0594: CSOperation operation = new CSOperation(CSOperators.CSO_n);
0595: getContent().addOperation(operation);
0596: }
0597:
0598: /*
0599: * (non-Javadoc)
0600: *
0601: * @see de.intarsys.pdf.content.CSDeviceAdapter#pathFillEvenOdd()
0602: */
0603: public void pathFillEvenOdd() {
0604: textEnd();
0605: CSOperation operation = new CSOperation(CSOperators.CSO_fstar);
0606: getContent().addOperation(operation);
0607: }
0608:
0609: /*
0610: * (non-Javadoc)
0611: *
0612: * @see de.intarsys.pdf.content.CSDeviceAdapter#pathFillNonZero()
0613: */
0614: public void pathFillNonZero() {
0615: textEnd();
0616: CSOperation operation = new CSOperation(CSOperators.CSO_f);
0617: getContent().addOperation(operation);
0618: }
0619:
0620: /*
0621: * (non-Javadoc)
0622: *
0623: * @see de.intarsys.pdf.content.CSDeviceAdapter#pathFillStrokeEvenOdd()
0624: */
0625: public void pathFillStrokeEvenOdd() {
0626: textEnd();
0627: CSOperation operation = new CSOperation(CSOperators.CSO_Bstar);
0628: getContent().addOperation(operation);
0629: }
0630:
0631: /*
0632: * (non-Javadoc)
0633: *
0634: * @see de.intarsys.pdf.content.CSDeviceAdapter#pathFillStrokeNonZero()
0635: */
0636: public void pathFillStrokeNonZero() {
0637: textEnd();
0638: CSOperation operation = new CSOperation(CSOperators.CSO_B);
0639: getContent().addOperation(operation);
0640: }
0641:
0642: /*
0643: * (non-Javadoc)
0644: *
0645: * @see de.intarsys.pdf.content.CSDeviceAdapter#pathStroke()
0646: */
0647: public void pathStroke() {
0648: textEnd();
0649: CSOperation operation = new CSOperation(CSOperators.CSO_S);
0650: getContent().addOperation(operation);
0651: }
0652:
0653: /**
0654: * Draw a circle. The center of the circle is at <code>x</code>,
0655: * <code>y</code> in user space. <code>r</code> defines the radius.
0656: *
0657: * @param x
0658: * The x coordinate of the center.
0659: * @param y
0660: * The y coordinate of the center.
0661: * @param r
0662: * The radius
0663: */
0664: public void penCircle(float x, float y, float r) {
0665: penEllipse(x, y, r, r);
0666: }
0667:
0668: /*
0669: * (non-Javadoc)
0670: *
0671: * @see de.intarsys.pdf.content.CSDeviceAdapter#penCurveToC(float, float,
0672: * float, float, float, float)
0673: */
0674: public void penCurveToC(float x1, float y1, float x2, float y2,
0675: float x3, float y3) {
0676: textEnd();
0677: CSOperation operation = new CSOperation(CSOperators.CSO_c);
0678: operation.addOperand(COSFixed.create(x1));
0679: operation.addOperand(COSFixed.create(y1));
0680: operation.addOperand(COSFixed.create(x2));
0681: operation.addOperand(COSFixed.create(y2));
0682: operation.addOperand(COSFixed.create(x3));
0683: operation.addOperand(COSFixed.create(y3));
0684: getContent().addOperation(operation);
0685: }
0686:
0687: /*
0688: * (non-Javadoc)
0689: *
0690: * @see de.intarsys.pdf.content.CSDeviceAdapter#penCurveToV(float, float,
0691: * float, float)
0692: */
0693: public void penCurveToV(float x2, float y2, float x3, float y3) {
0694: textEnd();
0695: CSOperation operation = new CSOperation(CSOperators.CSO_v);
0696: operation.addOperand(COSFixed.create(x2));
0697: operation.addOperand(COSFixed.create(y2));
0698: operation.addOperand(COSFixed.create(x3));
0699: operation.addOperand(COSFixed.create(y3));
0700: getContent().addOperation(operation);
0701: }
0702:
0703: /*
0704: * (non-Javadoc)
0705: *
0706: * @see de.intarsys.pdf.content.CSDeviceAdapter#penCurveToY(float, float,
0707: * float, float)
0708: */
0709: public void penCurveToY(float x1, float y1, float x3, float y3) {
0710: textEnd();
0711: CSOperation operation = new CSOperation(CSOperators.CSO_y);
0712: operation.addOperand(COSFixed.create(x1));
0713: operation.addOperand(COSFixed.create(y1));
0714: operation.addOperand(COSFixed.create(x3));
0715: operation.addOperand(COSFixed.create(y3));
0716: getContent().addOperation(operation);
0717: }
0718:
0719: /**
0720: * Draw an ellipse. The center of the ellipse is at <code>x</code>,
0721: * <code>y</code> in user space. <code>rx</code> and <code>ry</code>
0722: * define the radius in x and y direction respectively.
0723: *
0724: * @param x
0725: * The x coordinate of the center.
0726: * @param y
0727: * The y coordinate of the center.
0728: * @param rx
0729: * The radius in x direction
0730: * @param ry
0731: * The radius in y direction
0732: */
0733: public void penEllipse(float x, float y, float rx, float ry) {
0734: textEnd();
0735: float rxkappa = rx * KAPPA;
0736: float rykappa = ry * KAPPA;
0737: penMoveTo(x + rx, y);
0738: penCurveToC(x + rx, y + rykappa, x + rxkappa, y + ry, x, y + ry);
0739: penCurveToC(x - rxkappa, y + ry, x - rx, y + rykappa, x - rx, y);
0740: penCurveToC(x - rx, y - rykappa, x - rxkappa, y - ry, x, y - ry);
0741: penCurveToC(x + rxkappa, y - ry, x + rx, y - rykappa, x + rx, y);
0742: }
0743:
0744: /*
0745: * (non-Javadoc)
0746: *
0747: * @see de.intarsys.pdf.content.CSDeviceAdapter#penLineTo(float, float)
0748: */
0749: public void penLineTo(float x, float y) {
0750: textEnd();
0751: CSOperation operation = new CSOperation(CSOperators.CSO_l);
0752: operation.addOperand(COSFixed.create(x,
0753: VALUE_COORDINATE_PRECISION));
0754: operation.addOperand(COSFixed.create(y,
0755: VALUE_COORDINATE_PRECISION));
0756: getContent().addOperation(operation);
0757: }
0758:
0759: /*
0760: * (non-Javadoc)
0761: *
0762: * @see de.intarsys.pdf.content.CSDeviceAdapter#penMoveTo(float, float)
0763: */
0764: public void penMoveTo(float x, float y) {
0765: textEnd();
0766: CSOperation operation = new CSOperation(CSOperators.CSO_m);
0767: operation.addOperand(COSFixed.create(x,
0768: VALUE_COORDINATE_PRECISION));
0769: operation.addOperand(COSFixed.create(y,
0770: VALUE_COORDINATE_PRECISION));
0771: getContent().addOperation(operation);
0772: }
0773:
0774: /*
0775: * (non-Javadoc)
0776: *
0777: * @see de.intarsys.pdf.content.CSDeviceAdapter#penRectangle(float, float,
0778: * float, float)
0779: */
0780: public void penRectangle(float x, float y, float w, float h) {
0781: textEnd();
0782: CSOperation operation = new CSOperation(CSOperators.CSO_re);
0783: operation.addOperand(COSFixed.create(x,
0784: VALUE_COORDINATE_PRECISION));
0785: operation.addOperand(COSFixed.create(y,
0786: VALUE_COORDINATE_PRECISION));
0787: operation.addOperand(COSFixed.create(w,
0788: VALUE_COORDINATE_PRECISION));
0789: operation.addOperand(COSFixed.create(h,
0790: VALUE_COORDINATE_PRECISION));
0791: getContent().addOperation(operation);
0792: }
0793:
0794: protected void resetStrings() {
0795: strings = new ArrayList();
0796: resetTextBuffer();
0797: }
0798:
0799: protected void resetTextBuffer() {
0800: textBuffer = new ByteArrayOutputStream();
0801: }
0802:
0803: /*
0804: * (non-Javadoc)
0805: *
0806: * @see de.intarsys.pdf.content.CSDeviceAdapter#restoreState()
0807: */
0808: public void restoreState() {
0809: textEnd();
0810: CSOperation operation = new CSOperation(CSOperators.CSO_Q);
0811: getContent().addOperation(operation);
0812: super .restoreState();
0813: }
0814:
0815: /*
0816: * (non-Javadoc)
0817: *
0818: * @see de.intarsys.pdf.content.CSDeviceAdapter#saveState()
0819: */
0820: public void saveState() {
0821: textEnd();
0822: CSOperation operation = new CSOperation(CSOperators.CSO_q);
0823: getContent().addOperation(operation);
0824: super .saveState();
0825: }
0826:
0827: /**
0828: * Convenience method to access "setLineDash".
0829: *
0830: * @param unitsOn
0831: * @param unitsOff
0832: * @param phase
0833: */
0834: public void setLineDash(float unitsOn, float unitsOff, float phase) {
0835: setLineDash(new float[] { unitsOn, unitsOff }, phase);
0836: }
0837:
0838: /*
0839: * (non-Javadoc)
0840: *
0841: * @see de.intarsys.pdf.content.CSDeviceAdapter#setExtendedState(de.intarsys.pdf.cos.COSName,
0842: * de.intarsys.pdf.pd.PDExtGState)
0843: */
0844: public void setExtendedState(COSName name, PDExtGState gstate) {
0845: streamEnd();
0846: name = checkResource(PDResources.CN_RT_ExtGState,
0847: PDExtGState.META, name, gstate);
0848: super .setExtendedState(name, gstate);
0849: CSOperation operation = new CSOperation(CSOperators.CSO_gs);
0850: operation.addOperand(name);
0851: getContent().addOperation(operation);
0852: }
0853:
0854: /*
0855: * (non-Javadoc)
0856: *
0857: * @see de.intarsys.pdf.content.CSDeviceAdapter#setFlatnessTolerance(float)
0858: */
0859: public void setFlatnessTolerance(float flatness) {
0860: streamEnd();
0861: super .setFlatnessTolerance(flatness);
0862: CSOperation operation = new CSOperation(CSOperators.CSO_i);
0863: operation.addOperand(COSFixed.create(flatness,
0864: VALUE_FLATNESS_PRECISION));
0865: getContent().addOperation(operation);
0866: }
0867:
0868: /*
0869: * (non-Javadoc)
0870: *
0871: * @see de.intarsys.pdf.content.CSDeviceAdapter#setLineCap(int)
0872: */
0873: public void setLineCap(int style) {
0874: streamEnd();
0875: super .setLineCap(style);
0876: CSOperation operation = new CSOperation(CSOperators.CSO_J);
0877: operation.addOperand(COSInteger.create(style));
0878: getContent().addOperation(operation);
0879: }
0880:
0881: /*
0882: * (non-Javadoc)
0883: *
0884: * @see de.intarsys.pdf.content.CSDeviceAdapter#setDash(float[], float)
0885: */
0886: public void setLineDash(float[] pattern, float phase) {
0887: streamEnd();
0888: super .setLineDash(pattern, phase);
0889: CSOperation operation = new CSOperation(CSOperators.CSO_d);
0890: operation.addOperand(COSTools.createObject(pattern));
0891: operation.addOperand(COSFixed.create(phase,
0892: VALUE_DASH_PRECISION));
0893: getContent().addOperation(operation);
0894: }
0895:
0896: /*
0897: * (non-Javadoc)
0898: *
0899: * @see de.intarsys.pdf.content.CSDeviceAdapter#setLineJoin(int)
0900: */
0901: public void setLineJoin(int style) {
0902: streamEnd();
0903: super .setLineJoin(style);
0904: CSOperation operation = new CSOperation(CSOperators.CSO_j);
0905: operation.addOperand(COSInteger.create(style));
0906: getContent().addOperation(operation);
0907: }
0908:
0909: /*
0910: * (non-Javadoc)
0911: *
0912: * @see de.intarsys.pdf.content.CSDeviceAdapter#setLineWidth(float)
0913: */
0914: public void setLineWidth(float w) {
0915: if (graphicsState.getLineWidth() == w) {
0916: return;
0917: }
0918: streamEnd();
0919: super .setLineWidth(w);
0920: CSOperation operation = new CSOperation(CSOperators.CSO_w);
0921: operation.addOperand(COSFixed.create(w, VALUE_WIDTH_PRECISION));
0922: getContent().addOperation(operation);
0923: }
0924:
0925: /*
0926: * (non-Javadoc)
0927: *
0928: * @see de.intarsys.pdf.content.CSDeviceAdapter#setMiterLimit(float)
0929: */
0930: public void setMiterLimit(float miterLimit) {
0931: streamEnd();
0932: super .setMiterLimit(miterLimit);
0933: CSOperation operation = new CSOperation(CSOperators.CSO_M);
0934: operation.addOperand(COSFixed.create(miterLimit));
0935: getContent().addOperation(operation);
0936: }
0937:
0938: /*
0939: * (non-Javadoc)
0940: *
0941: * @see de.intarsys.pdf.content.CSDeviceAdapter#setNonStrokeColorCMYK(float,
0942: * float, float, float)
0943: */
0944: public void setNonStrokeColorCMYK(float c, float m, float y, float k) {
0945: c = Math.max(0, Math.min(1, c));
0946: m = Math.max(0, Math.min(1, m));
0947: y = Math.max(0, Math.min(1, y));
0948: k = Math.max(0, Math.min(1, k));
0949: if (isNonStrokeCMYKColor(c, m, y, k)) {
0950: return;
0951: }
0952: streamEnd();
0953: PDColorSpace pdColorSpace = PDColorSpace
0954: .getSingleton(PDColorSpace.CN_CS_DeviceCMYK);
0955: graphicsState
0956: .setNonStrokeColorValues(new float[] { c, m, y, k });
0957: graphicsState.setNonStrokeColorSpace(pdColorSpace);
0958: CSOperation operation = new CSOperation(CSOperators.CSO_k);
0959: operation.addOperand(COSFixed.create(c, VALUE_COLOR_PRECISION));
0960: operation.addOperand(COSFixed.create(m, VALUE_COLOR_PRECISION));
0961: operation.addOperand(COSFixed.create(y, VALUE_COLOR_PRECISION));
0962: operation.addOperand(COSFixed.create(k, VALUE_COLOR_PRECISION));
0963: getContent().addOperation(operation);
0964: }
0965:
0966: /*
0967: * (non-Javadoc)
0968: *
0969: * @see de.intarsys.pdf.content.CSDeviceAdapter#setNonStrokeColorGray(float)
0970: */
0971: public void setNonStrokeColorGray(float gray) {
0972: streamEnd();
0973: PDColorSpace pdColorSpace = PDColorSpace
0974: .getSingleton(PDColorSpace.CN_CS_DeviceGray);
0975: graphicsState.setNonStrokeColorValues(new float[] { gray });
0976: graphicsState.setNonStrokeColorSpace(pdColorSpace);
0977: CSOperation operation = new CSOperation(CSOperators.CSO_g);
0978: operation.addOperand(COSFixed
0979: .create(gray, VALUE_GRAY_PRECISION));
0980: getContent().addOperation(operation);
0981: }
0982:
0983: /*
0984: * (non-Javadoc)
0985: *
0986: * @see de.intarsys.pdf.content.CSDeviceAdapter#setNonStrokeColorRGB(float,
0987: * float, float)
0988: */
0989: public void setNonStrokeColorRGB(float red, float green, float blue) {
0990: red = Math.max(0, Math.min(1, red));
0991: green = Math.max(0, Math.min(1, green));
0992: blue = Math.max(0, Math.min(1, blue));
0993: if (isNonStrokeRGBColor(red, green, blue)) {
0994: return;
0995: }
0996: streamEnd();
0997: PDColorSpace pdColorSpace = PDColorSpace
0998: .getSingleton(PDColorSpace.CN_CS_DeviceRGB);
0999: graphicsState.setNonStrokeColorSpace(pdColorSpace);
1000: graphicsState.setNonStrokeColorValues(new float[] { red, green,
1001: blue });
1002: CSOperation operation = new CSOperation(CSOperators.CSO_rg);
1003: operation.addOperand(COSFixed
1004: .create(red, VALUE_COLOR_PRECISION));
1005: operation.addOperand(COSFixed.create(green,
1006: VALUE_COLOR_PRECISION));
1007: operation.addOperand(COSFixed.create(blue,
1008: VALUE_COLOR_PRECISION));
1009: getContent().addOperation(operation);
1010: }
1011:
1012: /*
1013: * (non-Javadoc)
1014: *
1015: * @see de.intarsys.pdf.content.CSDeviceAdapter#setNonStrokeColorSpace(de.intarsys.pdf.cos.COSName,
1016: * de.intarsys.pdf.pd.PDColorSpace)
1017: */
1018: public void setNonStrokeColorSpace(COSName name,
1019: PDColorSpace colorSpace) {
1020: streamEnd();
1021: name = checkResource(PDResources.CN_RT_ColorSpace,
1022: PDColorSpace.META, name, colorSpace);
1023: super .setNonStrokeColorSpace(name, colorSpace);
1024: CSOperation operation = new CSOperation(CSOperators.CSO_cs);
1025: operation.addOperand(name.copyOptional());
1026: getContent().addOperation(operation);
1027: }
1028:
1029: /*
1030: * (non-Javadoc)
1031: *
1032: * @see de.intarsys.pdf.content.CSDeviceAdapter#setNonStrokeColorValues(float[])
1033: */
1034: public void setNonStrokeColorValues(float[] values) {
1035: streamEnd();
1036: super .setNonStrokeColorValues(values);
1037: CSOperation operation = new CSOperation(CSOperators.CSO_sc);
1038: for (int i = 0; i < values.length; i++) {
1039: operation.addOperand(COSFixed.create(values[i],
1040: VALUE_COLOR_PRECISION));
1041: }
1042: getContent().addOperation(operation);
1043: }
1044:
1045: /*
1046: * (non-Javadoc)
1047: *
1048: * @see de.intarsys.pdf.content.CSDeviceAdapter#setNonStrokeColorValues(float[],
1049: * de.intarsys.pdf.cos.COSName, de.intarsys.pdf.pd.PDPattern)
1050: */
1051: public void setNonStrokeColorValues(float[] values, COSName name,
1052: PDPattern pattern) {
1053: streamEnd();
1054: name = checkResource(PDResources.CN_RT_Pattern, PDPattern.META,
1055: name, pattern);
1056: graphicsState.setNonStrokeColorValues(values);
1057: CSOperation operation = new CSOperation(CSOperators.CSO_scn);
1058: for (int i = 0; i < values.length; i++) {
1059: operation.addOperand(COSFixed.create(values[i],
1060: VALUE_COLOR_PRECISION));
1061: }
1062: if (name != null) {
1063: operation.addOperand(name.copyShallow());
1064: }
1065: getContent().addOperation(operation);
1066: }
1067:
1068: /*
1069: * (non-Javadoc)
1070: *
1071: * @see de.intarsys.pdf.content.CSDeviceAdapter#setRenderingIntent(de.intarsys.pdf.cos.COSName)
1072: */
1073: public void setRenderingIntent(COSName intent) {
1074: streamEnd();
1075: CSOperation operation = new CSOperation(CSOperators.CSO_ri);
1076: operation.addOperand(intent.copyOptional());
1077: getContent().addOperation(operation);
1078: }
1079:
1080: /*
1081: * (non-Javadoc)
1082: *
1083: * @see de.intarsys.pdf.content.CSDeviceAdapter#setStrokeColorCMYK(float,
1084: * float, float, float)
1085: */
1086: public void setStrokeColorCMYK(float cyan, float magenta,
1087: float yellow, float key) {
1088: cyan = Math.max(0, Math.min(1, cyan));
1089: magenta = Math.max(0, Math.min(1, magenta));
1090: yellow = Math.max(0, Math.min(1, yellow));
1091: key = Math.max(0, Math.min(1, key));
1092: if (isStrokeCMYKColor(cyan, magenta, yellow, key)) {
1093: return;
1094: }
1095: streamEnd();
1096: PDColorSpace pdColorSpace = PDColorSpace
1097: .getSingleton(PDColorSpace.CN_CS_DeviceCMYK);
1098: graphicsState.setStrokeColorValues(new float[] { cyan, magenta,
1099: yellow, key });
1100: graphicsState.setStrokeColorSpace(pdColorSpace);
1101: CSOperation operation = new CSOperation(CSOperators.CSO_K);
1102: operation.addOperand(COSFixed.create(cyan,
1103: VALUE_COLOR_PRECISION));
1104: operation.addOperand(COSFixed.create(magenta,
1105: VALUE_COLOR_PRECISION));
1106: operation.addOperand(COSFixed.create(yellow,
1107: VALUE_COLOR_PRECISION));
1108: operation.addOperand(COSFixed
1109: .create(key, VALUE_COLOR_PRECISION));
1110: getContent().addOperation(operation);
1111: }
1112:
1113: /*
1114: * (non-Javadoc)
1115: *
1116: * @see de.intarsys.pdf.content.CSDeviceAdapter#setStrokeColorGray(float)
1117: */
1118: public void setStrokeColorGray(float gray) {
1119: streamEnd();
1120: PDColorSpace pdColorSpace = PDColorSpace
1121: .getSingleton(PDColorSpace.CN_CS_DeviceGray);
1122: graphicsState.setStrokeColorValues(new float[] { gray });
1123: graphicsState.setStrokeColorSpace(pdColorSpace);
1124: CSOperation operation = new CSOperation(CSOperators.CSO_G);
1125: operation.addOperand(COSFixed
1126: .create(gray, VALUE_GRAY_PRECISION));
1127: getContent().addOperation(operation);
1128: }
1129:
1130: /*
1131: * (non-Javadoc)
1132: *
1133: * @see de.intarsys.pdf.content.CSDeviceAdapter#setStrokeColorRGB(float,
1134: * float, float)
1135: */
1136: public void setStrokeColorRGB(float red, float green, float blue) {
1137: red = Math.max(0, Math.min(1, red));
1138: green = Math.max(0, Math.min(1, green));
1139: blue = Math.max(0, Math.min(1, blue));
1140: if (isStrokeRGBColor(red, green, blue)) {
1141: return;
1142: }
1143: streamEnd();
1144: PDColorSpace pdColorSpace = PDColorSpace
1145: .getSingleton(PDColorSpace.CN_CS_DeviceRGB);
1146: graphicsState.setStrokeColorValues(new float[] { red, green,
1147: blue });
1148: graphicsState.setStrokeColorSpace(pdColorSpace);
1149: CSOperation operation = new CSOperation(CSOperators.CSO_RG);
1150: operation.addOperand(COSFixed
1151: .create(red, VALUE_COLOR_PRECISION));
1152: operation.addOperand(COSFixed.create(green,
1153: VALUE_COLOR_PRECISION));
1154: operation.addOperand(COSFixed.create(blue,
1155: VALUE_COLOR_PRECISION));
1156: getContent().addOperation(operation);
1157: }
1158:
1159: /*
1160: * (non-Javadoc)
1161: *
1162: * @see de.intarsys.pdf.content.CSDeviceAdapter#setStrokeColorSpace(de.intarsys.pdf.cos.COSName,
1163: * de.intarsys.pdf.pd.PDColorSpace)
1164: */
1165: public void setStrokeColorSpace(COSName name,
1166: PDColorSpace colorSpace) {
1167: streamEnd();
1168: name = checkResource(PDResources.CN_RT_ColorSpace,
1169: PDColorSpace.META, name, colorSpace);
1170: super .setStrokeColorSpace(name, colorSpace);
1171: CSOperation operation = new CSOperation(CSOperators.CSO_CS);
1172: operation.addOperand(name);
1173: getContent().addOperation(operation);
1174: }
1175:
1176: /*
1177: * (non-Javadoc)
1178: *
1179: * @see de.intarsys.pdf.content.CSDeviceAdapter#setStrokeColorValues(float[])
1180: */
1181: public void setStrokeColorValues(float[] values) {
1182: streamEnd();
1183: super .setStrokeColorValues(values);
1184: CSOperation operation = new CSOperation(CSOperators.CSO_SC);
1185: for (int i = 0; i < values.length; i++) {
1186: operation.addOperand(COSFixed.create(values[i],
1187: VALUE_COLOR_PRECISION));
1188: }
1189: getContent().addOperation(operation);
1190: }
1191:
1192: /*
1193: * (non-Javadoc)
1194: *
1195: * @see de.intarsys.pdf.content.CSDeviceAdapter#setStrokeColorValues(float[],
1196: * de.intarsys.pdf.cos.COSName, de.intarsys.pdf.pd.PDPattern)
1197: */
1198: public void setStrokeColorValues(float[] values, COSName name,
1199: PDPattern pattern) {
1200: streamEnd();
1201: name = checkResource(PDResources.CN_RT_Pattern, PDPattern.META,
1202: name, pattern);
1203: graphicsState.setStrokeColorValues(values);
1204: CSOperation operation = new CSOperation(CSOperators.CSO_SCN);
1205: for (int i = 0; i < values.length; i++) {
1206: operation.addOperand(COSFixed.create(values[i],
1207: VALUE_COLOR_PRECISION));
1208: }
1209: if (name != null) {
1210: operation.addOperand(name.copyShallow());
1211: }
1212: getContent().addOperation(operation);
1213: }
1214:
1215: protected void setTextMode(boolean b) {
1216: textMode = b;
1217: }
1218:
1219: /**
1220: * Close a currently open line.
1221: */
1222: protected void streamEnd() {
1223: streamEndRun();
1224: int size = getStrings().size();
1225: if (size == 1) {
1226: Object element = getStrings().get(0);
1227: if (element instanceof byte[]) {
1228: byte[] bytes = (byte[]) element;
1229: basicTextShow(bytes);
1230: }
1231: } else {
1232: if (size > 1) {
1233: COSArray cosStrings = COSArray.create(size);
1234: for (Iterator i = getStrings().iterator(); i.hasNext();) {
1235: Object element = i.next();
1236: if (element instanceof byte[]) {
1237: byte[] data = (byte[]) element;
1238: COSString cosString = COSString.create(data);
1239: cosStrings.add(cosString);
1240: } else {
1241: Integer move = (Integer) element;
1242: COSInteger cosMove = COSInteger.create(move
1243: .intValue());
1244: cosStrings.add(cosMove);
1245: }
1246: }
1247: streamEndShow(cosStrings);
1248: }
1249: }
1250: resetStrings();
1251: }
1252:
1253: /**
1254: * Close a currently open optimzed character sequence.
1255: */
1256: protected void streamEndRun() {
1257: if (getTextBuffer().toByteArray().length > 0) {
1258: getStrings().add(getTextBuffer().toByteArray());
1259: }
1260: resetTextBuffer();
1261: }
1262:
1263: protected void streamEndShow(COSArray theStrings) {
1264: CSOperation operation = new CSOperation(CSOperators.CSO_TJ);
1265: operation.addOperand(theStrings);
1266: getContent().addOperation(operation);
1267: for (Iterator cosObjects = theStrings.iterator(); cosObjects
1268: .hasNext();) {
1269: COSObject cosObject = (COSObject) cosObjects.next();
1270: if (cosObject instanceof COSString) {
1271: byte[] text = ((COSString) cosObject).byteValue();
1272: for (int i = 0; i < text.length; i++) {
1273: graphicsState.textState.getFont().setCharUsed(
1274: text[i]);
1275: }
1276: }
1277: }
1278: }
1279:
1280: public void textMoveTo(float x, float y) {
1281: textBegin();
1282: TextState textState = graphicsState.textState;
1283: AffineTransform tm = textState.getTextMatrix();
1284:
1285: // have we changed the baseline?
1286: float dDeltaY = y - (float) tm.getTranslateY();
1287: if (dDeltaY != 0) {
1288: // move relative to old line start
1289: textLineMoveTo(x, y);
1290: return;
1291: }
1292:
1293: // have we a x offset to current position?
1294: float dDeltaX = x - (float) tm.getTranslateX();
1295: if (dDeltaX != 0) {
1296: int iDelta = (int) ((-dDeltaX * 1000) / textState
1297: .getFontSize());
1298: if (iDelta != 0) {
1299: streamEndRun();
1300: // older acrobats do no support large offset values !
1301: if (iDelta < -10000) {
1302: textLineMoveTo(x, y);
1303: } else {
1304: getStrings().add(new Integer(iDelta));
1305: textState.tmMove(dDeltaX, 0);
1306: }
1307: }
1308: }
1309: }
1310:
1311: public void textMove(float dx, float dy) {
1312: textBegin();
1313: // have we changed the baseline?
1314: if (dy != 0) {
1315: // move relative to old line start
1316: textLineMove(dx, dy);
1317: return;
1318: }
1319: // have we a x offset to current position?
1320: if (dx != 0) {
1321: TextState textState = graphicsState.textState;
1322: int iDelta = (int) ((-dx * 1000) / textState.getFontSize());
1323: if (iDelta != 0) {
1324: streamEndRun();
1325: // older acrobats do no support large offset values !
1326: if (iDelta < -10000) {
1327: textLineMove(dx, dy);
1328: } else {
1329: getStrings().add(new Integer(iDelta));
1330: textState.tmMove(dx, 0);
1331: }
1332: }
1333: }
1334: }
1335:
1336: public void textShow(byte[] text, int offset, int length) {
1337: textBegin();
1338: getTextBuffer().write(text, offset, length);
1339: float width = PDFontTools.getGlyphWidth(graphicsState.textState
1340: .getFont(), text, offset, length);
1341: width = (graphicsState.textState.getFontSize() * width)
1342: / THOUSAND;
1343: // todo 2 text rendering formula not yet complete
1344: graphicsState.textState.tmMove(width, 0);
1345: }
1346:
1347: /*
1348: * (non-Javadoc)
1349: *
1350: * @see de.intarsys.pdf.content.CSDeviceAdapter#textBegin()
1351: */
1352: public void textBegin() {
1353: if (isTextMode()) {
1354: // ignore
1355: return;
1356: }
1357: super .textBegin();
1358: setTextMode(true);
1359: CSOperation operation = new CSOperation(CSOperators.CSO_BT);
1360: getContent().addOperation(operation);
1361: }
1362:
1363: /*
1364: * (non-Javadoc)
1365: *
1366: * @see de.intarsys.pdf.content.CSDeviceAdapter#textEnd()
1367: */
1368: public void textEnd() {
1369: if (!isTextMode()) {
1370: // ignore
1371: return;
1372: }
1373: streamEnd();
1374: super .textEnd();
1375: setTextMode(false);
1376: CSOperation lastOper = getContent().getLastOperation();
1377: if ((lastOper != null)
1378: && lastOper.matchesOperator(CSOperators.CSO_BT)) {
1379: getContent().removeLastOperation();
1380: return;
1381: }
1382: CSOperation operation = new CSOperation(CSOperators.CSO_ET);
1383: getContent().addOperation(operation);
1384: }
1385:
1386: /*
1387: * (non-Javadoc)
1388: *
1389: * @see de.intarsys.pdf.content.CSDeviceAdapter#textLineMove(float, float)
1390: */
1391: public void textLineMove(float dx, float dy) {
1392: textBegin();
1393: streamEnd();
1394: super .textLineMove(dx, dy);
1395: CSOperation operation = new CSOperation(CSOperators.CSO_Td);
1396: operation.addOperand(COSFixed.create(dx,
1397: VALUE_COORDINATE_PRECISION));
1398: operation.addOperand(COSFixed.create(dy,
1399: VALUE_COORDINATE_PRECISION));
1400: getContent().addOperation(operation);
1401: }
1402:
1403: /**
1404: * Move the current text line by <code>dx</code>, <code>dy</code>. Set
1405: * the current leading to the <code>dy</code> offset.
1406: * <p>
1407: * PDF graphics operator "TD"
1408: *
1409: * @param dx
1410: * The x offset for the new glyph starting point.
1411: * @param dy
1412: * The y offset for the new glyph starting point.
1413: */
1414: public void textLineMoveSetLeading(float dx, float dy) {
1415: // todo check usage
1416: textBegin();
1417: streamEnd();
1418: //
1419: super .textLineMove(dx, dy);
1420: super .textSetLeading(dy);
1421: //
1422: CSOperation operation = new CSOperation(CSOperators.CSO_TD);
1423: operation.addOperand(COSFixed.create(dx,
1424: VALUE_COORDINATE_PRECISION));
1425: operation.addOperand(COSFixed.create(dy,
1426: VALUE_COORDINATE_PRECISION));
1427: getContent().addOperation(operation);
1428: }
1429:
1430: /**
1431: * Move the current text line to absolute position <code>x</code>,
1432: * <code>y</code>.
1433: * <p>
1434: * PDF graphics operator "Td"
1435: */
1436: public void textLineMoveTo(float x, float y) {
1437: AffineTransform tx = graphicsState.textState
1438: .getTextLineMatrix();
1439: float dx = (float) (x - tx.getTranslateX());
1440: float dy = (float) (y - tx.getTranslateY());
1441: textLineMove(dx, dy);
1442: }
1443:
1444: /*
1445: * (non-Javadoc)
1446: *
1447: * @see de.intarsys.pdf.content.CSDeviceAdapter#textLineNew()
1448: */
1449: public void textLineNew() {
1450: textBegin();
1451: streamEnd();
1452: super .textLineNew();
1453: CSOperation operation = new CSOperation(CSOperators.CSO_Tstar);
1454: getContent().addOperation(operation);
1455: }
1456:
1457: /*
1458: * (non-Javadoc)
1459: *
1460: * @see de.intarsys.pdf.content.CSDeviceAdapter#textSetCharSpacing(float)
1461: */
1462: public void textSetCharSpacing(float charSpace) {
1463: textBegin();
1464: streamEnd();
1465: super .textSetCharSpacing(charSpace);
1466: CSOperation operation = new CSOperation(CSOperators.CSO_Tc);
1467: operation.addOperand(COSFixed.create(charSpace));
1468: getContent().addOperation(operation);
1469: }
1470:
1471: protected COSName checkResource(COSName resourceType,
1472: PDObject.MetaClass metaClass, COSName resourceName,
1473: PDObject resource) {
1474: if (getResources() == null) {
1475: throw new IllegalStateException(
1476: "must have resource dictionary"); //$NON-NLS-1$
1477: }
1478: if (resourceName == null) {
1479: // no name predefined, lookup / create a new
1480: resourceName = getResources().createResource(resourceType,
1481: resource);
1482: } else {
1483: PDObject temp = getResources().getResource(resourceType,
1484: metaClass, resourceName);
1485: if (temp == null) {
1486: getResources().addResource(resourceType, resourceName,
1487: resource);
1488: } else {
1489: if (resource != temp) {
1490: // resource conflict, create a new name...
1491: // this may happen when "replaying" a content stream
1492: // onto
1493: // another
1494: resourceName = getResources().createResource(
1495: resourceType, resource);
1496: }
1497: }
1498: }
1499: return resourceName;
1500: }
1501:
1502: /*
1503: * (non-Javadoc)
1504: *
1505: * @see de.intarsys.pdf.content.CSDeviceAdapter#textSetFont(de.intarsys.pdf.cos.COSName,
1506: * de.intarsys.pdf.font.PDFont, float)
1507: */
1508: public void textSetFont(COSName name, PDFont font, float size) {
1509: if (getResources() == null) {
1510: throw new IllegalStateException(
1511: "must have resource dictionary to set font"); //$NON-NLS-1$
1512: }
1513: textBegin();
1514: if (isFont(font, size)) {
1515: return;
1516: }
1517: streamEnd();
1518: name = checkResource(PDResources.CN_RT_Font, PDFont.META, name,
1519: font);
1520: super .textSetFont(name, font, size);
1521: CSOperation operation = new CSOperation(CSOperators.CSO_Tf);
1522: operation.addOperand(name);
1523: operation.addOperand(COSFixed
1524: .create(size, VALUE_FONT_PRECISION));
1525: getContent().addOperation(operation);
1526: }
1527:
1528: /*
1529: * (non-Javadoc)
1530: *
1531: * @see de.intarsys.pdf.content.CSDeviceAdapter#textSetHorizontalScaling(float)
1532: */
1533: public void textSetHorizontalScaling(float scale) {
1534: textBegin();
1535: streamEnd();
1536: super .textSetHorizontalScaling(scale);
1537: CSOperation operation = new CSOperation(CSOperators.CSO_Tz);
1538: operation.addOperand(COSFixed.create(scale));
1539: getContent().addOperation(operation);
1540: }
1541:
1542: /*
1543: * (non-Javadoc)
1544: *
1545: * @see de.intarsys.pdf.content.CSDeviceAdapter#textSetLeading(float)
1546: */
1547: public void textSetLeading(float leading) {
1548: textBegin();
1549: streamEnd();
1550: super .textSetLeading(leading);
1551: CSOperation operation = new CSOperation(CSOperators.CSO_TL);
1552: operation.addOperand(COSFixed.create(leading));
1553: getContent().addOperation(operation);
1554: }
1555:
1556: /*
1557: * (non-Javadoc)
1558: *
1559: * @see de.intarsys.pdf.content.CSDeviceAdapter#textSetRenderingMode(int)
1560: */
1561: public void textSetRenderingMode(int rendering) {
1562: textBegin();
1563: streamEnd();
1564: super .textSetRenderingMode(rendering);
1565: CSOperation operation = new CSOperation(CSOperators.CSO_Tr);
1566: operation.addOperand(COSInteger.create(rendering));
1567: getContent().addOperation(operation);
1568: }
1569:
1570: /*
1571: * (non-Javadoc)
1572: *
1573: * @see de.intarsys.pdf.content.CSDeviceAdapter#textSetRise(float)
1574: */
1575: public void textSetRise(float rise) {
1576: textBegin();
1577: streamEnd();
1578: super .textSetRise(rise);
1579: CSOperation operation = new CSOperation(CSOperators.CSO_Ts);
1580: operation.addOperand(COSFixed.create(rise));
1581: getContent().addOperation(operation);
1582: }
1583:
1584: /*
1585: * (non-Javadoc)
1586: *
1587: * @see de.intarsys.pdf.content.CSDeviceAdapter#textSetTransform(float,
1588: * float, float, float, float, float)
1589: */
1590: public void textSetTransform(float a, float b, float c, float d,
1591: float e, float f) {
1592: textBegin();
1593: streamEnd();
1594: super .textSetTransform(a, b, c, d, e, f);
1595: CSOperation operation = new CSOperation(CSOperators.CSO_Tm);
1596: operation
1597: .addOperand(COSFixed.create(a, VALUE_FACTOR_PRECISION));
1598: operation
1599: .addOperand(COSFixed.create(b, VALUE_FACTOR_PRECISION));
1600: operation
1601: .addOperand(COSFixed.create(c, VALUE_FACTOR_PRECISION));
1602: operation
1603: .addOperand(COSFixed.create(d, VALUE_FACTOR_PRECISION));
1604: operation.addOperand(COSFixed.create(e,
1605: VALUE_COORDINATE_PRECISION));
1606: operation.addOperand(COSFixed.create(f,
1607: VALUE_COORDINATE_PRECISION));
1608: getContent().addOperation(operation);
1609: }
1610:
1611: /*
1612: * (non-Javadoc)
1613: *
1614: * @see de.intarsys.pdf.content.CSDeviceAdapter#textSetWordSpacing(float)
1615: */
1616: public void textSetWordSpacing(float wordSpace) {
1617: textBegin();
1618: streamEnd();
1619: super .textSetWordSpacing(wordSpace);
1620: CSOperation operation = new CSOperation(CSOperators.CSO_Tw);
1621: operation.addOperand(COSFixed.create(wordSpace));
1622: getContent().addOperation(operation);
1623: }
1624:
1625: protected void basicTextShow(byte[] text) {
1626: CSOperation operation = new CSOperation(CSOperators.CSO_Tj);
1627: operation.addOperand(COSString.create(text));
1628: for (int i = 0; i < text.length; i++) {
1629: graphicsState.textState.getFont().setCharUsed(text[i]);
1630: }
1631: getContent().addOperation(operation);
1632: }
1633:
1634: /*
1635: * (non-Javadoc)
1636: *
1637: * @see de.intarsys.pdf.content.CSDeviceAdapter#textT3SetGlyphWidth(float,
1638: * float)
1639: */
1640: public void textT3SetGlyphWidth(float x, float y) {
1641: textBegin();
1642: streamEnd();
1643: super .textT3SetGlyphWidth(x, y);
1644: CSOperation operation = new CSOperation(CSOperators.CSO_d0);
1645: operation.addOperand(COSFixed.create(x));
1646: operation.addOperand(COSFixed.create(y));
1647: getContent().addOperation(operation);
1648: }
1649:
1650: /*
1651: * (non-Javadoc)
1652: *
1653: * @see de.intarsys.pdf.content.CSDeviceAdapter#textT3SetGlyphWidthBB(float,
1654: * float, float, float, float, float)
1655: */
1656: public void textT3SetGlyphWidthBB(float x, float y, float llx,
1657: float lly, float urx, float ury) {
1658: textBegin();
1659: streamEnd();
1660: super .textT3SetGlyphWidthBB(x, y, llx, lly, urx, ury);
1661: CSOperation operation = new CSOperation(CSOperators.CSO_d1);
1662: operation.addOperand(COSFixed.create(x));
1663: operation.addOperand(COSFixed.create(y));
1664: operation.addOperand(COSFixed.create(llx));
1665: operation.addOperand(COSFixed.create(lly));
1666: operation.addOperand(COSFixed.create(urx));
1667: operation.addOperand(COSFixed.create(ury));
1668: getContent().addOperation(operation);
1669: }
1670:
1671: /*
1672: * (non-Javadoc)
1673: *
1674: * @see de.intarsys.pdf.content.CSDeviceAdapter#transform(float, float,
1675: * float, float, float, float)
1676: */
1677: public void transform(float a, float b, float c, float d, float e,
1678: float f) {
1679: textEnd();
1680: super .transform(a, b, c, d, e, f);
1681: CSOperation operation = new CSOperation(CSOperators.CSO_cm);
1682: operation
1683: .addOperand(COSFixed.create(a, VALUE_FACTOR_PRECISION));
1684: operation
1685: .addOperand(COSFixed.create(b, VALUE_FACTOR_PRECISION));
1686: operation
1687: .addOperand(COSFixed.create(c, VALUE_FACTOR_PRECISION));
1688: operation
1689: .addOperand(COSFixed.create(d, VALUE_FACTOR_PRECISION));
1690: operation.addOperand(COSFixed.create(e,
1691: VALUE_COORDINATE_PRECISION));
1692: operation.addOperand(COSFixed.create(f,
1693: VALUE_COORDINATE_PRECISION));
1694: getContent().addOperation(operation);
1695: }
1696:
1697: public IContentStreamProvider getContentStreamProvider() {
1698: return contentStreamProvider;
1699: }
1700: }
|