1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 package org.apache.pdfbox.pdmodel.graphics; 18 19 import org.apache.pdfbox.cos.COSArray; 20 import org.apache.pdfbox.cos.COSBase; 21 import org.apache.pdfbox.cos.COSDictionary; 22 import org.apache.pdfbox.cos.COSFloat; 23 import org.apache.pdfbox.cos.COSName; 24 import org.apache.pdfbox.cos.COSNumber; 25 26 import org.apache.pdfbox.pdmodel.common.COSObjectable; 27 28 import java.io.IOException; 29 30 import java.util.Iterator; 31 32 /** 33 * This class represents the graphics state dictionary that is stored in the PDF document. 34 * The PDGraphicsStateValue holds the current runtime values as a stream is being executed. 35 * 36 * @author <a href="mailto:ben@benlitchfield.com">Ben Litchfield</a> 37 * @version $Revision: 1.5 $ 38 */ 39 public class PDExtendedGraphicsState implements COSObjectable 40 { 41 private static final COSName LW = COSName.getPDFName( "LW" ); 42 private static final COSName LC = COSName.getPDFName( "LC" ); 43 private static final COSName LJ = COSName.getPDFName( "LJ" ); 44 private static final COSName ML = COSName.getPDFName( "ML" ); 45 private static final COSName D = COSName.getPDFName( "D" ); 46 private static final COSName RI = COSName.getPDFName( "RI" ); 47 private static final COSName OP = COSName.getPDFName( "OP" ); 48 private static final COSName OP_NS = COSName.getPDFName( "op" ); 49 private static final COSName OPM = COSName.getPDFName( "OPM" ); 50 private static final COSName FONT = COSName.getPDFName( "Font" ); 51 private static final COSName FL = COSName.getPDFName( "FL" ); 52 private static final COSName SM = COSName.getPDFName( "SM" ); 53 private static final COSName SA = COSName.getPDFName( "SA" ); 54 private static final COSName CA = COSName.getPDFName( "CA" ); 55 private static final COSName CA_NS = COSName.getPDFName( "ca" ); 56 private static final COSName AIS = COSName.getPDFName( "AIS" ); 57 private static final COSName TK = COSName.getPDFName( "TK" ); 58 59 /** 60 * Rendering intent constants, see PDF Reference 1.5 Section 4.5.4 Rendering Intents. 61 */ 62 public static final String RENDERING_INTENT_ABSOLUTE_COLORIMETRIC = "AbsoluteColorimetric"; 63 /** 64 * Rendering intent constants, see PDF Reference 1.5 Section 4.5.4 Rendering Intents. 65 */ 66 public static final String RENDERING_INTENT_RELATIVE_COLORIMETRIC = "RelativeColorimetric"; 67 /** 68 * Rendering intent constants, see PDF Reference 1.5 Section 4.5.4 Rendering Intents. 69 */ 70 public static final String RENDERING_INTENT_SATURATION = "Saturation"; 71 /** 72 * Rendering intent constants, see PDF Reference 1.5 Section 4.5.4 Rendering Intents. 73 */ 74 public static final String RENDERING_INTENT_PERCEPTUAL = "Perceptual"; 75 76 77 private COSDictionary graphicsState; 78 79 /** 80 * Default constructor, creates blank graphics state. 81 */ 82 public PDExtendedGraphicsState() 83 { 84 graphicsState = new COSDictionary(); 85 graphicsState.setItem( COSName.TYPE, COSName.getPDFName( "ExtGState" ) ); 86 } 87 88 /** 89 * Create a graphics state from an existing dictionary. 90 * 91 * @param dictionary The existing graphics state. 92 */ 93 public PDExtendedGraphicsState( COSDictionary dictionary ) 94 { 95 graphicsState = dictionary; 96 } 97 98 /** 99 * This will implement the gs operator. 100 * 101 * @param gs The state to copy this dictionaries values into. 102 * 103 * @throws IOException If there is an error copying font information. 104 */ 105 public void copyIntoGraphicsState( PDGraphicsState gs ) throws IOException 106 { 107 for( COSName key : graphicsState.keySet() ) 108 { 109 if( key.equals( LW ) ) 110 { 111 gs.setLineWidth( getLineWidth().doubleValue() ); 112 } 113 else if( key.equals( LC ) ) 114 { 115 gs.setLineCap( getLineCapStyle() ); 116 } 117 else if( key.equals( LJ ) ) 118 { 119 gs.setLineJoin( getLineJoinStyle() ); 120 } 121 else if( key.equals( ML ) ) 122 { 123 gs.setMiterLimit( getMiterLimit().doubleValue() ); 124 } 125 else if( key.equals( D ) ) 126 { 127 gs.setLineDashPattern( getLineDashPattern() ); 128 } 129 else if( key.equals( RI ) ) 130 { 131 gs.setRenderingIntent( getRenderingIntent() ); 132 } 133 else if( key.equals( OPM ) ) 134 { 135 gs.setOverprintMode( getOverprintMode().doubleValue() ); 136 } 137 else if( key.equals( FONT ) ) 138 { 139 PDFontSetting setting = getFontSetting(); 140 gs.getTextState().setFont( setting.getFont() ); 141 gs.getTextState().setFontSize( setting.getFontSize() ); 142 } 143 else if( key.equals( FL ) ) 144 { 145 gs.setFlatness( getFlatnessTolerance().floatValue() ); 146 } 147 else if( key.equals( SM ) ) 148 { 149 gs.setSmoothness( getSmoothnessTolerance().floatValue() ); 150 } 151 else if( key.equals( SA ) ) 152 { 153 gs.setStrokeAdjustment( getAutomaticStrokeAdjustment() ); 154 } 155 else if( key.equals( CA ) ) 156 { 157 gs.setAlphaConstants( getStrokingAlpaConstant().floatValue() ); 158 }/** 159 else if( key.equals( CA_NS ) ) 160 { 161 }**/ 162 else if( key.equals( AIS ) ) 163 { 164 gs.setAlphaSource( getAlphaSourceFlag() ); 165 } 166 else if( key.equals( TK ) ) 167 { 168 gs.getTextState().setKnockoutFlag( getTextKnockoutFlag() ); 169 } 170 } 171 } 172 173 /** 174 * This will get the underlying dictionary that this class acts on. 175 * 176 * @return The underlying dictionary for this class. 177 */ 178 public COSDictionary getCOSDictionary() 179 { 180 return graphicsState; 181 } 182 183 /** 184 * Convert this standard java object to a COS object. 185 * 186 * @return The cos object that matches this Java object. 187 */ 188 public COSBase getCOSObject() 189 { 190 return graphicsState; 191 } 192 193 /** 194 * This will get the line width. This will return null if there is no line width 195 * 196 * @return null or the LW value of the dictionary. 197 */ 198 public Float getLineWidth() 199 { 200 return getFloatItem( LW ); 201 } 202 203 /** 204 * This will set the line width. 205 * 206 * @param width The line width for the object. 207 */ 208 public void setLineWidth( Float width ) 209 { 210 setFloatItem( LW, width ); 211 } 212 213 /** 214 * This will get the line cap style. 215 * 216 * @return null or the LC value of the dictionary. 217 */ 218 public int getLineCapStyle() 219 { 220 return graphicsState.getInt( LC ); 221 } 222 223 /** 224 * This will set the line cap style for the graphics state. 225 * 226 * @param style The new line cap style to set. 227 */ 228 public void setLineCapStyle( int style ) 229 { 230 graphicsState.setInt( LC, style ); 231 } 232 233 /** 234 * This will get the line join style. 235 * 236 * @return null or the LJ value in the dictionary. 237 */ 238 public int getLineJoinStyle() 239 { 240 return graphicsState.getInt( LJ ); 241 } 242 243 /** 244 * This will set the line join style. 245 * 246 * @param style The new line join style. 247 */ 248 public void setLineJoinStyle( int style ) 249 { 250 graphicsState.setInt( LJ, style ); 251 } 252 253 254 /** 255 * This will get the miter limit. 256 * 257 * @return null or the ML value in the dictionary. 258 */ 259 public Float getMiterLimit() 260 { 261 return getFloatItem( ML ); 262 } 263 264 /** 265 * This will set the miter limit for the graphics state. 266 * 267 * @param miterLimit The new miter limit value 268 */ 269 public void setMiterLimit( Float miterLimit ) 270 { 271 setFloatItem( ML, miterLimit ); 272 } 273 274 /** 275 * This will get the dash pattern. 276 * 277 * @return null or the D value in the dictionary. 278 */ 279 public PDLineDashPattern getLineDashPattern() 280 { 281 PDLineDashPattern retval = null; 282 COSArray dp = (COSArray)graphicsState.getDictionaryObject( D ); 283 if( dp != null ) 284 { 285 retval = new PDLineDashPattern( dp ); 286 } 287 return retval; 288 } 289 290 /** 291 * This will set the dash pattern for the graphics state. 292 * 293 * @param dashPattern The dash pattern 294 */ 295 public void setLineDashPattern( PDLineDashPattern dashPattern ) 296 { 297 graphicsState.setItem( D, dashPattern.getCOSObject() ); 298 } 299 300 /** 301 * This will get the rendering intent. 302 * 303 * @return null or the RI value in the dictionary. 304 */ 305 public String getRenderingIntent() 306 { 307 return graphicsState.getNameAsString( "RI" ); 308 } 309 310 /** 311 * This will set the rendering intent for the graphics state. 312 * 313 * @param ri The new rendering intent 314 */ 315 public void setRenderingIntent( String ri ) 316 { 317 graphicsState.setName( "RI", ri ); 318 } 319 320 /** 321 * This will get the overprint control. 322 * 323 * @return The overprint control or null if one has not been set. 324 */ 325 public boolean getStrokingOverprintControl() 326 { 327 return graphicsState.getBoolean( OP, false ); 328 } 329 330 /** 331 * This will get the overprint control(OP). 332 * 333 * @param op The overprint control. 334 */ 335 public void setStrokingOverprintControl( boolean op ) 336 { 337 graphicsState.setBoolean( OP, op ); 338 } 339 340 /** 341 * This will get the overprint control for non stroking operations. If this 342 * value is null then the regular overprint control value will be returned. 343 * 344 * @return The overprint control or null if one has not been set. 345 */ 346 public boolean getNonStrokingOverprintControl() 347 { 348 return graphicsState.getBoolean( OP_NS, getStrokingOverprintControl() ); 349 } 350 351 /** 352 * This will get the overprint control(OP). 353 * 354 * @param op The overprint control. 355 */ 356 public void setNonStrokingOverprintControl( boolean op ) 357 { 358 graphicsState.setBoolean( OP_NS, op ); 359 } 360 361 /** 362 * This will get the overprint control mode. 363 * 364 * @return The overprint control mode or null if one has not been set. 365 */ 366 public Float getOverprintMode() 367 { 368 return getFloatItem( OPM ); 369 } 370 371 /** 372 * This will get the overprint mode(OPM). 373 * 374 * @param overprintMode The overprint mode 375 */ 376 public void setOverprintMode( Float overprintMode ) 377 { 378 setFloatItem( OPM, overprintMode ); 379 } 380 381 /** 382 * This will get the font setting of the graphics state. 383 * 384 * @return The font setting. 385 */ 386 public PDFontSetting getFontSetting() 387 { 388 PDFontSetting setting = null; 389 COSArray font = (COSArray)graphicsState.getDictionaryObject( FONT ); 390 if( font != null ) 391 { 392 setting = new PDFontSetting( font ); 393 } 394 return setting; 395 } 396 397 /** 398 * This will set the font setting for this graphics state. 399 * 400 * @param fs The new font setting. 401 */ 402 public void setFontSetting( PDFontSetting fs ) 403 { 404 graphicsState.setItem( FONT, fs ); 405 } 406 407 /** 408 * This will get the flatness tolerance. 409 * 410 * @return The flatness tolerance or null if one has not been set. 411 */ 412 public Float getFlatnessTolerance() 413 { 414 return getFloatItem( FL ); 415 } 416 417 /** 418 * This will get the flatness tolerance. 419 * 420 * @param flatness The new flatness tolerance 421 */ 422 public void setFlatnessTolerance( Float flatness ) 423 { 424 setFloatItem( FL, flatness ); 425 } 426 427 /** 428 * This will get the smothness tolerance. 429 * 430 * @return The smothness tolerance or null if one has not been set. 431 */ 432 public Float getSmoothnessTolerance() 433 { 434 return getFloatItem( SM ); 435 } 436 437 /** 438 * This will get the smoothness tolerance. 439 * 440 * @param smoothness The new smoothness tolerance 441 */ 442 public void setSmoothnessTolerance( Float smoothness ) 443 { 444 setFloatItem( SM, smoothness ); 445 } 446 447 /** 448 * This will get the automatic stroke adjustment flag. 449 * 450 * @return The automatic stroke adjustment flag or null if one has not been set. 451 */ 452 public boolean getAutomaticStrokeAdjustment() 453 { 454 return graphicsState.getBoolean( SA,false ); 455 } 456 457 /** 458 * This will get the automatic stroke adjustment flag. 459 * 460 * @param sa The new automatic stroke adjustment flag. 461 */ 462 public void setAutomaticStrokeAdjustment( boolean sa ) 463 { 464 graphicsState.setBoolean( SA, sa ); 465 } 466 467 /** 468 * This will get the stroking alpha constant. 469 * 470 * @return The stroking alpha constant or null if one has not been set. 471 */ 472 public Float getStrokingAlpaConstant() 473 { 474 return getFloatItem( CA ); 475 } 476 477 /** 478 * This will get the stroking alpha constant. 479 * 480 * @param alpha The new stroking alpha constant. 481 */ 482 public void setStrokingAlphaConstant( Float alpha ) 483 { 484 setFloatItem( CA, alpha ); 485 } 486 487 /** 488 * This will get the non stroking alpha constant. 489 * 490 * @return The non stroking alpha constant or null if one has not been set. 491 */ 492 public Float getNonStrokingAlpaConstant() 493 { 494 return getFloatItem( CA_NS ); 495 } 496 497 /** 498 * This will get the non stroking alpha constant. 499 * 500 * @param alpha The new non stroking alpha constant. 501 */ 502 public void setNonStrokingAlphaConstant( Float alpha ) 503 { 504 setFloatItem( CA_NS, alpha ); 505 } 506 507 /** 508 * This will get the alpha source flag. 509 * 510 * @return The alpha source flag. 511 */ 512 public boolean getAlphaSourceFlag() 513 { 514 return graphicsState.getBoolean( AIS, false ); 515 } 516 517 /** 518 * This will get the alpha source flag. 519 * 520 * @param alpha The alpha source flag. 521 */ 522 public void setAlphaSourceFlag( boolean alpha ) 523 { 524 graphicsState.setBoolean( AIS, alpha ); 525 } 526 527 /** 528 * This will get the text knockout flag. 529 * 530 * @return The text knockout flag. 531 */ 532 public boolean getTextKnockoutFlag() 533 { 534 return graphicsState.getBoolean( TK,true ); 535 } 536 537 /** 538 * This will get the text knockout flag. 539 * 540 * @param tk The text knockout flag. 541 */ 542 public void setTextKnockoutFlag( boolean tk ) 543 { 544 graphicsState.setBoolean( TK, tk ); 545 } 546 547 /** 548 * This will get a float item from the dictionary. 549 * 550 * @param key The key to the item. 551 * 552 * @return The value for that item. 553 */ 554 private Float getFloatItem( COSName key ) 555 { 556 Float retval = null; 557 COSNumber value = (COSNumber)graphicsState.getDictionaryObject( key ); 558 if( value != null ) 559 { 560 retval = new Float( value.floatValue() ); 561 } 562 return retval; 563 } 564 565 /** 566 * This will set a float object. 567 * 568 * @param key The key to the data that we are setting. 569 * @param value The value that we are setting. 570 */ 571 private void setFloatItem( COSName key, Float value ) 572 { 573 if( value == null ) 574 { 575 graphicsState.removeItem( key ); 576 } 577 else 578 { 579 graphicsState.setItem( key, new COSFloat( value.floatValue() ) ); 580 } 581 } 582 }