You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

HwmfFill.java 26KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760
  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. http://www.apache.org/licenses/LICENSE-2.0
  9. Unless required by applicable law or agreed to in writing, software
  10. distributed under the License is distributed on an "AS IS" BASIS,
  11. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. See the License for the specific language governing permissions and
  13. limitations under the License.
  14. ==================================================================== */
  15. package org.apache.poi.hwmf.record;
  16. import static org.apache.poi.hwmf.record.HwmfDraw.boundsToString;
  17. import static org.apache.poi.hwmf.record.HwmfDraw.readPointS;
  18. import java.awt.Shape;
  19. import java.awt.geom.Path2D;
  20. import java.awt.geom.Point2D;
  21. import java.awt.geom.Rectangle2D;
  22. import java.awt.image.BufferedImage;
  23. import java.io.IOException;
  24. import org.apache.poi.hwmf.draw.HwmfDrawProperties;
  25. import org.apache.poi.hwmf.draw.HwmfGraphics;
  26. import org.apache.poi.util.LittleEndianConsts;
  27. import org.apache.poi.util.LittleEndianInputStream;
  28. public class HwmfFill {
  29. /**
  30. * A record which contains an image (to be extracted)
  31. */
  32. public interface HwmfImageRecord {
  33. BufferedImage getImage();
  34. }
  35. /**
  36. * The ColorUsage Enumeration (a 16-bit unsigned integer) specifies whether a color table
  37. * exists in a device-independent bitmap (DIB) and how to interpret its values,
  38. * i.e. if contains explicit RGB values or indexes into a palette.
  39. */
  40. public enum ColorUsage {
  41. /**
  42. * The color table contains RGB values
  43. */
  44. DIB_RGB_COLORS(0x0000),
  45. /**
  46. * The color table contains 16-bit indices into the current logical palette in
  47. * the playback device context.
  48. */
  49. DIB_PAL_COLORS(0x0001),
  50. /**
  51. * No color table exists. The pixels in the DIB are indices into the current
  52. * logical palette in the playback device context.
  53. */
  54. DIB_PAL_INDICES(0x0002)
  55. ;
  56. public final int flag;
  57. ColorUsage(int flag) {
  58. this.flag = flag;
  59. }
  60. public static ColorUsage valueOf(int flag) {
  61. for (ColorUsage bs : values()) {
  62. if (bs.flag == flag) return bs;
  63. }
  64. return null;
  65. }
  66. }
  67. /**
  68. * The META_FILLREGION record fills a region using a specified brush.
  69. */
  70. public static class WmfFillRegion implements HwmfRecord {
  71. /**
  72. * A 16-bit unsigned integer used to index into the WMF Object Table to get
  73. * the region to be filled.
  74. */
  75. protected int regionIndex;
  76. /**
  77. * A 16-bit unsigned integer used to index into the WMF Object Table to get the
  78. * brush to use for filling the region.
  79. */
  80. protected int brushIndex;
  81. @Override
  82. public HwmfRecordType getWmfRecordType() {
  83. return HwmfRecordType.fillRegion;
  84. }
  85. @Override
  86. public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
  87. regionIndex = leis.readUShort();
  88. brushIndex = leis.readUShort();
  89. return 2*LittleEndianConsts.SHORT_SIZE;
  90. }
  91. @Override
  92. public void draw(HwmfGraphics ctx) {
  93. ctx.applyObjectTableEntry(regionIndex);
  94. ctx.applyObjectTableEntry(brushIndex);
  95. Shape region = ctx.getProperties().getRegion();
  96. if (region != null) {
  97. ctx.fill(region);
  98. }
  99. }
  100. }
  101. /**
  102. * The META_PAINTREGION record paints the specified region by using the brush that is
  103. * defined in the playback device context.
  104. */
  105. public static class WmfPaintRegion implements HwmfRecord {
  106. /**
  107. * A 16-bit unsigned integer used to index into the WMF Object Table to get
  108. * the region to be painted.
  109. */
  110. int regionIndex;
  111. public HwmfRecordType getWmfRecordType() {
  112. return HwmfRecordType.paintRegion;
  113. }
  114. public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
  115. regionIndex = leis.readUShort();
  116. return LittleEndianConsts.SHORT_SIZE;
  117. }
  118. @Override
  119. public void draw(HwmfGraphics ctx) {
  120. ctx.applyObjectTableEntry(regionIndex);
  121. Shape region = ctx.getProperties().getRegion();
  122. if (region != null) {
  123. ctx.fill(region);
  124. }
  125. }
  126. }
  127. /**
  128. * The META_FLOODFILL record fills an area of the output surface with the brush that
  129. * is defined in the playback device context.
  130. */
  131. public static class WmfFloodFill implements HwmfRecord {
  132. /**
  133. * A 32-bit ColorRef Object that defines the color value.
  134. */
  135. protected final HwmfColorRef colorRef = new HwmfColorRef();
  136. /** the point where filling is to start. */
  137. protected final Point2D start = new Point2D.Double();
  138. @Override
  139. public HwmfRecordType getWmfRecordType() {
  140. return HwmfRecordType.floodFill;
  141. }
  142. @Override
  143. public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
  144. int size = colorRef.init(leis);
  145. size += readPointS(leis, start);
  146. return size;
  147. }
  148. @Override
  149. public void draw(HwmfGraphics ctx) {
  150. }
  151. }
  152. /**
  153. * The META_SETPOLYFILLMODE record sets polygon fill mode in the playback device context for
  154. * graphics operations that fill polygons.
  155. */
  156. public static class WmfSetPolyfillMode implements HwmfRecord {
  157. /**
  158. * A 16-bit unsigned integer that defines polygon fill mode.
  159. * This MUST be one of the values: ALTERNATE = 0x0001, WINDING = 0x0002
  160. */
  161. public enum HwmfPolyfillMode {
  162. /**
  163. * Selects alternate mode (fills the area between odd-numbered and
  164. * even-numbered polygon sides on each scan line).
  165. */
  166. ALTERNATE(0x0001, Path2D.WIND_EVEN_ODD),
  167. /**
  168. * Selects winding mode (fills any region with a nonzero winding value).
  169. */
  170. WINDING(0x0002, Path2D.WIND_NON_ZERO);
  171. public final int wmfFlag;
  172. public final int awtFlag;
  173. HwmfPolyfillMode(int wmfFlag, int awtFlag) {
  174. this.wmfFlag = wmfFlag;
  175. this.awtFlag = awtFlag;
  176. }
  177. public static HwmfPolyfillMode valueOf(int wmfFlag) {
  178. for (HwmfPolyfillMode pm : values()) {
  179. if (pm.wmfFlag == wmfFlag) return pm;
  180. }
  181. return null;
  182. }
  183. }
  184. /**
  185. * An unsigned integer that defines polygon fill mode.
  186. * This MUST be one of the values: ALTERNATE = 0x0001, WINDING = 0x0002
  187. */
  188. protected HwmfPolyfillMode polyFillMode;
  189. @Override
  190. public HwmfRecordType getWmfRecordType() {
  191. return HwmfRecordType.setPolyFillMode;
  192. }
  193. @Override
  194. public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
  195. polyFillMode = HwmfPolyfillMode.valueOf(leis.readUShort() & 3);
  196. return LittleEndianConsts.SHORT_SIZE;
  197. }
  198. @Override
  199. public void draw(HwmfGraphics ctx) {
  200. ctx.getProperties().setPolyfillMode(polyFillMode);
  201. }
  202. @Override
  203. public String toString() {
  204. return "{ polyFillMode: '"+ polyFillMode +"' }";
  205. }
  206. }
  207. /**
  208. * The META_EXTFLOODFILL record fills an area with the brush that is defined in
  209. * the playback device context.
  210. */
  211. public static class WmfExtFloodFill extends WmfFloodFill {
  212. /**
  213. * A 16-bit unsigned integer that defines the fill operation to be performed. This
  214. * member MUST be one of the values in the FloodFill Enumeration table:
  215. *
  216. * FLOODFILLBORDER = 0x0000:
  217. * The fill area is bounded by the color specified by the Color member.
  218. * This style is identical to the filling performed by the META_FLOODFILL record.
  219. *
  220. * FLOODFILLSURFACE = 0x0001:
  221. * The fill area is bounded by the color that is specified by the Color member.
  222. * Filling continues outward in all directions as long as the color is encountered.
  223. * This style is useful for filling areas with multicolored boundaries.
  224. */
  225. protected int mode;
  226. @Override
  227. public HwmfRecordType getWmfRecordType() {
  228. return HwmfRecordType.extFloodFill;
  229. }
  230. @Override
  231. public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
  232. mode = leis.readUShort();
  233. return super.init(leis, recordSize, recordFunction)+LittleEndianConsts.SHORT_SIZE;
  234. }
  235. @Override
  236. public void draw(HwmfGraphics ctx) {
  237. }
  238. }
  239. /**
  240. * The META_INVERTREGION record draws a region in which the colors are inverted.
  241. */
  242. public static class WmfInvertRegion implements HwmfRecord {
  243. /**
  244. * A 16-bit unsigned integer used to index into the WMF Object Table to get
  245. * the region to be inverted.
  246. */
  247. private int region;
  248. @Override
  249. public HwmfRecordType getWmfRecordType() {
  250. return HwmfRecordType.invertRegion;
  251. }
  252. @Override
  253. public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
  254. region = leis.readUShort();
  255. return LittleEndianConsts.SHORT_SIZE;
  256. }
  257. @Override
  258. public void draw(HwmfGraphics ctx) {
  259. }
  260. }
  261. /**
  262. * The META_PATBLT record paints a specified rectangle using the brush that is defined in the playback
  263. * device context. The brush color and the surface color or colors are combined using the specified
  264. * raster operation.
  265. */
  266. public static class WmfPatBlt implements HwmfRecord {
  267. /**
  268. * A 32-bit unsigned integer that defines the raster operation code.
  269. * This code MUST be one of the values in the Ternary Raster Operation enumeration table.
  270. */
  271. private HwmfTernaryRasterOp rasterOperation;
  272. private final Rectangle2D bounds = new Rectangle2D.Double();
  273. @Override
  274. public HwmfRecordType getWmfRecordType() {
  275. return HwmfRecordType.patBlt;
  276. }
  277. @Override
  278. public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
  279. int rasterOpCode = leis.readUShort();
  280. int rasterOpIndex = leis.readUShort();
  281. rasterOperation = HwmfTernaryRasterOp.valueOf(rasterOpIndex);
  282. assert(rasterOpCode == rasterOperation.opCode);
  283. return readBounds2(leis, bounds)+2*LittleEndianConsts.SHORT_SIZE;
  284. }
  285. @Override
  286. public void draw(HwmfGraphics ctx) {
  287. }
  288. }
  289. /**
  290. * The META_STRETCHBLT record specifies the transfer of a block of pixels according to a raster
  291. * operation, with possible expansion or contraction.
  292. * The destination of the transfer is the current output region in the playback device context.
  293. * There are two forms of META_STRETCHBLT, one which specifies a bitmap as the source, and the other
  294. * which uses the playback device context as the source. Definitions follow for the fields that are the
  295. * same in the two forms of META_STRETCHBLT are defined below. The subsections that follow specify
  296. * the packet structures of the two forms of META_STRETCHBLT.
  297. * The expansion or contraction is performed according to the stretching mode currently set in the
  298. * playback device context, which MUST be a value from the StretchMode.
  299. */
  300. public static class WmfStretchBlt implements HwmfRecord {
  301. /**
  302. * A 32-bit unsigned integer that defines how the source pixels, the current brush
  303. * in the playback device context, and the destination pixels are to be combined to form the new
  304. * image. This code MUST be one of the values in the Ternary Raster Operation Enumeration
  305. */
  306. protected HwmfTernaryRasterOp rasterOperation;
  307. /** the source rectangle */
  308. protected final Rectangle2D srcBounds = new Rectangle2D.Double();
  309. /** the destination rectangle */
  310. protected final Rectangle2D dstBounds = new Rectangle2D.Double();
  311. /**
  312. * A variable-sized Bitmap16 Object that defines source image content.
  313. * This object MUST be specified, even if the raster operation does not require a source.
  314. */
  315. protected HwmfBitmap16 target;
  316. @Override
  317. public HwmfRecordType getWmfRecordType() {
  318. return HwmfRecordType.stretchBlt;
  319. }
  320. @Override
  321. public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
  322. boolean hasBitmap = (recordSize > ((recordFunction >> 8) + 3));
  323. int rasterOpCode = leis.readUShort();
  324. int rasterOpIndex = leis.readUShort();
  325. rasterOperation = HwmfTernaryRasterOp.valueOf(rasterOpIndex);
  326. assert(rasterOpCode == rasterOperation.opCode);
  327. int size = 2*LittleEndianConsts.SHORT_SIZE;
  328. size += readBounds2(leis, srcBounds);
  329. if (!hasBitmap) {
  330. /*int reserved =*/ leis.readShort();
  331. size += LittleEndianConsts.SHORT_SIZE;
  332. }
  333. size += readBounds2(leis, dstBounds);
  334. if (hasBitmap) {
  335. target = new HwmfBitmap16();
  336. size += target.init(leis);
  337. }
  338. return size;
  339. }
  340. @Override
  341. public void draw(HwmfGraphics ctx) {
  342. }
  343. @Override
  344. public String toString() {
  345. return
  346. "{ rasterOperation: '"+rasterOperation+"'"+
  347. ", srcBounds: "+boundsToString(srcBounds)+
  348. ", dstBounds: "+boundsToString(dstBounds)+
  349. "}";
  350. }
  351. }
  352. /**
  353. * The META_STRETCHDIB record specifies the transfer of color data from a
  354. * block of pixels in device independent format according to a raster operation,
  355. * with possible expansion or contraction.
  356. * The source of the color data is a DIB, and the destination of the transfer is
  357. * the current output region in the playback device context.
  358. */
  359. public static class WmfStretchDib implements HwmfRecord, HwmfImageRecord {
  360. /**
  361. * A 32-bit unsigned integer that defines how the source pixels, the current brush in
  362. * the playback device context, and the destination pixels are to be combined to
  363. * form the new image.
  364. */
  365. protected HwmfTernaryRasterOp rasterOperation;
  366. /**
  367. * A 16-bit unsigned integer that defines whether the Colors field of the
  368. * DIB contains explicit RGB values or indexes into a palette.
  369. */
  370. protected ColorUsage colorUsage;
  371. /** the source rectangle. */
  372. protected final Rectangle2D srcBounds = new Rectangle2D.Double();
  373. /** the destination rectangle. */
  374. protected final Rectangle2D dstBounds = new Rectangle2D.Double();
  375. /**
  376. * A variable-sized DeviceIndependentBitmap Object (section 2.2.2.9) that is the
  377. * source of the color data.
  378. */
  379. protected final HwmfBitmapDib bitmap = new HwmfBitmapDib();
  380. @Override
  381. public HwmfRecordType getWmfRecordType() {
  382. return HwmfRecordType.stretchDib;
  383. }
  384. @Override
  385. public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
  386. int rasterOpCode = leis.readUShort();
  387. int rasterOpIndex = leis.readUShort();
  388. rasterOperation = HwmfTernaryRasterOp.valueOf(rasterOpIndex);
  389. assert(rasterOpCode == rasterOperation.opCode);
  390. colorUsage = ColorUsage.valueOf(leis.readUShort());
  391. int size = 3*LittleEndianConsts.SHORT_SIZE;
  392. size += readBounds2(leis, srcBounds);
  393. size += readBounds2(leis, dstBounds);
  394. size += bitmap.init(leis, (int)(recordSize-6-size));
  395. return size;
  396. }
  397. @Override
  398. public void draw(HwmfGraphics ctx) {
  399. HwmfDrawProperties prop = ctx.getProperties();
  400. prop.setRasterOp(rasterOperation);
  401. if (bitmap.isValid()) {
  402. ctx.drawImage(getImage(), srcBounds, dstBounds);
  403. } else if (!dstBounds.isEmpty()) {
  404. BufferedImage bi = new BufferedImage(100, 100, BufferedImage.TYPE_INT_ARGB);
  405. ctx.drawImage(bi, new Rectangle2D.Double(0,0,100,100), dstBounds);
  406. }
  407. }
  408. @Override
  409. public BufferedImage getImage() {
  410. return bitmap.getImage();
  411. }
  412. @Override
  413. public String toString() {
  414. return
  415. "{ rasterOperation: '"+rasterOperation+"'"+
  416. ", colorUsage: '"+colorUsage+"'"+
  417. ", srcBounds: "+boundsToString(srcBounds)+
  418. ", dstBounds: "+boundsToString(dstBounds)+
  419. "}";
  420. }
  421. }
  422. public static class WmfBitBlt extends WmfStretchBlt {
  423. @Override
  424. public HwmfRecordType getWmfRecordType() {
  425. return HwmfRecordType.bitBlt;
  426. }
  427. @Override
  428. public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
  429. boolean hasBitmap = (recordSize/2 != ((recordFunction >> 8) + 3));
  430. int rasterOpCode = leis.readUShort();
  431. int rasterOpIndex = leis.readUShort();
  432. rasterOperation = HwmfTernaryRasterOp.valueOf(rasterOpIndex);
  433. assert(rasterOpCode == rasterOperation.opCode);
  434. int size = 2*LittleEndianConsts.SHORT_SIZE;
  435. final Point2D srcPnt = new Point2D.Double();
  436. size += readPointS(leis, srcPnt);
  437. if (!hasBitmap) {
  438. /*int reserved =*/ leis.readShort();
  439. size += LittleEndianConsts.SHORT_SIZE;
  440. }
  441. size += readBounds2(leis, dstBounds);
  442. if (hasBitmap) {
  443. target = new HwmfBitmap16();
  444. size += target.init(leis);
  445. }
  446. srcBounds.setRect(srcPnt.getX(), srcPnt.getY(), dstBounds.getWidth(), dstBounds.getHeight());
  447. return size;
  448. }
  449. }
  450. /**
  451. * The META_SETDIBTODEV record sets a block of pixels in the playback device context
  452. * using deviceindependent color data.
  453. * The source of the color data is a DIB
  454. */
  455. public static class WmfSetDibToDev implements HwmfRecord, HwmfImageRecord, HwmfObjectTableEntry {
  456. /**
  457. * A 16-bit unsigned integer that defines whether the Colors field of the
  458. * DIB contains explicit RGB values or indexes into a palette.
  459. */
  460. private ColorUsage colorUsage;
  461. /**
  462. * A 16-bit unsigned integer that defines the number of scan lines in the source.
  463. */
  464. private int scanCount;
  465. /**
  466. * A 16-bit unsigned integer that defines the starting scan line in the source.
  467. */
  468. private int startScan;
  469. /** the source rectangle */
  470. protected final Rectangle2D srcBounds = new Rectangle2D.Double();
  471. /** the destination rectangle, having the same dimension as the source rectangle */
  472. protected final Rectangle2D dstBounds = new Rectangle2D.Double();
  473. /**
  474. * A variable-sized DeviceIndependentBitmap Object that is the source of the color data.
  475. */
  476. private HwmfBitmapDib dib;
  477. @Override
  478. public HwmfRecordType getWmfRecordType() {
  479. return HwmfRecordType.setDibToDev;
  480. }
  481. @Override
  482. public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
  483. colorUsage = ColorUsage.valueOf(leis.readUShort());
  484. scanCount = leis.readUShort();
  485. startScan = leis.readUShort();
  486. int size = 3*LittleEndianConsts.SHORT_SIZE;
  487. final Point2D srcPnt = new Point2D.Double();
  488. size += readPointS(leis, srcPnt);
  489. size += readBounds2(leis, dstBounds);
  490. dib = new HwmfBitmapDib();
  491. size += dib.init(leis, (int)(recordSize-6-size));
  492. srcBounds.setRect(srcPnt.getX(), srcPnt.getY(), dstBounds.getWidth(), dstBounds.getHeight());
  493. return size;
  494. }
  495. @Override
  496. public void draw(HwmfGraphics ctx) {
  497. ctx.addObjectTableEntry(this);
  498. }
  499. @Override
  500. public void applyObject(HwmfGraphics ctx) {
  501. }
  502. @Override
  503. public BufferedImage getImage() {
  504. return dib.getImage();
  505. }
  506. }
  507. public static class WmfDibBitBlt extends WmfDibStretchBlt {
  508. @Override
  509. public HwmfRecordType getWmfRecordType() {
  510. return HwmfRecordType.dibBitBlt;
  511. }
  512. @Override
  513. public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
  514. boolean hasBitmap = (recordSize/2 != ((recordFunction >> 8) + 3));
  515. int rasterOpCode = leis.readUShort();
  516. int rasterOpIndex = leis.readUShort();
  517. rasterOperation = HwmfTernaryRasterOp.valueOf(rasterOpIndex);
  518. assert(rasterOpCode == rasterOperation.opCode);
  519. int size = 2*LittleEndianConsts.SHORT_SIZE;
  520. final Point2D srcPnt = new Point2D.Double();
  521. size += readPointS(leis, srcPnt);
  522. if (!hasBitmap) {
  523. /*int reserved =*/ leis.readShort();
  524. size += LittleEndianConsts.SHORT_SIZE;
  525. }
  526. size += readBounds2(leis, dstBounds);
  527. if (hasBitmap) {
  528. target = new HwmfBitmapDib();
  529. size += target.init(leis, (int)(recordSize-6-size));
  530. }
  531. // the destination rectangle, having the same dimension as the source rectangle
  532. srcBounds.setRect(srcPnt.getX(), srcPnt.getY(), dstBounds.getWidth(), dstBounds.getHeight());
  533. return size;
  534. }
  535. }
  536. public static class WmfDibStretchBlt implements HwmfRecord, HwmfImageRecord, HwmfObjectTableEntry {
  537. /**
  538. * A 32-bit unsigned integer that defines how the source pixels, the current brush
  539. * in the playback device context, and the destination pixels are to be combined to form the
  540. * new image. This code MUST be one of the values in the Ternary Raster Operation Enumeration.
  541. */
  542. protected HwmfTernaryRasterOp rasterOperation;
  543. /** the source rectangle */
  544. protected final Rectangle2D srcBounds = new Rectangle2D.Double();
  545. /** the destination rectangle */
  546. protected final Rectangle2D dstBounds = new Rectangle2D.Double();
  547. /**
  548. * A variable-sized DeviceIndependentBitmap Object that defines image content.
  549. * This object MUST be specified, even if the raster operation does not require a source.
  550. */
  551. protected HwmfBitmapDib target;
  552. @Override
  553. public HwmfRecordType getWmfRecordType() {
  554. return HwmfRecordType.dibStretchBlt;
  555. }
  556. @Override
  557. public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
  558. boolean hasBitmap = (recordSize > ((recordFunction >> 8) + 3));
  559. int rasterOpCode = leis.readUShort();
  560. int rasterOpIndex = leis.readUShort();
  561. rasterOperation = HwmfTernaryRasterOp.valueOf(rasterOpIndex);
  562. assert(rasterOpCode == rasterOperation.opCode);
  563. int size = 2*LittleEndianConsts.SHORT_SIZE;
  564. size += readBounds2(leis, srcBounds);
  565. if (!hasBitmap) {
  566. /*int reserved =*/ leis.readShort();
  567. size += LittleEndianConsts.SHORT_SIZE;
  568. }
  569. size += readBounds2(leis, dstBounds);
  570. if (hasBitmap) {
  571. target = new HwmfBitmapDib();
  572. size += target.init(leis, (int)(recordSize-6-size));
  573. }
  574. return size;
  575. }
  576. @Override
  577. public void draw(HwmfGraphics ctx) {
  578. ctx.addObjectTableEntry(this);
  579. }
  580. @Override
  581. public void applyObject(HwmfGraphics ctx) {
  582. }
  583. @Override
  584. public BufferedImage getImage() {
  585. return (target != null && target.isValid()) ? target.getImage() : null;
  586. }
  587. }
  588. static int readBounds2(LittleEndianInputStream leis, Rectangle2D bounds) {
  589. /**
  590. * The 16-bit signed integers that defines the corners of the bounding rectangle.
  591. */
  592. int h = leis.readShort();
  593. int w = leis.readShort();
  594. int y = leis.readShort();
  595. int x = leis.readShort();
  596. bounds.setRect(x, y, w, h);
  597. return 4 * LittleEndianConsts.SHORT_SIZE;
  598. }
  599. }