001: /**
002: * Copyright (c) 2003-2004, 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.font;
031:
032: import java.awt.Image;
033:
034: import java.io.IOException;
035:
036: import java.util.List;
037:
038: import org.fontbox.util.BoundingBox;
039:
040: import org.pdfbox.cos.COSNumber;
041: import org.pdfbox.cos.COSStream;
042:
043: import org.pdfbox.pdmodel.graphics.xobject.PDInlinedImage;
044:
045: import org.pdfbox.util.ImageParameters;
046: import org.pdfbox.util.PDFOperator;
047: import org.pdfbox.util.PDFStreamEngine;
048:
049: /**
050: * This class will handle creating an image for a type 3 glyph.
051: *
052: * @author <a href="mailto:ben@benlitchfield.com">Ben Litchfield</a>
053: * @version $Revision: 1.10 $
054: */
055: public class Type3StreamParser extends PDFStreamEngine {
056: private PDInlinedImage image = null;
057: private BoundingBox box = null;
058:
059: /**
060: * This will parse a type3 stream and create an image from it.
061: *
062: * @param type3Stream The stream containing the operators to draw the image.
063: *
064: * @return The image that was created.
065: *
066: * @throws IOException If there is an error processing the stream.
067: */
068: public Image createImage(COSStream type3Stream) throws IOException {
069: processStream(null, null, type3Stream);
070: return image.createImage();
071: }
072:
073: /**
074: * This is used to handle an operation.
075: *
076: * @param operator The operation to perform.
077: * @param arguments The list of arguments.
078: *
079: * @throws IOException If there is an error processing the operation.
080: */
081: protected void processOperator(PDFOperator operator, List arguments)
082: throws IOException {
083: super .processOperator(operator, arguments);
084: String operation = operator.getOperation();
085: /**
086: if( operation.equals( "b" ) )
087: {
088: //Close, fill, and stroke path using nonzero winding number rule
089: }
090: else if( operation.equals( "B" ) )
091: {
092: //Fill and stroke path using nonzero winding number rule
093: }
094: else if( operation.equals( "b*" ) )
095: {
096: //Close, fill, and stroke path using even-odd rule
097: }
098: else if( operation.equals( "B*" ) )
099: {
100: //Fill and stroke path using even-odd rule
101: }
102: else if( operation.equals( "BDC" ) )
103: {
104: //(PDF 1.2) Begin marked-content sequence with property list
105: }
106: else **/
107: if (operation.equals("BI")) {
108: ImageParameters params = operator.getImageParameters();
109: image = new PDInlinedImage();
110: image.setImageParameters(params);
111: image.setImageData(operator.getImageData());
112: //begin inline image object
113: }
114: /**
115: else if( operation.equals( "BMC" ) )
116: {
117: //(PDF 1.2) Begin marked-content sequence
118: }
119: else if( operation.equals( "BT" ) )
120: {
121: log.debug( "<BT>" );
122: textMatrix = new Matrix();
123: textLineMatrix = new Matrix();
124: }
125: else if( operation.equals( "BX" ) )
126: {
127: //(PDF 1.1) Begin compatibility section
128: }
129: else if( operation.equals( "c" ) )
130: {
131: //Append curved segment to path (three control points)
132: }
133: else if( operation.equals( "cm" ) )
134: {
135: }
136: else if( operation.equals( "cs" ) )
137: {
138: }
139: else if( operation.equals( "CS" ) )
140: {
141: }
142: else if( operation.equals( "d" ) )
143: {
144: //Set the line dash pattern in the graphics state
145: }
146: else */
147: if (operation.equals("d0")) {
148: //set glyph with for a type3 font
149: //COSNumber horizontalWidth = (COSNumber)arguments.get( 0 );
150: //COSNumber verticalWidth = (COSNumber)arguments.get( 1 );
151: //width = horizontalWidth.intValue();
152: //height = verticalWidth.intValue();
153: } else if (operation.equals("d1")) {
154: //set glyph with and bounding box for type 3 font
155: //COSNumber horizontalWidth = (COSNumber)arguments.get( 0 );
156: //COSNumber verticalWidth = (COSNumber)arguments.get( 1 );
157: COSNumber llx = (COSNumber) arguments.get(2);
158: COSNumber lly = (COSNumber) arguments.get(3);
159: COSNumber urx = (COSNumber) arguments.get(4);
160: COSNumber ury = (COSNumber) arguments.get(5);
161:
162: //width = horizontalWidth.intValue();
163: //height = verticalWidth.intValue();
164: box = new BoundingBox();
165: box.setLowerLeftX(llx.floatValue());
166: box.setLowerLeftY(lly.floatValue());
167: box.setUpperRightX(urx.floatValue());
168: box.setUpperRightY(ury.floatValue());
169: }/*
170: else if( operation.equals( "Do" ) )
171: {
172: //invoke named object.
173: }
174: else if( operation.equals( "DP" ) )
175: {
176: //(PDF 1.2) De.ne marked-content point with property list
177: }
178: else if( operation.equals( "EI" ) )
179: {
180: //end inline image object
181: }
182: else if( operation.equals( "EMC" ) )
183: {
184: //End inline image object
185: }
186: else if( operation.equals( "ET" ) )
187: {
188: log.debug( "<ET>" );
189: textMatrix = null;
190: textLineMatrix = null;
191: }
192: else if( operation.equals( "EX" ) )
193: {
194: //(PDF 1.1) End compatibility section
195: }
196: else if( operation.equals( "f" ) )
197: {
198: //Fill the path, using the nonzero winding number rule to determine the region to .ll
199: }
200: else if( operation.equals( "F" ) )
201: {
202: }
203: else if( operation.equals( "f*" ) )
204: {
205: //Fill path using even-odd rule
206: }
207: else if( operation.equals( "g" ) )
208: {
209: }
210: else if( operation.equals( "G" ) )
211: {
212: }
213: else if( operation.equals( "gs" ) )
214: {
215: }
216: else if( operation.equals( "h" ) )
217: {
218: //close subpath
219: }
220: else if( operation.equals( "i" ) )
221: {
222: //set flatness tolerance, not sure what this does
223: }
224: else if( operation.equals( "ID" ) )
225: {
226: //begin inline image data
227: }
228: else if( operation.equals( "j" ) )
229: {
230: //Set the line join style in the graphics state
231: //System.out.println( "<j>" );
232: }
233: else if( operation.equals( "J" ) )
234: {
235: //Set the line cap style in the graphics state
236: //System.out.println( "<J>" );
237: }
238: else if( operation.equals( "k" ) )
239: {
240: //Set CMYK color for nonstroking operations
241: }
242: else if( operation.equals( "K" ) )
243: {
244: //Set CMYK color for stroking operations
245: }
246: else if( operation.equals( "l" ) )
247: {
248: //append straight line segment from the current point to the point.
249: COSNumber x = (COSNumber)arguments.get( 0 );
250: COSNumber y = (COSNumber)arguments.get( 1 );
251: linePath.lineTo( x.floatValue(), pageSize.getHeight()-y.floatValue() );
252: }
253: else if( operation.equals( "m" ) )
254: {
255: COSNumber x = (COSNumber)arguments.get( 0 );
256: COSNumber y = (COSNumber)arguments.get( 1 );
257: linePath.reset();
258: linePath.moveTo( x.floatValue(), pageSize.getHeight()-y.floatValue() );
259: //System.out.println( "<m x=\"" + x.getValue() + "\" y=\"" + y.getValue() + "\" >" );
260: }
261: else if( operation.equals( "M" ) )
262: {
263: //System.out.println( "<M>" );
264: }
265: else if( operation.equals( "MP" ) )
266: {
267: //(PDF 1.2) Define marked-content point
268: }
269: else if( operation.equals( "n" ) )
270: {
271: //End path without .lling or stroking
272: //System.out.println( "<n>" );
273: }
274: else if( operation.equals( "q" ) )
275: {
276: //save graphics state
277: if( log.isDebugEnabled() )
278: {
279: log.debug( "<" + operation + "> - save state" );
280: }
281: graphicsStack.push(graphicsState.clone());
282: }
283: else if( operation.equals( "Q" ) )
284: {
285: //restore graphics state
286: if( log.isDebugEnabled() )
287: {
288: log.debug( "<" + operation + "> - restore state" );
289: }
290: graphicsState = (PDGraphicsState)graphicsStack.pop();
291: }
292: else if( operation.equals( "re" ) )
293: {
294: }
295: else if( operation.equals( "rg" ) )
296: {
297: //Set RGB color for nonstroking operations
298: }
299: else if( operation.equals( "RG" ) )
300: {
301: //Set RGB color for stroking operations
302: }
303: else if( operation.equals( "ri" ) )
304: {
305: //Set color rendering intent
306: }
307: else if( operation.equals( "s" ) )
308: {
309: //Close and stroke path
310: }
311: else if( operation.equals( "S" ) )
312: {
313: graphics.draw( linePath );
314: }
315: else if( operation.equals( "sc" ) )
316: {
317: //set color for nonstroking operations
318: //System.out.println( "<sc>" );
319: }
320: else if( operation.equals( "SC" ) )
321: {
322: //set color for stroking operations
323: //System.out.println( "<SC>" );
324: }
325: else if( operation.equals( "scn" ) )
326: {
327: //set color for nonstroking operations special
328: }
329: else if( operation.equals( "SCN" ) )
330: {
331: //set color for stroking operations special
332: }
333: else if( operation.equals( "sh" ) )
334: {
335: //(PDF 1.3) Paint area de.ned by shading pattern
336: }
337: else if( operation.equals( "T*" ) )
338: {
339: if (log.isDebugEnabled())
340: {
341: log.debug("<T* graphicsState.getTextState().getLeading()=\"" +
342: graphicsState.getTextState().getLeading() + "\">");
343: }
344: //move to start of next text line
345: if( graphicsState.getTextState().getLeading() == 0 )
346: {
347: graphicsState.getTextState().setLeading( -.01f );
348: }
349: Matrix td = new Matrix();
350: td.setValue( 2, 1, -1 * graphicsState.getTextState().getLeading() * textMatrix.getValue(1,1));
351: textLineMatrix = textLineMatrix.multiply( td );
352: textMatrix = textLineMatrix.copy();
353: }
354: else if( operation.equals( "Tc" ) )
355: {
356: //set character spacing
357: COSNumber characterSpacing = (COSNumber)arguments.get( 0 );
358: if (log.isDebugEnabled())
359: {
360: log.debug("<Tc characterSpacing=\"" + characterSpacing.floatValue() + "\" />");
361: }
362: graphicsState.getTextState().setCharacterSpacing( characterSpacing.floatValue() );
363: }
364: else if( operation.equals( "Td" ) )
365: {
366: COSNumber x = (COSNumber)arguments.get( 0 );
367: COSNumber y = (COSNumber)arguments.get( 1 );
368: if (log.isDebugEnabled())
369: {
370: log.debug("<Td x=\"" + x.floatValue() + "\" y=\"" + y.floatValue() + "\">");
371: }
372: Matrix td = new Matrix();
373: td.setValue( 2, 0, x.floatValue() * textMatrix.getValue(0,0) );
374: td.setValue( 2, 1, y.floatValue() * textMatrix.getValue(1,1) );
375: //log.debug( "textLineMatrix before " + textLineMatrix );
376: textLineMatrix = textLineMatrix.multiply( td );
377: //log.debug( "textLineMatrix after " + textLineMatrix );
378: textMatrix = textLineMatrix.copy();
379: }
380: else if( operation.equals( "TD" ) )
381: {
382: //move text position and set leading
383: COSNumber x = (COSNumber)arguments.get( 0 );
384: COSNumber y = (COSNumber)arguments.get( 1 );
385: if (log.isDebugEnabled())
386: {
387: log.debug("<TD x=\"" + x.floatValue() + "\" y=\"" + y.floatValue() + "\">");
388: }
389: graphicsState.getTextState().setLeading( -1 * y.floatValue() );
390: Matrix td = new Matrix();
391: td.setValue( 2, 0, x.floatValue() * textMatrix.getValue(0,0) );
392: td.setValue( 2, 1, y.floatValue() * textMatrix.getValue(1,1) );
393: //log.debug( "textLineMatrix before " + textLineMatrix );
394: textLineMatrix = textLineMatrix.multiply( td );
395: //log.debug( "textLineMatrix after " + textLineMatrix );
396: textMatrix = textLineMatrix.copy();
397: }
398: else if( operation.equals( "Tf" ) )
399: {
400: //set font and size
401: COSName fontName = (COSName)arguments.get( 0 );
402: graphicsState.getTextState().setFontSize( ((COSNumber)arguments.get( 1 ) ).floatValue() );
403:
404: if (log.isDebugEnabled())
405: {
406: log.debug("<Tf font=\"" + fontName.getName() + "\" size=\"" +
407: graphicsState.getTextState().getFontSize() + "\">");
408: }
409:
410: //old way
411: //graphicsState.getTextState().getFont() = (COSObject)stream.getDictionaryObject( fontName );
412: //if( graphicsState.getTextState().getFont() == null )
413: //{
414: // graphicsState.getTextState().getFont() = (COSObject)graphicsState.getTextState().getFont()
415: // Dictionary.getItem( fontName );
416: //}
417: graphicsState.getTextState().setFont( (PDFont)fonts.get( fontName.getName() ) );
418: if( graphicsState.getTextState().getFont() == null )
419: {
420: throw new IOException( "Error: Could not find font(" + fontName + ") in map=" + fonts );
421: }
422: //log.debug( "Font Resource=" + fontResource );
423: //log.debug( "Current Font=" + graphicsState.getTextState().getFont() );
424: //log.debug( "graphicsState.getTextState().getFontSize()=" + graphicsState.getTextState().getFontSize() );
425: }
426: else if( operation.equals( "Tj" ) )
427: {
428: COSString string = (COSString)arguments.get( 0 );
429: TextPosition pos = showString( string.getBytes() );
430: if (log.isDebugEnabled())
431: {
432: log.debug("<Tj string=\"" + string.getString() + "\">");
433: }
434: }
435: else if( operation.equals( "TJ" ) )
436: {
437: Matrix td = new Matrix();
438:
439: COSArray array = (COSArray)arguments.get( 0 );
440: for( int i=0; i<array.size(); i++ )
441: {
442: COSBase next = array.get( i );
443: if( next instanceof COSNumber )
444: {
445: float value = -1*
446: (((COSNumber)next).floatValue()/1000) *
447: graphicsState.getTextState().getFontSize() *
448: textMatrix.getValue(1,1);
449:
450: if (log.isDebugEnabled())
451: {
452: log.debug( "<TJ(" + i + ") value=\"" + value +
453: "\", param=\"" + ((COSNumber)next).floatValue() +
454: "\", fontsize=\"" + graphicsState.getTextState().getFontSize() + "\">" );
455: }
456: td.setValue( 2, 0, value );
457: textMatrix = textMatrix.multiply( td );
458: }
459: else if( next instanceof COSString )
460: {
461: TextPosition pos = showString( ((COSString)next).getBytes() );
462: if (log.isDebugEnabled())
463: {
464: log.debug("<TJ(" + i + ") string=\"" + pos.getString() + "\">");
465: }
466: }
467: else
468: {
469: throw new IOException( "Unknown type in array for TJ operation:" + next );
470: }
471: }
472: }
473: else if( operation.equals( "TL" ) )
474: {
475: COSNumber leading = (COSNumber)arguments.get( 0 );
476: graphicsState.getTextState().setLeading( leading.floatValue() );
477: if (log.isDebugEnabled())
478: {
479: log.debug("<TL leading=\"" + leading.floatValue() + "\" >");
480: }
481: }
482: else if( operation.equals( "Tm" ) )
483: {
484: //Set text matrix and text line matrix
485: COSNumber a = (COSNumber)arguments.get( 0 );
486: COSNumber b = (COSNumber)arguments.get( 1 );
487: COSNumber c = (COSNumber)arguments.get( 2 );
488: COSNumber d = (COSNumber)arguments.get( 3 );
489: COSNumber e = (COSNumber)arguments.get( 4 );
490: COSNumber f = (COSNumber)arguments.get( 5 );
491:
492: if (log.isDebugEnabled())
493: {
494: log.debug("<Tm " +
495: "a=\"" + a.floatValue() + "\" " +
496: "b=\"" + b.floatValue() + "\" " +
497: "c=\"" + c.floatValue() + "\" " +
498: "d=\"" + d.floatValue() + "\" " +
499: "e=\"" + e.floatValue() + "\" " +
500: "f=\"" + f.floatValue() + "\" >");
501: }
502:
503: textMatrix = new Matrix();
504: textMatrix.setValue( 0, 0, a.floatValue() );
505: textMatrix.setValue( 0, 1, b.floatValue() );
506: textMatrix.setValue( 1, 0, c.floatValue() );
507: textMatrix.setValue( 1, 1, d.floatValue() );
508: textMatrix.setValue( 2, 0, e.floatValue() );
509: textMatrix.setValue( 2, 1, f.floatValue() );
510: textLineMatrix = textMatrix.copy();
511: }
512: else if( operation.equals( "Tr" ) )
513: {
514: //Set text rendering mode
515: //System.out.println( "<Tr>" );
516: }
517: else if( operation.equals( "Ts" ) )
518: {
519: //Set text rise
520: //System.out.println( "<Ts>" );
521: }
522: else if( operation.equals( "Tw" ) )
523: {
524: //set word spacing
525: COSNumber wordSpacing = (COSNumber)arguments.get( 0 );
526: if (log.isDebugEnabled())
527: {
528: log.debug("<Tw wordSpacing=\"" + wordSpacing.floatValue() + "\" />");
529: }
530: graphicsState.getTextState().setWordSpacing( wordSpacing.floatValue() );
531: }
532: else if( operation.equals( "Tz" ) )
533: {
534: //Set horizontal text scaling
535: }
536: else if( operation.equals( "v" ) )
537: {
538: //Append curved segment to path (initial point replicated)
539: }
540: else if( operation.equals( "w" ) )
541: {
542: //Set the line width in the graphics state
543: //System.out.println( "<w>" );
544: }
545: else if( operation.equals( "W" ) )
546: {
547: //Set clipping path using nonzero winding number rule
548: //System.out.println( "<W>" );
549: }
550: else if( operation.equals( "W*" ) )
551: {
552: //Set clipping path using even-odd rule
553: }
554: else if( operation.equals( "y" ) )
555: {
556: //Append curved segment to path (final point replicated)
557: }
558: else if( operation.equals( "'" ) )
559: {
560: // Move to start of next text line, and show text
561: //
562: COSString string = (COSString)arguments.get( 0 );
563: if (log.isDebugEnabled())
564: {
565: log.debug("<' string=\"" + string.getString() + "\">");
566: }
567:
568: Matrix td = new Matrix();
569: td.setValue( 2, 1, -1 * graphicsState.getTextState().getLeading() * textMatrix.getValue(1,1));
570: textLineMatrix = textLineMatrix.multiply( td );
571: textMatrix = textLineMatrix.copy();
572:
573: showString( string.getBytes() );
574: }
575: else if( operation.equals( "\"" ) )
576: {
577: //Set word and character spacing, move to next line, and show text
578: //
579: COSNumber wordSpacing = (COSNumber)arguments.get( 0 );
580: COSNumber characterSpacing = (COSNumber)arguments.get( 1 );
581: COSString string = (COSString)arguments.get( 2 );
582:
583: if (log.isDebugEnabled())
584: {
585: log.debug("<\" wordSpacing=\"" + wordSpacing +
586: "\", characterSpacing=\"" + characterSpacing +
587: "\", string=\"" + string.getString() + "\">");
588: }
589:
590: graphicsState.getTextState().setCharacterSpacing( characterSpacing.floatValue() );
591: graphicsState.getTextState().setWordSpacing( wordSpacing.floatValue() );
592:
593: Matrix td = new Matrix();
594: td.setValue( 2, 1, -1 * graphicsState.getTextState().getLeading() * textMatrix.getValue(1,1));
595: textLineMatrix = textLineMatrix.multiply( td );
596: textMatrix = textLineMatrix.copy();
597:
598: showString( string.getBytes() );
599: }*/
600: }
601:
602: }
|