001/* 002 * $Id: MetaDo.java 4784 2011-03-15 08:33:00Z blowagie $ 003 * 004 * This file is part of the iText (R) project. 005 * Copyright (c) 1998-2011 1T3XT BVBA 006 * Authors: Bruno Lowagie, Paulo Soares, et al. 007 * 008 * This program is free software; you can redistribute it and/or modify 009 * it under the terms of the GNU Affero General Public License version 3 010 * as published by the Free Software Foundation with the addition of the 011 * following permission added to Section 15 as permitted in Section 7(a): 012 * FOR ANY PART OF THE COVERED WORK IN WHICH THE COPYRIGHT IS OWNED BY 1T3XT, 013 * 1T3XT DISCLAIMS THE WARRANTY OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. 014 * 015 * This program is distributed in the hope that it will be useful, but 016 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 017 * or FITNESS FOR A PARTICULAR PURPOSE. 018 * See the GNU Affero General Public License for more details. 019 * You should have received a copy of the GNU Affero General Public License 020 * along with this program; if not, see http://www.gnu.org/licenses or write to 021 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 022 * Boston, MA, 02110-1301 USA, or download the license from the following URL: 023 * http://itextpdf.com/terms-of-use/ 024 * 025 * The interactive user interfaces in modified source and object code versions 026 * of this program must display Appropriate Legal Notices, as required under 027 * Section 5 of the GNU Affero General Public License. 028 * 029 * In accordance with Section 7(b) of the GNU Affero General Public License, 030 * a covered work must retain the producer line in every PDF that is created 031 * or manipulated using iText. 032 * 033 * You can be released from the requirements of the license by purchasing 034 * a commercial license. Buying such a license is mandatory as soon as you 035 * develop commercial activities involving the iText software without 036 * disclosing the source code of your own applications. 037 * These activities include: offering paid services to customers as an ASP, 038 * serving PDFs on the fly in a web application, shipping iText with a closed 039 * source product. 040 * 041 * For more information, please contact iText Software Corp. at this 042 * address: sales@itextpdf.com 043 */ 044package com.itextpdf.text.pdf.codec.wmf; 045import java.io.ByteArrayInputStream; 046import java.io.ByteArrayOutputStream; 047import java.io.IOException; 048import java.io.InputStream; 049import java.io.OutputStream; 050import java.io.UnsupportedEncodingException; 051import java.util.ArrayList; 052 053import com.itextpdf.text.BaseColor; 054import com.itextpdf.text.DocumentException; 055import com.itextpdf.text.Image; 056import com.itextpdf.text.error_messages.MessageLocalization; 057import com.itextpdf.text.pdf.BaseFont; 058import com.itextpdf.text.pdf.PdfContentByte; 059import com.itextpdf.text.pdf.codec.BmpImage; 060 061public class MetaDo { 062 063 public static final int META_SETBKCOLOR = 0x0201; 064 public static final int META_SETBKMODE = 0x0102; 065 public static final int META_SETMAPMODE = 0x0103; 066 public static final int META_SETROP2 = 0x0104; 067 public static final int META_SETRELABS = 0x0105; 068 public static final int META_SETPOLYFILLMODE = 0x0106; 069 public static final int META_SETSTRETCHBLTMODE = 0x0107; 070 public static final int META_SETTEXTCHAREXTRA = 0x0108; 071 public static final int META_SETTEXTCOLOR = 0x0209; 072 public static final int META_SETTEXTJUSTIFICATION = 0x020A; 073 public static final int META_SETWINDOWORG = 0x020B; 074 public static final int META_SETWINDOWEXT = 0x020C; 075 public static final int META_SETVIEWPORTORG = 0x020D; 076 public static final int META_SETVIEWPORTEXT = 0x020E; 077 public static final int META_OFFSETWINDOWORG = 0x020F; 078 public static final int META_SCALEWINDOWEXT = 0x0410; 079 public static final int META_OFFSETVIEWPORTORG = 0x0211; 080 public static final int META_SCALEVIEWPORTEXT = 0x0412; 081 public static final int META_LINETO = 0x0213; 082 public static final int META_MOVETO = 0x0214; 083 public static final int META_EXCLUDECLIPRECT = 0x0415; 084 public static final int META_INTERSECTCLIPRECT = 0x0416; 085 public static final int META_ARC = 0x0817; 086 public static final int META_ELLIPSE = 0x0418; 087 public static final int META_FLOODFILL = 0x0419; 088 public static final int META_PIE = 0x081A; 089 public static final int META_RECTANGLE = 0x041B; 090 public static final int META_ROUNDRECT = 0x061C; 091 public static final int META_PATBLT = 0x061D; 092 public static final int META_SAVEDC = 0x001E; 093 public static final int META_SETPIXEL = 0x041F; 094 public static final int META_OFFSETCLIPRGN = 0x0220; 095 public static final int META_TEXTOUT = 0x0521; 096 public static final int META_BITBLT = 0x0922; 097 public static final int META_STRETCHBLT = 0x0B23; 098 public static final int META_POLYGON = 0x0324; 099 public static final int META_POLYLINE = 0x0325; 100 public static final int META_ESCAPE = 0x0626; 101 public static final int META_RESTOREDC = 0x0127; 102 public static final int META_FILLREGION = 0x0228; 103 public static final int META_FRAMEREGION = 0x0429; 104 public static final int META_INVERTREGION = 0x012A; 105 public static final int META_PAINTREGION = 0x012B; 106 public static final int META_SELECTCLIPREGION = 0x012C; 107 public static final int META_SELECTOBJECT = 0x012D; 108 public static final int META_SETTEXTALIGN = 0x012E; 109 public static final int META_CHORD = 0x0830; 110 public static final int META_SETMAPPERFLAGS = 0x0231; 111 public static final int META_EXTTEXTOUT = 0x0a32; 112 public static final int META_SETDIBTODEV = 0x0d33; 113 public static final int META_SELECTPALETTE = 0x0234; 114 public static final int META_REALIZEPALETTE = 0x0035; 115 public static final int META_ANIMATEPALETTE = 0x0436; 116 public static final int META_SETPALENTRIES = 0x0037; 117 public static final int META_POLYPOLYGON = 0x0538; 118 public static final int META_RESIZEPALETTE = 0x0139; 119 public static final int META_DIBBITBLT = 0x0940; 120 public static final int META_DIBSTRETCHBLT = 0x0b41; 121 public static final int META_DIBCREATEPATTERNBRUSH = 0x0142; 122 public static final int META_STRETCHDIB = 0x0f43; 123 public static final int META_EXTFLOODFILL = 0x0548; 124 public static final int META_DELETEOBJECT = 0x01f0; 125 public static final int META_CREATEPALETTE = 0x00f7; 126 public static final int META_CREATEPATTERNBRUSH = 0x01F9; 127 public static final int META_CREATEPENINDIRECT = 0x02FA; 128 public static final int META_CREATEFONTINDIRECT = 0x02FB; 129 public static final int META_CREATEBRUSHINDIRECT = 0x02FC; 130 public static final int META_CREATEREGION = 0x06FF; 131 132 public PdfContentByte cb; 133 public InputMeta in; 134 int left; 135 int top; 136 int right; 137 int bottom; 138 int inch; 139 MetaState state = new MetaState(); 140 141 public MetaDo(InputStream in, PdfContentByte cb) { 142 this.cb = cb; 143 this.in = new InputMeta(in); 144 } 145 146 public void readAll() throws IOException, DocumentException{ 147 if (in.readInt() != 0x9AC6CDD7) { 148 throw new DocumentException(MessageLocalization.getComposedMessage("not.a.placeable.windows.metafile")); 149 } 150 in.readWord(); 151 left = in.readShort(); 152 top = in.readShort(); 153 right = in.readShort(); 154 bottom = in.readShort(); 155 inch = in.readWord(); 156 state.setScalingX((float)(right - left) / (float)inch * 72f); 157 state.setScalingY((float)(bottom - top) / (float)inch * 72f); 158 state.setOffsetWx(left); 159 state.setOffsetWy(top); 160 state.setExtentWx(right - left); 161 state.setExtentWy(bottom - top); 162 in.readInt(); 163 in.readWord(); 164 in.skip(18); 165 166 int tsize; 167 int function; 168 cb.setLineCap(1); 169 cb.setLineJoin(1); 170 for (;;) { 171 int lenMarker = in.getLength(); 172 tsize = in.readInt(); 173 if (tsize < 3) 174 break; 175 function = in.readWord(); 176 switch (function) { 177 case 0: 178 break; 179 case META_CREATEPALETTE: 180 case META_CREATEREGION: 181 case META_DIBCREATEPATTERNBRUSH: 182 state.addMetaObject(new MetaObject()); 183 break; 184 case META_CREATEPENINDIRECT: 185 { 186 MetaPen pen = new MetaPen(); 187 pen.init(in); 188 state.addMetaObject(pen); 189 break; 190 } 191 case META_CREATEBRUSHINDIRECT: 192 { 193 MetaBrush brush = new MetaBrush(); 194 brush.init(in); 195 state.addMetaObject(brush); 196 break; 197 } 198 case META_CREATEFONTINDIRECT: 199 { 200 MetaFont font = new MetaFont(); 201 font.init(in); 202 state.addMetaObject(font); 203 break; 204 } 205 case META_SELECTOBJECT: 206 { 207 int idx = in.readWord(); 208 state.selectMetaObject(idx, cb); 209 break; 210 } 211 case META_DELETEOBJECT: 212 { 213 int idx = in.readWord(); 214 state.deleteMetaObject(idx); 215 break; 216 } 217 case META_SAVEDC: 218 state.saveState(cb); 219 break; 220 case META_RESTOREDC: 221 { 222 int idx = in.readShort(); 223 state.restoreState(idx, cb); 224 break; 225 } 226 case META_SETWINDOWORG: 227 state.setOffsetWy(in.readShort()); 228 state.setOffsetWx(in.readShort()); 229 break; 230 case META_SETWINDOWEXT: 231 state.setExtentWy(in.readShort()); 232 state.setExtentWx(in.readShort()); 233 break; 234 case META_MOVETO: 235 { 236 int y = in.readShort(); 237 Point p = new Point(in.readShort(), y); 238 state.setCurrentPoint(p); 239 break; 240 } 241 case META_LINETO: 242 { 243 int y = in.readShort(); 244 int x = in.readShort(); 245 Point p = state.getCurrentPoint(); 246 cb.moveTo(state.transformX(p.x), state.transformY(p.y)); 247 cb.lineTo(state.transformX(x), state.transformY(y)); 248 cb.stroke(); 249 state.setCurrentPoint(new Point(x, y)); 250 break; 251 } 252 case META_POLYLINE: 253 { 254 state.setLineJoinPolygon(cb); 255 int len = in.readWord(); 256 int x = in.readShort(); 257 int y = in.readShort(); 258 cb.moveTo(state.transformX(x), state.transformY(y)); 259 for (int k = 1; k < len; ++k) { 260 x = in.readShort(); 261 y = in.readShort(); 262 cb.lineTo(state.transformX(x), state.transformY(y)); 263 } 264 cb.stroke(); 265 break; 266 } 267 case META_POLYGON: 268 { 269 if (isNullStrokeFill(false)) 270 break; 271 int len = in.readWord(); 272 int sx = in.readShort(); 273 int sy = in.readShort(); 274 cb.moveTo(state.transformX(sx), state.transformY(sy)); 275 for (int k = 1; k < len; ++k) { 276 int x = in.readShort(); 277 int y = in.readShort(); 278 cb.lineTo(state.transformX(x), state.transformY(y)); 279 } 280 cb.lineTo(state.transformX(sx), state.transformY(sy)); 281 strokeAndFill(); 282 break; 283 } 284 case META_POLYPOLYGON: 285 { 286 if (isNullStrokeFill(false)) 287 break; 288 int numPoly = in.readWord(); 289 int lens[] = new int[numPoly]; 290 for (int k = 0; k < lens.length; ++k) 291 lens[k] = in.readWord(); 292 for (int j = 0; j < lens.length; ++j) { 293 int len = lens[j]; 294 int sx = in.readShort(); 295 int sy = in.readShort(); 296 cb.moveTo(state.transformX(sx), state.transformY(sy)); 297 for (int k = 1; k < len; ++k) { 298 int x = in.readShort(); 299 int y = in.readShort(); 300 cb.lineTo(state.transformX(x), state.transformY(y)); 301 } 302 cb.lineTo(state.transformX(sx), state.transformY(sy)); 303 } 304 strokeAndFill(); 305 break; 306 } 307 case META_ELLIPSE: 308 { 309 if (isNullStrokeFill(state.getLineNeutral())) 310 break; 311 int b = in.readShort(); 312 int r = in.readShort(); 313 int t = in.readShort(); 314 int l = in.readShort(); 315 cb.arc(state.transformX(l), state.transformY(b), state.transformX(r), state.transformY(t), 0, 360); 316 strokeAndFill(); 317 break; 318 } 319 case META_ARC: 320 { 321 if (isNullStrokeFill(state.getLineNeutral())) 322 break; 323 float yend = state.transformY(in.readShort()); 324 float xend = state.transformX(in.readShort()); 325 float ystart = state.transformY(in.readShort()); 326 float xstart = state.transformX(in.readShort()); 327 float b = state.transformY(in.readShort()); 328 float r = state.transformX(in.readShort()); 329 float t = state.transformY(in.readShort()); 330 float l = state.transformX(in.readShort()); 331 float cx = (r + l) / 2; 332 float cy = (t + b) / 2; 333 float arc1 = getArc(cx, cy, xstart, ystart); 334 float arc2 = getArc(cx, cy, xend, yend); 335 arc2 -= arc1; 336 if (arc2 <= 0) 337 arc2 += 360; 338 cb.arc(l, b, r, t, arc1, arc2); 339 cb.stroke(); 340 break; 341 } 342 case META_PIE: 343 { 344 if (isNullStrokeFill(state.getLineNeutral())) 345 break; 346 float yend = state.transformY(in.readShort()); 347 float xend = state.transformX(in.readShort()); 348 float ystart = state.transformY(in.readShort()); 349 float xstart = state.transformX(in.readShort()); 350 float b = state.transformY(in.readShort()); 351 float r = state.transformX(in.readShort()); 352 float t = state.transformY(in.readShort()); 353 float l = state.transformX(in.readShort()); 354 float cx = (r + l) / 2; 355 float cy = (t + b) / 2; 356 float arc1 = getArc(cx, cy, xstart, ystart); 357 float arc2 = getArc(cx, cy, xend, yend); 358 arc2 -= arc1; 359 if (arc2 <= 0) 360 arc2 += 360; 361 ArrayList<float[]> ar = PdfContentByte.bezierArc(l, b, r, t, arc1, arc2); 362 if (ar.isEmpty()) 363 break; 364 float pt[] = ar.get(0); 365 cb.moveTo(cx, cy); 366 cb.lineTo(pt[0], pt[1]); 367 for (int k = 0; k < ar.size(); ++k) { 368 pt = ar.get(k); 369 cb.curveTo(pt[2], pt[3], pt[4], pt[5], pt[6], pt[7]); 370 } 371 cb.lineTo(cx, cy); 372 strokeAndFill(); 373 break; 374 } 375 case META_CHORD: 376 { 377 if (isNullStrokeFill(state.getLineNeutral())) 378 break; 379 float yend = state.transformY(in.readShort()); 380 float xend = state.transformX(in.readShort()); 381 float ystart = state.transformY(in.readShort()); 382 float xstart = state.transformX(in.readShort()); 383 float b = state.transformY(in.readShort()); 384 float r = state.transformX(in.readShort()); 385 float t = state.transformY(in.readShort()); 386 float l = state.transformX(in.readShort()); 387 float cx = (r + l) / 2; 388 float cy = (t + b) / 2; 389 float arc1 = getArc(cx, cy, xstart, ystart); 390 float arc2 = getArc(cx, cy, xend, yend); 391 arc2 -= arc1; 392 if (arc2 <= 0) 393 arc2 += 360; 394 ArrayList<float[]> ar = PdfContentByte.bezierArc(l, b, r, t, arc1, arc2); 395 if (ar.isEmpty()) 396 break; 397 float pt[] = ar.get(0); 398 cx = pt[0]; 399 cy = pt[1]; 400 cb.moveTo(cx, cy); 401 for (int k = 0; k < ar.size(); ++k) { 402 pt = ar.get(k); 403 cb.curveTo(pt[2], pt[3], pt[4], pt[5], pt[6], pt[7]); 404 } 405 cb.lineTo(cx, cy); 406 strokeAndFill(); 407 break; 408 } 409 case META_RECTANGLE: 410 { 411 if (isNullStrokeFill(true)) 412 break; 413 float b = state.transformY(in.readShort()); 414 float r = state.transformX(in.readShort()); 415 float t = state.transformY(in.readShort()); 416 float l = state.transformX(in.readShort()); 417 cb.rectangle(l, b, r - l, t - b); 418 strokeAndFill(); 419 break; 420 } 421 case META_ROUNDRECT: 422 { 423 if (isNullStrokeFill(true)) 424 break; 425 float h = state.transformY(0) - state.transformY(in.readShort()); 426 float w = state.transformX(in.readShort()) - state.transformX(0); 427 float b = state.transformY(in.readShort()); 428 float r = state.transformX(in.readShort()); 429 float t = state.transformY(in.readShort()); 430 float l = state.transformX(in.readShort()); 431 cb.roundRectangle(l, b, r - l, t - b, (h + w) / 4); 432 strokeAndFill(); 433 break; 434 } 435 case META_INTERSECTCLIPRECT: 436 { 437 float b = state.transformY(in.readShort()); 438 float r = state.transformX(in.readShort()); 439 float t = state.transformY(in.readShort()); 440 float l = state.transformX(in.readShort()); 441 cb.rectangle(l, b, r - l, t - b); 442 cb.eoClip(); 443 cb.newPath(); 444 break; 445 } 446 case META_EXTTEXTOUT: 447 { 448 int y = in.readShort(); 449 int x = in.readShort(); 450 int count = in.readWord(); 451 int flag = in.readWord(); 452 int x1 = 0; 453 int y1 = 0; 454 int x2 = 0; 455 int y2 = 0; 456 if ((flag & (MetaFont.ETO_CLIPPED | MetaFont.ETO_OPAQUE)) != 0) { 457 x1 = in.readShort(); 458 y1 = in.readShort(); 459 x2 = in.readShort(); 460 y2 = in.readShort(); 461 } 462 byte text[] = new byte[count]; 463 int k; 464 for (k = 0; k < count; ++k) { 465 byte c = (byte)in.readByte(); 466 if (c == 0) 467 break; 468 text[k] = c; 469 } 470 String s; 471 try { 472 s = new String(text, 0, k, "Cp1252"); 473 } 474 catch (UnsupportedEncodingException e) { 475 s = new String(text, 0, k); 476 } 477 outputText(x, y, flag, x1, y1, x2, y2, s); 478 break; 479 } 480 case META_TEXTOUT: 481 { 482 int count = in.readWord(); 483 byte text[] = new byte[count]; 484 int k; 485 for (k = 0; k < count; ++k) { 486 byte c = (byte)in.readByte(); 487 if (c == 0) 488 break; 489 text[k] = c; 490 } 491 String s; 492 try { 493 s = new String(text, 0, k, "Cp1252"); 494 } 495 catch (UnsupportedEncodingException e) { 496 s = new String(text, 0, k); 497 } 498 count = count + 1 & 0xfffe; 499 in.skip(count - k); 500 int y = in.readShort(); 501 int x = in.readShort(); 502 outputText(x, y, 0, 0, 0, 0, 0, s); 503 break; 504 } 505 case META_SETBKCOLOR: 506 state.setCurrentBackgroundColor(in.readColor()); 507 break; 508 case META_SETTEXTCOLOR: 509 state.setCurrentTextColor(in.readColor()); 510 break; 511 case META_SETTEXTALIGN: 512 state.setTextAlign(in.readWord()); 513 break; 514 case META_SETBKMODE: 515 state.setBackgroundMode(in.readWord()); 516 break; 517 case META_SETPOLYFILLMODE: 518 state.setPolyFillMode(in.readWord()); 519 break; 520 case META_SETPIXEL: 521 { 522 BaseColor color = in.readColor(); 523 int y = in.readShort(); 524 int x = in.readShort(); 525 cb.saveState(); 526 cb.setColorFill(color); 527 cb.rectangle(state.transformX(x), state.transformY(y), .2f, .2f); 528 cb.fill(); 529 cb.restoreState(); 530 break; 531 } 532 case META_DIBSTRETCHBLT: 533 case META_STRETCHDIB: { 534 int rop = in.readInt(); 535 if (function == META_STRETCHDIB) { 536 /*int usage = */ in.readWord(); 537 } 538 int srcHeight = in.readShort(); 539 int srcWidth = in.readShort(); 540 int ySrc = in.readShort(); 541 int xSrc = in.readShort(); 542 float destHeight = state.transformY(in.readShort()) - state.transformY(0); 543 float destWidth = state.transformX(in.readShort()) - state.transformX(0); 544 float yDest = state.transformY(in.readShort()); 545 float xDest = state.transformX(in.readShort()); 546 byte b[] = new byte[tsize * 2 - (in.getLength() - lenMarker)]; 547 for (int k = 0; k < b.length; ++k) 548 b[k] = (byte)in.readByte(); 549 try { 550 ByteArrayInputStream inb = new ByteArrayInputStream(b); 551 Image bmp = BmpImage.getImage(inb, true, b.length); 552 cb.saveState(); 553 cb.rectangle(xDest, yDest, destWidth, destHeight); 554 cb.clip(); 555 cb.newPath(); 556 bmp.scaleAbsolute(destWidth * bmp.getWidth() / srcWidth, -destHeight * bmp.getHeight() / srcHeight); 557 bmp.setAbsolutePosition(xDest - destWidth * xSrc / srcWidth, yDest + destHeight * ySrc / srcHeight - bmp.getScaledHeight()); 558 cb.addImage(bmp); 559 cb.restoreState(); 560 } 561 catch (Exception e) { 562 // empty on purpose 563 } 564 break; 565 } 566 } 567 in.skip(tsize * 2 - (in.getLength() - lenMarker)); 568 } 569 state.cleanup(cb); 570 } 571 572 public void outputText(int x, int y, int flag, int x1, int y1, int x2, int y2, String text) { 573 MetaFont font = state.getCurrentFont(); 574 float refX = state.transformX(x); 575 float refY = state.transformY(y); 576 float angle = state.transformAngle(font.getAngle()); 577 float sin = (float)Math.sin(angle); 578 float cos = (float)Math.cos(angle); 579 float fontSize = font.getFontSize(state); 580 BaseFont bf = font.getFont(); 581 int align = state.getTextAlign(); 582 float textWidth = bf.getWidthPoint(text, fontSize); 583 float tx = 0; 584 float ty = 0; 585 float descender = bf.getFontDescriptor(BaseFont.DESCENT, fontSize); 586 float ury = bf.getFontDescriptor(BaseFont.BBOXURY, fontSize); 587 cb.saveState(); 588 cb.concatCTM(cos, sin, -sin, cos, refX, refY); 589 if ((align & MetaState.TA_CENTER) == MetaState.TA_CENTER) 590 tx = -textWidth / 2; 591 else if ((align & MetaState.TA_RIGHT) == MetaState.TA_RIGHT) 592 tx = -textWidth; 593 if ((align & MetaState.TA_BASELINE) == MetaState.TA_BASELINE) 594 ty = 0; 595 else if ((align & MetaState.TA_BOTTOM) == MetaState.TA_BOTTOM) 596 ty = -descender; 597 else 598 ty = -ury; 599 BaseColor textColor; 600 if (state.getBackgroundMode() == MetaState.OPAQUE) { 601 textColor = state.getCurrentBackgroundColor(); 602 cb.setColorFill(textColor); 603 cb.rectangle(tx, ty + descender, textWidth, ury - descender); 604 cb.fill(); 605 } 606 textColor = state.getCurrentTextColor(); 607 cb.setColorFill(textColor); 608 cb.beginText(); 609 cb.setFontAndSize(bf, fontSize); 610 cb.setTextMatrix(tx, ty); 611 cb.showText(text); 612 cb.endText(); 613 if (font.isUnderline()) { 614 cb.rectangle(tx, ty - fontSize / 4, textWidth, fontSize / 15); 615 cb.fill(); 616 } 617 if (font.isStrikeout()) { 618 cb.rectangle(tx, ty + fontSize / 3, textWidth, fontSize / 15); 619 cb.fill(); 620 } 621 cb.restoreState(); 622 } 623 624 public boolean isNullStrokeFill(boolean isRectangle) { 625 MetaPen pen = state.getCurrentPen(); 626 MetaBrush brush = state.getCurrentBrush(); 627 boolean noPen = pen.getStyle() == MetaPen.PS_NULL; 628 int style = brush.getStyle(); 629 boolean isBrush = style == MetaBrush.BS_SOLID || style == MetaBrush.BS_HATCHED && state.getBackgroundMode() == MetaState.OPAQUE; 630 boolean result = noPen && !isBrush; 631 if (!noPen) { 632 if (isRectangle) 633 state.setLineJoinRectangle(cb); 634 else 635 state.setLineJoinPolygon(cb); 636 } 637 return result; 638 } 639 640 public void strokeAndFill(){ 641 MetaPen pen = state.getCurrentPen(); 642 MetaBrush brush = state.getCurrentBrush(); 643 int penStyle = pen.getStyle(); 644 int brushStyle = brush.getStyle(); 645 if (penStyle == MetaPen.PS_NULL) { 646 cb.closePath(); 647 if (state.getPolyFillMode() == MetaState.ALTERNATE) { 648 cb.eoFill(); 649 } 650 else { 651 cb.fill(); 652 } 653 } 654 else { 655 boolean isBrush = brushStyle == MetaBrush.BS_SOLID || brushStyle == MetaBrush.BS_HATCHED && state.getBackgroundMode() == MetaState.OPAQUE; 656 if (isBrush) { 657 if (state.getPolyFillMode() == MetaState.ALTERNATE) 658 cb.closePathEoFillStroke(); 659 else 660 cb.closePathFillStroke(); 661 } 662 else { 663 cb.closePathStroke(); 664 } 665 } 666 } 667 668 static float getArc(float xCenter, float yCenter, float xDot, float yDot) { 669 double s = Math.atan2(yDot - yCenter, xDot - xCenter); 670 if (s < 0) 671 s += Math.PI * 2; 672 return (float)(s / Math.PI * 180); 673 } 674 675 public static byte[] wrapBMP(Image image) throws IOException { 676 if (image.getOriginalType() != Image.ORIGINAL_BMP) 677 throw new IOException(MessageLocalization.getComposedMessage("only.bmp.can.be.wrapped.in.wmf")); 678 InputStream imgIn; 679 byte data[] = null; 680 if (image.getOriginalData() == null) { 681 imgIn = image.getUrl().openStream(); 682 ByteArrayOutputStream out = new ByteArrayOutputStream(); 683 int b = 0; 684 while ((b = imgIn.read()) != -1) 685 out.write(b); 686 imgIn.close(); 687 data = out.toByteArray(); 688 } 689 else 690 data = image.getOriginalData(); 691 int sizeBmpWords = data.length - 14 + 1 >>> 1; 692 ByteArrayOutputStream os = new ByteArrayOutputStream(); 693 // write metafile header 694 writeWord(os, 1); 695 writeWord(os, 9); 696 writeWord(os, 0x0300); 697 writeDWord(os, 9 + 4 + 5 + 5 + 13 + sizeBmpWords + 3); // total metafile size 698 writeWord(os, 1); 699 writeDWord(os, 14 + sizeBmpWords); // max record size 700 writeWord(os, 0); 701 // write records 702 writeDWord(os, 4); 703 writeWord(os, META_SETMAPMODE); 704 writeWord(os, 8); 705 706 writeDWord(os, 5); 707 writeWord(os, META_SETWINDOWORG); 708 writeWord(os, 0); 709 writeWord(os, 0); 710 711 writeDWord(os, 5); 712 writeWord(os, META_SETWINDOWEXT); 713 writeWord(os, (int)image.getHeight()); 714 writeWord(os, (int)image.getWidth()); 715 716 writeDWord(os, 13 + sizeBmpWords); 717 writeWord(os, META_DIBSTRETCHBLT); 718 writeDWord(os, 0x00cc0020); 719 writeWord(os, (int)image.getHeight()); 720 writeWord(os, (int)image.getWidth()); 721 writeWord(os, 0); 722 writeWord(os, 0); 723 writeWord(os, (int)image.getHeight()); 724 writeWord(os, (int)image.getWidth()); 725 writeWord(os, 0); 726 writeWord(os, 0); 727 os.write(data, 14, data.length - 14); 728 if ((data.length & 1) == 1) 729 os.write(0); 730// writeDWord(os, 14 + sizeBmpWords); 731// writeWord(os, META_STRETCHDIB); 732// writeDWord(os, 0x00cc0020); 733// writeWord(os, 0); 734// writeWord(os, (int)image.height()); 735// writeWord(os, (int)image.width()); 736// writeWord(os, 0); 737// writeWord(os, 0); 738// writeWord(os, (int)image.height()); 739// writeWord(os, (int)image.width()); 740// writeWord(os, 0); 741// writeWord(os, 0); 742// os.write(data, 14, data.length - 14); 743// if ((data.length & 1) == 1) 744// os.write(0); 745 746 writeDWord(os, 3); 747 writeWord(os, 0); 748 os.close(); 749 return os.toByteArray(); 750 } 751 752 public static void writeWord(OutputStream os, int v) throws IOException { 753 os.write(v & 0xff); 754 os.write(v >>> 8 & 0xff); 755 } 756 757 public static void writeDWord(OutputStream os, int v) throws IOException { 758 writeWord(os, v & 0xffff); 759 writeWord(os, v >>> 16 & 0xffff); 760 } 761}