001: /**
002: * Copyright (c) 2004-2005, www.pdfbox.org
003: * All rights reserved.
004: *
005: * Redistribution and use in source and binary forms, with or without
006: * modification, are permitted provided that the following conditions are met:
007: *
008: * 1. Redistributions of source code must retain the above copyright notice,
009: * this list of conditions and the following disclaimer.
010: * 2. Redistributions in binary form must reproduce the above copyright notice,
011: * this list of conditions and the following disclaimer in the documentation
012: * and/or other materials provided with the distribution.
013: * 3. Neither the name of pdfbox; nor the names of its
014: * contributors may be used to endorse or promote products derived from this
015: * software without specific prior written permission.
016: *
017: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
018: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
019: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
020: * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
021: * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
022: * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
023: * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
024: * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
025: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
026: * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
027: *
028: * http://www.pdfbox.org
029: *
030: */package org.pdfbox.pdmodel.edit;
031:
032: import java.awt.Color;
033: import java.awt.color.ColorSpace;
034: import java.io.ByteArrayOutputStream;
035: import java.io.IOException;
036: import java.io.OutputStream;
037:
038: import java.text.NumberFormat;
039:
040: import java.util.ArrayList;
041: import java.util.List;
042: import java.util.Locale;
043: import java.util.Map;
044: import java.util.HashMap;
045:
046: import org.pdfbox.pdmodel.PDDocument;
047: import org.pdfbox.pdmodel.PDPage;
048: import org.pdfbox.pdmodel.PDResources;
049:
050: import org.pdfbox.pdmodel.common.COSStreamArray;
051: import org.pdfbox.pdmodel.common.PDStream;
052:
053: import org.pdfbox.pdmodel.font.PDFont;
054: import org.pdfbox.pdmodel.graphics.color.PDColorSpace;
055: import org.pdfbox.pdmodel.graphics.color.PDDeviceCMYK;
056: import org.pdfbox.pdmodel.graphics.color.PDDeviceGray;
057: import org.pdfbox.pdmodel.graphics.color.PDDeviceN;
058: import org.pdfbox.pdmodel.graphics.color.PDDeviceRGB;
059: import org.pdfbox.pdmodel.graphics.color.PDICCBased;
060: import org.pdfbox.pdmodel.graphics.color.PDPattern;
061: import org.pdfbox.pdmodel.graphics.color.PDSeparation;
062: import org.pdfbox.pdmodel.graphics.xobject.PDXObjectImage;
063: import org.pdfbox.util.MapUtil;
064:
065: import org.pdfbox.cos.COSArray;
066: import org.pdfbox.cos.COSDictionary;
067: import org.pdfbox.cos.COSName;
068: import org.pdfbox.cos.COSString;
069:
070: /**
071: * This class will is a convenience for creating page content streams. You MUST
072: * call close() when you are finished with this object.
073: *
074: * @author <a href="mailto:ben@benlitchfield.com">Ben Litchfield</a>
075: * @version $Revision: 1.18 $
076: */
077: public class PDPageContentStream {
078: private PDPage page;
079: private OutputStream output;
080: private boolean inTextMode = false;
081: private Map fontMappings = new HashMap();
082: private Map imageMappings = new HashMap();
083: private PDResources resources;
084: private Map fonts;
085: private Map images;
086:
087: private PDColorSpace currentStrokingColorSpace = new PDDeviceGray();
088: private PDColorSpace currentNonStrokingColorSpace = new PDDeviceGray();
089:
090: //cached storage component for getting color values
091: private float[] colorComponents = new float[4];
092:
093: private NumberFormat formatDecimal = NumberFormat
094: .getNumberInstance(Locale.US);
095:
096: private static final String BEGIN_TEXT = "BT\n";
097: private static final String END_TEXT = "ET\n";
098: private static final String SET_FONT = "Tf\n";
099: private static final String MOVE_TEXT_POSITION = "Td\n";
100: private static final String SHOW_TEXT = "Tj\n";
101:
102: private static final String SAVE_GRAPHICS_STATE = "q\n";
103: private static final String RESTORE_GRAPHICS_STATE = "Q\n";
104: private static final String CONCATENATE_MATRIX = "cm\n";
105: private static final String XOBJECT_DO = "Do\n";
106: private static final String RG_STROKING = "RG\n";
107: private static final String RG_NON_STROKING = "rg\n";
108: private static final String K_STROKING = "K\n";
109: private static final String K_NON_STROKING = "k\n";
110: private static final String G_STROKING = "G\n";
111: private static final String G_NON_STROKING = "g\n";
112: private static final String APPEND_RECTANGLE = "re\n";
113: private static final String FILL = "f\n";
114:
115: private static final String SET_STROKING_COLORSPACE = "CS\n";
116: private static final String SET_NON_STROKING_COLORSPACE = "cs\n";
117:
118: private static final String SET_STROKING_COLOR_SIMPLE = "SC\n";
119: private static final String SET_STROKING_COLOR_COMPLEX = "SCN\n";
120: private static final String SET_NON_STROKING_COLOR_SIMPLE = "sc\n";
121: private static final String SET_NON_STROKING_COLOR_COMPLEX = "scn\n";
122:
123: private static final int SPACE = 32;
124:
125: /**
126: * Create a new PDPage content stream.
127: *
128: * @param document The document the page is part of.
129: * @param sourcePage The page to write the contents to.
130: * @throws IOException If there is an error writing to the page contents.
131: */
132: public PDPageContentStream(PDDocument document, PDPage sourcePage)
133: throws IOException {
134: this (document, sourcePage, false, true);
135: }
136:
137: /**
138: * Create a new PDPage content stream.
139: *
140: * @param document The document the page is part of.
141: * @param sourcePage The page to write the contents to.
142: * @param appendContent Indicates whether content will be overwritten. If false all previous content is deleted.
143: * @param compress Tell if the content stream should compress the page contents.
144: * @throws IOException If there is an error writing to the page contents.
145: */
146: public PDPageContentStream(PDDocument document, PDPage sourcePage,
147: boolean appendContent, boolean compress) throws IOException {
148: page = sourcePage;
149: resources = page.getResources();
150: if (resources == null) {
151: resources = new PDResources();
152: page.setResources(resources);
153: }
154: fonts = resources.getFonts();
155: images = resources.getImages();
156: // If request specifies the need to append to the document
157: if (appendContent) {
158: // Get the pdstream from the source page instead of creating a new one
159: PDStream contents = sourcePage.getContents();
160:
161: // Create a pdstream to append new content
162: PDStream contentsToAppend = new PDStream(document);
163:
164: // This will be the resulting COSStreamArray after existing and new streams are merged
165: COSStreamArray compoundStream = null;
166:
167: // If contents is already an array, a new stream is simply appended to it
168: if (contents.getStream() instanceof COSStreamArray) {
169: compoundStream = (COSStreamArray) contents.getStream();
170: compoundStream.appendStream(contentsToAppend
171: .getStream());
172: } else {
173: // Creates the COSStreamArray and adds the current stream plus a new one to it
174: COSArray newArray = new COSArray();
175: newArray.add(contents.getCOSObject());
176: newArray.add(contentsToAppend.getCOSObject());
177: compoundStream = new COSStreamArray(newArray);
178: }
179:
180: if (compress) {
181: List filters = new ArrayList();
182: filters.add(COSName.FLATE_DECODE);
183: contentsToAppend.setFilters(filters);
184: }
185:
186: // Sets the compoundStream as page contents
187: sourcePage.setContents(new PDStream(compoundStream));
188: output = contentsToAppend.createOutputStream();
189: } else {
190: PDStream contents = new PDStream(document);
191: if (compress) {
192: List filters = new ArrayList();
193: filters.add(COSName.FLATE_DECODE);
194: contents.setFilters(filters);
195: }
196: sourcePage.setContents(contents);
197: output = contents.createOutputStream();
198: }
199: formatDecimal.setMaximumFractionDigits(10);
200: formatDecimal.setGroupingUsed(false);
201: }
202:
203: /**
204: * Begin some text operations.
205: *
206: * @throws IOException If there is an error writing to the stream or if you attempt to
207: * nest beginText calls.
208: */
209: public void beginText() throws IOException {
210: if (inTextMode) {
211: throw new IOException(
212: "Error: Nested beginText() calls are not allowed.");
213: }
214: appendRawCommands(BEGIN_TEXT);
215: inTextMode = true;
216: }
217:
218: /**
219: * End some text operations.
220: *
221: * @throws IOException If there is an error writing to the stream or if you attempt to
222: * nest endText calls.
223: */
224: public void endText() throws IOException {
225: if (!inTextMode) {
226: throw new IOException(
227: "Error: You must call beginText() before calling endText.");
228: }
229: appendRawCommands(END_TEXT);
230: inTextMode = false;
231: }
232:
233: /**
234: * Set the font to draw text with.
235: *
236: * @param font The font to use.
237: * @param fontSize The font size to draw the text.
238: * @throws IOException If there is an error writing the font information.
239: */
240: public void setFont(PDFont font, float fontSize) throws IOException {
241: String fontMapping = (String) fontMappings.get(font);
242: if (fontMapping == null) {
243: fontMapping = MapUtil.getNextUniqueKey(fonts, "F");
244: fontMappings.put(font, fontMapping);
245: fonts.put(fontMapping, font);
246: }
247: appendRawCommands("/");
248: appendRawCommands(fontMapping);
249: appendRawCommands(SPACE);
250: appendRawCommands(formatDecimal.format(fontSize));
251: appendRawCommands(SPACE);
252: appendRawCommands(SET_FONT);
253: }
254:
255: /**
256: * Draw an image at the x,y coordinates, with the default size of the image.
257: *
258: * @param image The image to draw.
259: * @param x The x-coordinate to draw the image.
260: * @param y The y-coordinate to draw the image.
261: *
262: * @throws IOException If there is an error writing to the stream.
263: */
264: public void drawImage(PDXObjectImage image, float x, float y)
265: throws IOException {
266: drawImage(image, x, y, image.getWidth(), image.getHeight());
267: }
268:
269: /**
270: * Draw an image at the x,y coordinates and a certain width and height.
271: *
272: * @param image The image to draw.
273: * @param x The x-coordinate to draw the image.
274: * @param y The y-coordinate to draw the image.
275: * @param width The width of the image to draw.
276: * @param height The height of the image to draw.
277: *
278: * @throws IOException If there is an error writing to the stream.
279: */
280: public void drawImage(PDXObjectImage image, float x, float y,
281: float width, float height) throws IOException {
282: String imageMapping = (String) imageMappings.get(image);
283: if (imageMapping == null) {
284: imageMapping = MapUtil.getNextUniqueKey(images, "Im");
285: imageMappings.put(image, imageMapping);
286: images.put(imageMapping, image);
287: }
288: appendRawCommands(SAVE_GRAPHICS_STATE);
289: appendRawCommands(formatDecimal.format(width));
290: appendRawCommands(SPACE);
291: appendRawCommands(formatDecimal.format(0));
292: appendRawCommands(SPACE);
293: appendRawCommands(formatDecimal.format(0));
294: appendRawCommands(SPACE);
295: appendRawCommands(formatDecimal.format(height));
296: appendRawCommands(SPACE);
297: appendRawCommands(formatDecimal.format(x));
298: appendRawCommands(SPACE);
299: appendRawCommands(formatDecimal.format(y));
300: appendRawCommands(SPACE);
301: appendRawCommands(CONCATENATE_MATRIX);
302: appendRawCommands(SPACE);
303: appendRawCommands("/");
304: appendRawCommands(imageMapping);
305: appendRawCommands(SPACE);
306: appendRawCommands(XOBJECT_DO);
307: appendRawCommands(SPACE);
308: appendRawCommands(RESTORE_GRAPHICS_STATE);
309: }
310:
311: /**
312: * The Td operator.
313: * @param x The x coordinate.
314: * @param y The y coordinate.
315: * @throws IOException If there is an error writing to the stream.
316: */
317: public void moveTextPositionByAmount(float x, float y)
318: throws IOException {
319: if (!inTextMode) {
320: throw new IOException(
321: "Error: must call beginText() before moveTextPositionByAmount");
322: }
323: appendRawCommands(formatDecimal.format(x));
324: appendRawCommands(SPACE);
325: appendRawCommands(formatDecimal.format(y));
326: appendRawCommands(SPACE);
327: appendRawCommands(MOVE_TEXT_POSITION);
328: }
329:
330: /**
331: * This will draw a string at the current location on the screen.
332: *
333: * @param text The text to draw.
334: * @throws IOException If an io exception occurs.
335: */
336: public void drawString(String text) throws IOException {
337: if (!inTextMode) {
338: throw new IOException(
339: "Error: must call beginText() before drawString");
340: }
341: COSString string = new COSString(text);
342: ByteArrayOutputStream buffer = new ByteArrayOutputStream();
343: string.writePDF(buffer);
344: appendRawCommands(new String(buffer.toByteArray(), "ISO-8859-1"));
345: appendRawCommands(SPACE);
346: appendRawCommands(SHOW_TEXT);
347: }
348:
349: /**
350: * Set the stroking color space. This will add the colorspace to the PDResources
351: * if necessary.
352: *
353: * @param colorSpace The colorspace to write.
354: * @throws IOException If there is an error writing the colorspace.
355: */
356: public void setStrokingColorSpace(PDColorSpace colorSpace)
357: throws IOException {
358: writeColorSpace(colorSpace);
359: appendRawCommands(SET_STROKING_COLORSPACE);
360: }
361:
362: /**
363: * Set the stroking color space. This will add the colorspace to the PDResources
364: * if necessary.
365: *
366: * @param colorSpace The colorspace to write.
367: * @throws IOException If there is an error writing the colorspace.
368: */
369: public void setNonStrokingColorSpace(PDColorSpace colorSpace)
370: throws IOException {
371: writeColorSpace(colorSpace);
372: appendRawCommands(SET_NON_STROKING_COLORSPACE);
373: }
374:
375: private void writeColorSpace(PDColorSpace colorSpace)
376: throws IOException {
377: COSName key = null;
378: if (colorSpace instanceof PDDeviceGray
379: || colorSpace instanceof PDDeviceRGB
380: || colorSpace instanceof PDDeviceCMYK) {
381: key = COSName.getPDFName(colorSpace.getName());
382: } else {
383: COSDictionary colorSpaces = (COSDictionary) resources
384: .getCOSDictionary().getDictionaryObject(
385: COSName.COLORSPACE);
386: if (colorSpaces == null) {
387: colorSpaces = new COSDictionary();
388: resources.getCOSDictionary().setItem(
389: COSName.COLORSPACE, colorSpaces);
390: }
391: key = colorSpaces.getKeyForValue(colorSpace.getCOSObject());
392:
393: if (key == null) {
394: int counter = 0;
395: String csName = "CS";
396: while (colorSpaces.containsValue(csName + counter)) {
397: counter++;
398: }
399: key = COSName.getPDFName(csName + counter);
400: colorSpaces.setItem(key, colorSpace);
401: }
402: }
403: key.writePDF(output);
404: appendRawCommands(SPACE);
405: }
406:
407: /**
408: * Set the color components of current stroking colorspace.
409: *
410: * @param components The components to set for the current color.
411: * @throws IOException If there is an error while writing to the stream.
412: */
413: public void setStrokingColor(float[] components) throws IOException {
414: for (int i = 0; i < components.length; i++) {
415: appendRawCommands(formatDecimal.format(components[i]));
416: appendRawCommands(SPACE);
417: }
418: if (currentStrokingColorSpace instanceof PDSeparation
419: || currentStrokingColorSpace instanceof PDPattern
420: || currentStrokingColorSpace instanceof PDDeviceN
421: || currentStrokingColorSpace instanceof PDICCBased) {
422: appendRawCommands(SET_STROKING_COLOR_COMPLEX);
423: } else {
424: appendRawCommands(SET_STROKING_COLOR_SIMPLE);
425: }
426: }
427:
428: /**
429: * Set the stroking color, specified as RGB.
430: *
431: * @param color The color to set.
432: * @throws IOException If an IO error occurs while writing to the stream.
433: */
434: public void setStrokingColor(Color color) throws IOException {
435: ColorSpace colorSpace = color.getColorSpace();
436: if (colorSpace.getType() == ColorSpace.TYPE_RGB) {
437: setStrokingColor(color.getRed(), color.getGreen(), color
438: .getBlue());
439: } else if (colorSpace.getType() == ColorSpace.TYPE_GRAY) {
440: color.getColorComponents(colorComponents);
441: setStrokingColor(colorComponents[0]);
442: } else if (colorSpace.getType() == ColorSpace.TYPE_CMYK) {
443: color.getColorComponents(colorComponents);
444: setStrokingColor(colorComponents[0], colorComponents[2],
445: colorComponents[2], colorComponents[3]);
446: } else {
447: throw new IOException("Error: unknown colorspace:"
448: + colorSpace);
449: }
450: }
451:
452: /**
453: * Set the non stroking color, specified as RGB.
454: *
455: * @param color The color to set.
456: * @throws IOException If an IO error occurs while writing to the stream.
457: */
458: public void setNonStrokingColor(Color color) throws IOException {
459: ColorSpace colorSpace = color.getColorSpace();
460: if (colorSpace.getType() == ColorSpace.TYPE_RGB) {
461: setNonStrokingColor(color.getRed(), color.getGreen(), color
462: .getBlue());
463: } else if (colorSpace.getType() == ColorSpace.TYPE_GRAY) {
464: color.getColorComponents(colorComponents);
465: setNonStrokingColor(colorComponents[0]);
466: } else if (colorSpace.getType() == ColorSpace.TYPE_CMYK) {
467: color.getColorComponents(colorComponents);
468: setNonStrokingColor(colorComponents[0], colorComponents[2],
469: colorComponents[2], colorComponents[3]);
470: } else {
471: throw new IOException("Error: unknown colorspace:"
472: + colorSpace);
473: }
474: }
475:
476: /**
477: * Set the stroking color, specified as RGB, 0-255.
478: *
479: * @param r The red value.
480: * @param g The green value.
481: * @param b The blue value.
482: * @throws IOException If an IO error occurs while writing to the stream.
483: */
484: public void setStrokingColor(int r, int g, int b)
485: throws IOException {
486: appendRawCommands(formatDecimal.format(r / 255d));
487: appendRawCommands(SPACE);
488: appendRawCommands(formatDecimal.format(g / 255d));
489: appendRawCommands(SPACE);
490: appendRawCommands(formatDecimal.format(b / 255d));
491: appendRawCommands(SPACE);
492: appendRawCommands(RG_STROKING);
493: }
494:
495: /**
496: * Set the stroking color, specified as CMYK, 0-255.
497: *
498: * @param c The cyan value.
499: * @param m The magenta value.
500: * @param y The yellow value.
501: * @param k The black value.
502: * @throws IOException If an IO error occurs while writing to the stream.
503: */
504: public void setStrokingColor(int c, int m, int y, int k)
505: throws IOException {
506: appendRawCommands(formatDecimal.format(c / 255d));
507: appendRawCommands(SPACE);
508: appendRawCommands(formatDecimal.format(m / 255d));
509: appendRawCommands(SPACE);
510: appendRawCommands(formatDecimal.format(y / 255d));
511: appendRawCommands(SPACE);
512: appendRawCommands(formatDecimal.format(k / 255d));
513: appendRawCommands(SPACE);
514: appendRawCommands(K_STROKING);
515: }
516:
517: /**
518: * Set the stroking color, specified as CMYK, 0.0-1.0.
519: *
520: * @param c The cyan value.
521: * @param m The magenta value.
522: * @param y The yellow value.
523: * @param k The black value.
524: * @throws IOException If an IO error occurs while writing to the stream.
525: */
526: public void setStrokingColor(double c, double m, double y, double k)
527: throws IOException {
528: appendRawCommands(formatDecimal.format(c));
529: appendRawCommands(SPACE);
530: appendRawCommands(formatDecimal.format(m));
531: appendRawCommands(SPACE);
532: appendRawCommands(formatDecimal.format(y));
533: appendRawCommands(SPACE);
534: appendRawCommands(formatDecimal.format(k));
535: appendRawCommands(SPACE);
536: appendRawCommands(K_STROKING);
537: }
538:
539: /**
540: * Set the stroking color, specified as grayscale, 0-255.
541: *
542: * @param g The gray value.
543: * @throws IOException If an IO error occurs while writing to the stream.
544: */
545: public void setStrokingColor(int g) throws IOException {
546: appendRawCommands(formatDecimal.format(g / 255d));
547: appendRawCommands(SPACE);
548: appendRawCommands(G_STROKING);
549: }
550:
551: /**
552: * Set the stroking color, specified as Grayscale 0.0-1.0.
553: *
554: * @param g The gray value.
555: * @throws IOException If an IO error occurs while writing to the stream.
556: */
557: public void setStrokingColor(double g) throws IOException {
558: appendRawCommands(formatDecimal.format(g));
559: appendRawCommands(SPACE);
560: appendRawCommands(G_STROKING);
561: }
562:
563: /**
564: * Set the color components of current non stroking colorspace.
565: *
566: * @param components The components to set for the current color.
567: * @throws IOException If there is an error while writing to the stream.
568: */
569: public void setNonStrokingColor(float[] components)
570: throws IOException {
571: for (int i = 0; i < components.length; i++) {
572: appendRawCommands(formatDecimal.format(components[i]));
573: appendRawCommands(SPACE);
574: }
575: if (currentNonStrokingColorSpace instanceof PDSeparation
576: || currentNonStrokingColorSpace instanceof PDPattern
577: || currentNonStrokingColorSpace instanceof PDDeviceN
578: || currentNonStrokingColorSpace instanceof PDICCBased) {
579: appendRawCommands(SET_NON_STROKING_COLOR_COMPLEX);
580: } else {
581: appendRawCommands(SET_NON_STROKING_COLOR_SIMPLE);
582: }
583: }
584:
585: /**
586: * Set the non stroking color, specified as RGB, 0-255.
587: *
588: * @param r The red value.
589: * @param g The green value.
590: * @param b The blue value.
591: * @throws IOException If an IO error occurs while writing to the stream.
592: */
593: public void setNonStrokingColor(int r, int g, int b)
594: throws IOException {
595: appendRawCommands(formatDecimal.format(r / 255d));
596: appendRawCommands(SPACE);
597: appendRawCommands(formatDecimal.format(g / 255d));
598: appendRawCommands(SPACE);
599: appendRawCommands(formatDecimal.format(b / 255d));
600: appendRawCommands(SPACE);
601: appendRawCommands(RG_NON_STROKING);
602: }
603:
604: /**
605: * Set the non stroking color, specified as CMYK, 0-255.
606: *
607: * @param c The cyan value.
608: * @param m The magenta value.
609: * @param y The yellow value.
610: * @param k The black value.
611: * @throws IOException If an IO error occurs while writing to the stream.
612: */
613: public void setNonStrokingColor(int c, int m, int y, int k)
614: throws IOException {
615: appendRawCommands(formatDecimal.format(c / 255d));
616: appendRawCommands(SPACE);
617: appendRawCommands(formatDecimal.format(m / 255d));
618: appendRawCommands(SPACE);
619: appendRawCommands(formatDecimal.format(y / 255d));
620: appendRawCommands(SPACE);
621: appendRawCommands(formatDecimal.format(k / 255d));
622: appendRawCommands(SPACE);
623: appendRawCommands(K_NON_STROKING);
624: }
625:
626: /**
627: * Set the non stroking color, specified as CMYK, 0.0-1.0.
628: *
629: * @param c The cyan value.
630: * @param m The magenta value.
631: * @param y The yellow value.
632: * @param k The black value.
633: * @throws IOException If an IO error occurs while writing to the stream.
634: */
635: public void setNonStrokingColor(double c, double m, double y,
636: double k) throws IOException {
637: appendRawCommands(formatDecimal.format(c));
638: appendRawCommands(SPACE);
639: appendRawCommands(formatDecimal.format(m));
640: appendRawCommands(SPACE);
641: appendRawCommands(formatDecimal.format(y));
642: appendRawCommands(SPACE);
643: appendRawCommands(formatDecimal.format(k));
644: appendRawCommands(SPACE);
645: appendRawCommands(K_NON_STROKING);
646: }
647:
648: /**
649: * Set the non stroking color, specified as grayscale, 0-255.
650: *
651: * @param g The gray value.
652: * @throws IOException If an IO error occurs while writing to the stream.
653: */
654: public void setNonStrokingColor(int g) throws IOException {
655: appendRawCommands(formatDecimal.format(g / 255d));
656: appendRawCommands(SPACE);
657: appendRawCommands(G_NON_STROKING);
658: }
659:
660: /**
661: * Set the non stroking color, specified as Grayscale 0.0-1.0.
662: *
663: * @param g The gray value.
664: * @throws IOException If an IO error occurs while writing to the stream.
665: */
666: public void setNonStrokingColor(double g) throws IOException {
667: appendRawCommands(formatDecimal.format(g));
668: appendRawCommands(SPACE);
669: appendRawCommands(G_NON_STROKING);
670: }
671:
672: /**
673: * Draw a rectangle on the page using the current non stroking color.
674: *
675: * @param x The lower left x coordinate.
676: * @param y The lower left y coordinate.
677: * @param width The width of the rectangle.
678: * @param height The height of the rectangle.
679: * @throws IOException If there is an error while drawing on the screen.
680: */
681: public void fillRect(float x, float y, float width, float height)
682: throws IOException {
683: appendRawCommands(formatDecimal.format(x));
684: appendRawCommands(SPACE);
685: appendRawCommands(formatDecimal.format(y));
686: appendRawCommands(SPACE);
687: appendRawCommands(formatDecimal.format(width));
688: appendRawCommands(SPACE);
689: appendRawCommands(formatDecimal.format(height));
690: appendRawCommands(SPACE);
691: appendRawCommands(APPEND_RECTANGLE);
692: appendRawCommands(FILL);
693: }
694:
695: /**
696: * This will append raw commands to the content stream.
697: *
698: * @param commands The commands to append to the stream.
699: * @throws IOException If an error occurs while writing to the stream.
700: */
701: public void appendRawCommands(String commands) throws IOException {
702: appendRawCommands(commands.getBytes("ISO-8859-1"));
703: }
704:
705: /**
706: * This will append raw commands to the content stream.
707: *
708: * @param commands The commands to append to the stream.
709: * @throws IOException If an error occurs while writing to the stream.
710: */
711: public void appendRawCommands(byte[] commands) throws IOException {
712: output.write(commands);
713: }
714:
715: /**
716: * This will append raw commands to the content stream.
717: *
718: * @param data Append a raw byte to the stream.
719: *
720: * @throws IOException If an error occurs while writing to the stream.
721: */
722: public void appendRawCommands(int data) throws IOException {
723: output.write(data);
724: }
725:
726: /**
727: * Close the content stream. This must be called when you are done with this
728: * object.
729: * @throws IOException If the underlying stream has a problem being written to.
730: */
731: public void close() throws IOException {
732: output.close();
733: }
734: }
|