PageRenderTime 60ms CodeModel.GetById 22ms RepoModel.GetById 1ms app.codeStats 0ms

/src/share/classes/com/sun/imageio/plugins/bmp/BMPImageReader.java

https://bitbucket.org/infinitekind/openjdk7u-jdk
Java | 1821 lines | 1383 code | 267 blank | 171 comment | 328 complexity | 04f154ffd4bb4090cbe68e473914bacd MD5 | raw file
Possible License(s): GPL-2.0, BSD-3-Clause-No-Nuclear-License-2014, LGPL-3.0
  1. /*
  2. * Copyright (c) 2003, 2005, Oracle and/or its affiliates. All rights reserved.
  3. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4. *
  5. * This code is free software; you can redistribute it and/or modify it
  6. * under the terms of the GNU General Public License version 2 only, as
  7. * published by the Free Software Foundation. Oracle designates this
  8. * particular file as subject to the "Classpath" exception as provided
  9. * by Oracle in the LICENSE file that accompanied this code.
  10. *
  11. * This code is distributed in the hope that it will be useful, but WITHOUT
  12. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13. * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
  14. * version 2 for more details (a copy is included in the LICENSE file that
  15. * accompanied this code).
  16. *
  17. * You should have received a copy of the GNU General Public License version
  18. * 2 along with this work; if not, write to the Free Software Foundation,
  19. * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20. *
  21. * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22. * or visit www.oracle.com if you need additional information or have any
  23. * questions.
  24. */
  25. package com.sun.imageio.plugins.bmp;
  26. import java.awt.Point;
  27. import java.awt.Rectangle;
  28. import java.awt.Transparency;
  29. import java.awt.color.ColorSpace;
  30. import java.awt.color.ICC_ColorSpace;
  31. import java.awt.color.ICC_Profile;
  32. import java.awt.image.BufferedImage;
  33. import java.awt.image.ColorModel;
  34. import java.awt.image.ComponentColorModel;
  35. import java.awt.image.ComponentSampleModel;
  36. import java.awt.image.DataBuffer;
  37. import java.awt.image.DataBufferByte;
  38. import java.awt.image.DataBufferInt;
  39. import java.awt.image.DataBufferUShort;
  40. import java.awt.image.DirectColorModel;
  41. import java.awt.image.IndexColorModel;
  42. import java.awt.image.MultiPixelPackedSampleModel;
  43. import java.awt.image.PixelInterleavedSampleModel;
  44. import java.awt.image.Raster;
  45. import java.awt.image.SampleModel;
  46. import java.awt.image.SinglePixelPackedSampleModel;
  47. import java.awt.image.WritableRaster;
  48. import javax.imageio.IIOException;
  49. import javax.imageio.ImageIO;
  50. import javax.imageio.ImageReader;
  51. import javax.imageio.ImageReadParam;
  52. import javax.imageio.ImageTypeSpecifier;
  53. import javax.imageio.metadata.IIOMetadata;
  54. import javax.imageio.spi.ImageReaderSpi;
  55. import javax.imageio.stream.ImageInputStream;
  56. import javax.imageio.event.IIOReadProgressListener;
  57. import javax.imageio.event.IIOReadUpdateListener;
  58. import javax.imageio.event.IIOReadWarningListener;
  59. import java.io.*;
  60. import java.nio.*;
  61. import java.security.AccessController;
  62. import java.security.PrivilegedAction;
  63. import java.util.ArrayList;
  64. import java.util.Iterator;
  65. import java.util.StringTokenizer;
  66. import com.sun.imageio.plugins.common.ImageUtil;
  67. import com.sun.imageio.plugins.common.I18N;
  68. /** This class is the Java Image IO plugin reader for BMP images.
  69. * It may subsample the image, clip the image, select sub-bands,
  70. * and shift the decoded image origin if the proper decoding parameter
  71. * are set in the provided <code>ImageReadParam</code>.
  72. *
  73. * This class supports Microsoft Windows Bitmap Version 3-5,
  74. * as well as OS/2 Bitmap Version 2.x (for single-image BMP file).
  75. */
  76. public class BMPImageReader extends ImageReader implements BMPConstants {
  77. // BMP Image types
  78. private static final int VERSION_2_1_BIT = 0;
  79. private static final int VERSION_2_4_BIT = 1;
  80. private static final int VERSION_2_8_BIT = 2;
  81. private static final int VERSION_2_24_BIT = 3;
  82. private static final int VERSION_3_1_BIT = 4;
  83. private static final int VERSION_3_4_BIT = 5;
  84. private static final int VERSION_3_8_BIT = 6;
  85. private static final int VERSION_3_24_BIT = 7;
  86. private static final int VERSION_3_NT_16_BIT = 8;
  87. private static final int VERSION_3_NT_32_BIT = 9;
  88. private static final int VERSION_4_1_BIT = 10;
  89. private static final int VERSION_4_4_BIT = 11;
  90. private static final int VERSION_4_8_BIT = 12;
  91. private static final int VERSION_4_16_BIT = 13;
  92. private static final int VERSION_4_24_BIT = 14;
  93. private static final int VERSION_4_32_BIT = 15;
  94. private static final int VERSION_3_XP_EMBEDDED = 16;
  95. private static final int VERSION_4_XP_EMBEDDED = 17;
  96. private static final int VERSION_5_XP_EMBEDDED = 18;
  97. // BMP variables
  98. private long bitmapFileSize;
  99. private long bitmapOffset;
  100. private long compression;
  101. private long imageSize;
  102. private byte palette[];
  103. private int imageType;
  104. private int numBands;
  105. private boolean isBottomUp;
  106. private int bitsPerPixel;
  107. private int redMask, greenMask, blueMask, alphaMask;
  108. private SampleModel sampleModel, originalSampleModel;
  109. private ColorModel colorModel, originalColorModel;
  110. /** The input stream where reads from */
  111. private ImageInputStream iis = null;
  112. /** Indicates whether the header is read. */
  113. private boolean gotHeader = false;
  114. /** The original image width. */
  115. private int width;
  116. /** The original image height. */
  117. private int height;
  118. /** The destination region. */
  119. private Rectangle destinationRegion;
  120. /** The source region. */
  121. private Rectangle sourceRegion;
  122. /** The metadata from the stream. */
  123. private BMPMetadata metadata;
  124. /** The destination image. */
  125. private BufferedImage bi;
  126. /** Indicates whether subsampled, subregion is required, and offset is
  127. * defined
  128. */
  129. private boolean noTransform = true;
  130. /** Indicates whether subband is selected. */
  131. private boolean seleBand = false;
  132. /** The scaling factors. */
  133. private int scaleX, scaleY;
  134. /** source and destination bands. */
  135. private int[] sourceBands, destBands;
  136. /** Constructs <code>BMPImageReader</code> from the provided
  137. * <code>ImageReaderSpi</code>.
  138. */
  139. public BMPImageReader(ImageReaderSpi originator) {
  140. super(originator);
  141. }
  142. /** Overrides the method defined in the superclass. */
  143. public void setInput(Object input,
  144. boolean seekForwardOnly,
  145. boolean ignoreMetadata) {
  146. super.setInput(input, seekForwardOnly, ignoreMetadata);
  147. iis = (ImageInputStream) input; // Always works
  148. if(iis != null)
  149. iis.setByteOrder(ByteOrder.LITTLE_ENDIAN);
  150. resetHeaderInfo();
  151. }
  152. /** Overrides the method defined in the superclass. */
  153. public int getNumImages(boolean allowSearch) throws IOException {
  154. if (iis == null) {
  155. throw new IllegalStateException(I18N.getString("GetNumImages0"));
  156. }
  157. if (seekForwardOnly && allowSearch) {
  158. throw new IllegalStateException(I18N.getString("GetNumImages1"));
  159. }
  160. return 1;
  161. }
  162. public int getWidth(int imageIndex) throws IOException {
  163. checkIndex(imageIndex);
  164. readHeader();
  165. return width;
  166. }
  167. public int getHeight(int imageIndex) throws IOException {
  168. checkIndex(imageIndex);
  169. readHeader();
  170. return height;
  171. }
  172. private void checkIndex(int imageIndex) {
  173. if (imageIndex != 0) {
  174. throw new IndexOutOfBoundsException(I18N.getString("BMPImageReader0"));
  175. }
  176. }
  177. public void readHeader() throws IOException {
  178. if (gotHeader)
  179. return;
  180. if (iis == null) {
  181. throw new IllegalStateException("Input source not set!");
  182. }
  183. int profileData = 0, profileSize = 0;
  184. this.metadata = new BMPMetadata();
  185. iis.mark();
  186. // read and check the magic marker
  187. byte[] marker = new byte[2];
  188. iis.read(marker);
  189. if (marker[0] != 0x42 || marker[1] != 0x4d)
  190. throw new IllegalArgumentException(I18N.getString("BMPImageReader1"));
  191. // Read file size
  192. bitmapFileSize = iis.readUnsignedInt();
  193. // skip the two reserved fields
  194. iis.skipBytes(4);
  195. // Offset to the bitmap from the beginning
  196. bitmapOffset = iis.readUnsignedInt();
  197. // End File Header
  198. // Start BitmapCoreHeader
  199. long size = iis.readUnsignedInt();
  200. if (size == 12) {
  201. width = iis.readShort();
  202. height = iis.readShort();
  203. } else {
  204. width = iis.readInt();
  205. height = iis.readInt();
  206. }
  207. metadata.width = width;
  208. metadata.height = height;
  209. int planes = iis.readUnsignedShort();
  210. bitsPerPixel = iis.readUnsignedShort();
  211. //metadata.colorPlane = planes;
  212. metadata.bitsPerPixel = (short)bitsPerPixel;
  213. // As BMP always has 3 rgb bands, except for Version 5,
  214. // which is bgra
  215. numBands = 3;
  216. if (size == 12) {
  217. // Windows 2.x and OS/2 1.x
  218. metadata.bmpVersion = VERSION_2;
  219. // Classify the image type
  220. if (bitsPerPixel == 1) {
  221. imageType = VERSION_2_1_BIT;
  222. } else if (bitsPerPixel == 4) {
  223. imageType = VERSION_2_4_BIT;
  224. } else if (bitsPerPixel == 8) {
  225. imageType = VERSION_2_8_BIT;
  226. } else if (bitsPerPixel == 24) {
  227. imageType = VERSION_2_24_BIT;
  228. }
  229. // Read in the palette
  230. int numberOfEntries = (int)((bitmapOffset - 14 - size) / 3);
  231. int sizeOfPalette = numberOfEntries*3;
  232. palette = new byte[sizeOfPalette];
  233. iis.readFully(palette, 0, sizeOfPalette);
  234. metadata.palette = palette;
  235. metadata.paletteSize = numberOfEntries;
  236. } else {
  237. compression = iis.readUnsignedInt();
  238. imageSize = iis.readUnsignedInt();
  239. long xPelsPerMeter = iis.readInt();
  240. long yPelsPerMeter = iis.readInt();
  241. long colorsUsed = iis.readUnsignedInt();
  242. long colorsImportant = iis.readUnsignedInt();
  243. metadata.compression = (int)compression;
  244. metadata.xPixelsPerMeter = (int)xPelsPerMeter;
  245. metadata.yPixelsPerMeter = (int)yPelsPerMeter;
  246. metadata.colorsUsed = (int)colorsUsed;
  247. metadata.colorsImportant = (int)colorsImportant;
  248. if (size == 40) {
  249. // Windows 3.x and Windows NT
  250. switch((int)compression) {
  251. case BI_JPEG:
  252. case BI_PNG:
  253. metadata.bmpVersion = VERSION_3;
  254. imageType = VERSION_3_XP_EMBEDDED;
  255. break;
  256. case BI_RGB: // No compression
  257. case BI_RLE8: // 8-bit RLE compression
  258. case BI_RLE4: // 4-bit RLE compression
  259. // Read in the palette
  260. int numberOfEntries = (int)((bitmapOffset-14-size) / 4);
  261. int sizeOfPalette = numberOfEntries * 4;
  262. palette = new byte[sizeOfPalette];
  263. iis.readFully(palette, 0, sizeOfPalette);
  264. metadata.palette = palette;
  265. metadata.paletteSize = numberOfEntries;
  266. if (bitsPerPixel == 1) {
  267. imageType = VERSION_3_1_BIT;
  268. } else if (bitsPerPixel == 4) {
  269. imageType = VERSION_3_4_BIT;
  270. } else if (bitsPerPixel == 8) {
  271. imageType = VERSION_3_8_BIT;
  272. } else if (bitsPerPixel == 24) {
  273. imageType = VERSION_3_24_BIT;
  274. } else if (bitsPerPixel == 16) {
  275. imageType = VERSION_3_NT_16_BIT;
  276. redMask = 0x7C00;
  277. greenMask = 0x3E0;
  278. blueMask = (1 << 5) - 1;// 0x1F;
  279. metadata.redMask = redMask;
  280. metadata.greenMask = greenMask;
  281. metadata.blueMask = blueMask;
  282. } else if (bitsPerPixel == 32) {
  283. imageType = VERSION_3_NT_32_BIT;
  284. redMask = 0x00FF0000;
  285. greenMask = 0x0000FF00;
  286. blueMask = 0x000000FF;
  287. metadata.redMask = redMask;
  288. metadata.greenMask = greenMask;
  289. metadata.blueMask = blueMask;
  290. }
  291. metadata.bmpVersion = VERSION_3;
  292. break;
  293. case BI_BITFIELDS:
  294. if (bitsPerPixel == 16) {
  295. imageType = VERSION_3_NT_16_BIT;
  296. } else if (bitsPerPixel == 32) {
  297. imageType = VERSION_3_NT_32_BIT;
  298. }
  299. // BitsField encoding
  300. redMask = (int)iis.readUnsignedInt();
  301. greenMask = (int)iis.readUnsignedInt();
  302. blueMask = (int)iis.readUnsignedInt();
  303. metadata.redMask = redMask;
  304. metadata.greenMask = greenMask;
  305. metadata.blueMask = blueMask;
  306. if (colorsUsed != 0) {
  307. // there is a palette
  308. sizeOfPalette = (int)colorsUsed*4;
  309. palette = new byte[sizeOfPalette];
  310. iis.readFully(palette, 0, sizeOfPalette);
  311. metadata.palette = palette;
  312. metadata.paletteSize = (int)colorsUsed;
  313. }
  314. metadata.bmpVersion = VERSION_3_NT;
  315. break;
  316. default:
  317. throw new
  318. RuntimeException(I18N.getString("BMPImageReader2"));
  319. }
  320. } else if (size == 108 || size == 124) {
  321. // Windows 4.x BMP
  322. if (size == 108)
  323. metadata.bmpVersion = VERSION_4;
  324. else if (size == 124)
  325. metadata.bmpVersion = VERSION_5;
  326. // rgb masks, valid only if comp is BI_BITFIELDS
  327. redMask = (int)iis.readUnsignedInt();
  328. greenMask = (int)iis.readUnsignedInt();
  329. blueMask = (int)iis.readUnsignedInt();
  330. // Only supported for 32bpp BI_RGB argb
  331. alphaMask = (int)iis.readUnsignedInt();
  332. long csType = iis.readUnsignedInt();
  333. int redX = iis.readInt();
  334. int redY = iis.readInt();
  335. int redZ = iis.readInt();
  336. int greenX = iis.readInt();
  337. int greenY = iis.readInt();
  338. int greenZ = iis.readInt();
  339. int blueX = iis.readInt();
  340. int blueY = iis.readInt();
  341. int blueZ = iis.readInt();
  342. long gammaRed = iis.readUnsignedInt();
  343. long gammaGreen = iis.readUnsignedInt();
  344. long gammaBlue = iis.readUnsignedInt();
  345. if (size == 124) {
  346. metadata.intent = iis.readInt();
  347. profileData = iis.readInt();
  348. profileSize = iis.readInt();
  349. iis.skipBytes(4);
  350. }
  351. metadata.colorSpace = (int)csType;
  352. if (csType == LCS_CALIBRATED_RGB) {
  353. // All the new fields are valid only for this case
  354. metadata.redX = redX;
  355. metadata.redY = redY;
  356. metadata.redZ = redZ;
  357. metadata.greenX = greenX;
  358. metadata.greenY = greenY;
  359. metadata.greenZ = greenZ;
  360. metadata.blueX = blueX;
  361. metadata.blueY = blueY;
  362. metadata.blueZ = blueZ;
  363. metadata.gammaRed = (int)gammaRed;
  364. metadata.gammaGreen = (int)gammaGreen;
  365. metadata.gammaBlue = (int)gammaBlue;
  366. }
  367. // Read in the palette
  368. int numberOfEntries = (int)((bitmapOffset-14-size) / 4);
  369. int sizeOfPalette = numberOfEntries*4;
  370. palette = new byte[sizeOfPalette];
  371. iis.readFully(palette, 0, sizeOfPalette);
  372. metadata.palette = palette;
  373. metadata.paletteSize = numberOfEntries;
  374. switch ((int)compression) {
  375. case BI_JPEG:
  376. case BI_PNG:
  377. if (size == 108) {
  378. imageType = VERSION_4_XP_EMBEDDED;
  379. } else if (size == 124) {
  380. imageType = VERSION_5_XP_EMBEDDED;
  381. }
  382. break;
  383. default:
  384. if (bitsPerPixel == 1) {
  385. imageType = VERSION_4_1_BIT;
  386. } else if (bitsPerPixel == 4) {
  387. imageType = VERSION_4_4_BIT;
  388. } else if (bitsPerPixel == 8) {
  389. imageType = VERSION_4_8_BIT;
  390. } else if (bitsPerPixel == 16) {
  391. imageType = VERSION_4_16_BIT;
  392. if ((int)compression == BI_RGB) {
  393. redMask = 0x7C00;
  394. greenMask = 0x3E0;
  395. blueMask = 0x1F;
  396. }
  397. } else if (bitsPerPixel == 24) {
  398. imageType = VERSION_4_24_BIT;
  399. } else if (bitsPerPixel == 32) {
  400. imageType = VERSION_4_32_BIT;
  401. if ((int)compression == BI_RGB) {
  402. redMask = 0x00FF0000;
  403. greenMask = 0x0000FF00;
  404. blueMask = 0x000000FF;
  405. }
  406. }
  407. metadata.redMask = redMask;
  408. metadata.greenMask = greenMask;
  409. metadata.blueMask = blueMask;
  410. metadata.alphaMask = alphaMask;
  411. }
  412. } else {
  413. throw new
  414. RuntimeException(I18N.getString("BMPImageReader3"));
  415. }
  416. }
  417. if (height > 0) {
  418. // bottom up image
  419. isBottomUp = true;
  420. } else {
  421. // top down image
  422. isBottomUp = false;
  423. height = Math.abs(height);
  424. }
  425. // Reset Image Layout so there's only one tile.
  426. //Define the color space
  427. ColorSpace colorSpace = ColorSpace.getInstance(ColorSpace.CS_sRGB);
  428. if (metadata.colorSpace == PROFILE_LINKED ||
  429. metadata.colorSpace == PROFILE_EMBEDDED) {
  430. iis.mark();
  431. iis.skipBytes(profileData - size);
  432. byte[] profile = new byte[profileSize];
  433. iis.readFully(profile, 0, profileSize);
  434. iis.reset();
  435. try {
  436. if (metadata.colorSpace == PROFILE_LINKED &&
  437. isLinkedProfileAllowed() &&
  438. !isUncOrDevicePath(profile))
  439. {
  440. String path = new String(profile, "windows-1252");
  441. colorSpace =
  442. new ICC_ColorSpace(ICC_Profile.getInstance(path));
  443. } else {
  444. colorSpace =
  445. new ICC_ColorSpace(ICC_Profile.getInstance(profile));
  446. }
  447. } catch (Exception e) {
  448. colorSpace = ColorSpace.getInstance(ColorSpace.CS_sRGB);
  449. }
  450. }
  451. if (bitsPerPixel == 0 ||
  452. compression == BI_JPEG || compression == BI_PNG )
  453. {
  454. // the colorModel and sampleModel will be initialzed
  455. // by the reader of embedded image
  456. colorModel = null;
  457. sampleModel = null;
  458. } else if (bitsPerPixel == 1 || bitsPerPixel == 4 || bitsPerPixel == 8) {
  459. // When number of bitsPerPixel is <= 8, we use IndexColorModel.
  460. numBands = 1;
  461. if (bitsPerPixel == 8) {
  462. int[] bandOffsets = new int[numBands];
  463. for (int i = 0; i < numBands; i++) {
  464. bandOffsets[i] = numBands -1 -i;
  465. }
  466. sampleModel =
  467. new PixelInterleavedSampleModel(DataBuffer.TYPE_BYTE,
  468. width, height,
  469. numBands,
  470. numBands * width,
  471. bandOffsets);
  472. } else {
  473. // 1 and 4 bit pixels can be stored in a packed format.
  474. sampleModel =
  475. new MultiPixelPackedSampleModel(DataBuffer.TYPE_BYTE,
  476. width, height,
  477. bitsPerPixel);
  478. }
  479. // Create IndexColorModel from the palette.
  480. byte r[], g[], b[];
  481. if (imageType == VERSION_2_1_BIT ||
  482. imageType == VERSION_2_4_BIT ||
  483. imageType == VERSION_2_8_BIT) {
  484. size = palette.length/3;
  485. if (size > 256) {
  486. size = 256;
  487. }
  488. int off;
  489. r = new byte[(int)size];
  490. g = new byte[(int)size];
  491. b = new byte[(int)size];
  492. for (int i=0; i<(int)size; i++) {
  493. off = 3 * i;
  494. b[i] = palette[off];
  495. g[i] = palette[off+1];
  496. r[i] = palette[off+2];
  497. }
  498. } else {
  499. size = palette.length/4;
  500. if (size > 256) {
  501. size = 256;
  502. }
  503. int off;
  504. r = new byte[(int)size];
  505. g = new byte[(int)size];
  506. b = new byte[(int)size];
  507. for (int i=0; i<size; i++) {
  508. off = 4 * i;
  509. b[i] = palette[off];
  510. g[i] = palette[off+1];
  511. r[i] = palette[off+2];
  512. }
  513. }
  514. if (ImageUtil.isIndicesForGrayscale(r, g, b))
  515. colorModel =
  516. ImageUtil.createColorModel(null, sampleModel);
  517. else
  518. colorModel = new IndexColorModel(bitsPerPixel, (int)size, r, g, b);
  519. } else if (bitsPerPixel == 16) {
  520. numBands = 3;
  521. sampleModel =
  522. new SinglePixelPackedSampleModel(DataBuffer.TYPE_USHORT,
  523. width, height,
  524. new int[] {redMask, greenMask, blueMask});
  525. colorModel =
  526. new DirectColorModel(colorSpace,
  527. 16, redMask, greenMask, blueMask, 0,
  528. false, DataBuffer.TYPE_USHORT);
  529. } else if (bitsPerPixel == 32) {
  530. numBands = alphaMask == 0 ? 3 : 4;
  531. // The number of bands in the SampleModel is determined by
  532. // the length of the mask array passed in.
  533. int[] bitMasks = numBands == 3 ?
  534. new int[] {redMask, greenMask, blueMask} :
  535. new int[] {redMask, greenMask, blueMask, alphaMask};
  536. sampleModel =
  537. new SinglePixelPackedSampleModel(DataBuffer.TYPE_INT,
  538. width, height,
  539. bitMasks);
  540. colorModel =
  541. new DirectColorModel(colorSpace,
  542. 32, redMask, greenMask, blueMask, alphaMask,
  543. false, DataBuffer.TYPE_INT);
  544. } else {
  545. numBands = 3;
  546. // Create SampleModel
  547. int[] bandOffsets = new int[numBands];
  548. for (int i = 0; i < numBands; i++) {
  549. bandOffsets[i] = numBands -1 -i;
  550. }
  551. sampleModel =
  552. new PixelInterleavedSampleModel(DataBuffer.TYPE_BYTE,
  553. width, height,
  554. numBands,
  555. numBands * width,
  556. bandOffsets);
  557. colorModel =
  558. ImageUtil.createColorModel(colorSpace, sampleModel);
  559. }
  560. originalSampleModel = sampleModel;
  561. originalColorModel = colorModel;
  562. // Reset to the start of bitmap; then jump to the
  563. //start of image data
  564. iis.reset();
  565. iis.skipBytes(bitmapOffset);
  566. gotHeader = true;
  567. }
  568. public Iterator getImageTypes(int imageIndex)
  569. throws IOException {
  570. checkIndex(imageIndex);
  571. readHeader();
  572. ArrayList list = new ArrayList(1);
  573. list.add(new ImageTypeSpecifier(originalColorModel,
  574. originalSampleModel));
  575. return list.iterator();
  576. }
  577. public ImageReadParam getDefaultReadParam() {
  578. return new ImageReadParam();
  579. }
  580. public IIOMetadata getImageMetadata(int imageIndex)
  581. throws IOException {
  582. checkIndex(imageIndex);
  583. if (metadata == null) {
  584. readHeader();
  585. }
  586. return metadata;
  587. }
  588. public IIOMetadata getStreamMetadata() throws IOException {
  589. return null;
  590. }
  591. public boolean isRandomAccessEasy(int imageIndex) throws IOException {
  592. checkIndex(imageIndex);
  593. readHeader();
  594. return metadata.compression == BI_RGB;
  595. }
  596. public BufferedImage read(int imageIndex, ImageReadParam param)
  597. throws IOException {
  598. if (iis == null) {
  599. throw new IllegalStateException(I18N.getString("BMPImageReader5"));
  600. }
  601. checkIndex(imageIndex);
  602. clearAbortRequest();
  603. processImageStarted(imageIndex);
  604. if (param == null)
  605. param = getDefaultReadParam();
  606. //read header
  607. readHeader();
  608. sourceRegion = new Rectangle(0, 0, 0, 0);
  609. destinationRegion = new Rectangle(0, 0, 0, 0);
  610. computeRegions(param, this.width, this.height,
  611. param.getDestination(),
  612. sourceRegion,
  613. destinationRegion);
  614. scaleX = param.getSourceXSubsampling();
  615. scaleY = param.getSourceYSubsampling();
  616. // If the destination band is set used it
  617. sourceBands = param.getSourceBands();
  618. destBands = param.getDestinationBands();
  619. seleBand = (sourceBands != null) && (destBands != null);
  620. noTransform =
  621. destinationRegion.equals(new Rectangle(0, 0, width, height)) ||
  622. seleBand;
  623. if (!seleBand) {
  624. sourceBands = new int[numBands];
  625. destBands = new int[numBands];
  626. for (int i = 0; i < numBands; i++)
  627. destBands[i] = sourceBands[i] = i;
  628. }
  629. // If the destination is provided, then use it. Otherwise, create new one
  630. bi = param.getDestination();
  631. // Get the image data.
  632. WritableRaster raster = null;
  633. if (bi == null) {
  634. if (sampleModel != null && colorModel != null) {
  635. sampleModel =
  636. sampleModel.createCompatibleSampleModel(destinationRegion.x +
  637. destinationRegion.width,
  638. destinationRegion.y +
  639. destinationRegion.height);
  640. if (seleBand)
  641. sampleModel = sampleModel.createSubsetSampleModel(sourceBands);
  642. raster = Raster.createWritableRaster(sampleModel, new Point());
  643. bi = new BufferedImage(colorModel, raster, false, null);
  644. }
  645. } else {
  646. raster = bi.getWritableTile(0, 0);
  647. sampleModel = bi.getSampleModel();
  648. colorModel = bi.getColorModel();
  649. noTransform &= destinationRegion.equals(raster.getBounds());
  650. }
  651. byte bdata[] = null; // buffer for byte data
  652. short sdata[] = null; // buffer for short data
  653. int idata[] = null; // buffer for int data
  654. // the sampleModel can be null in case of embedded image
  655. if (sampleModel != null) {
  656. if (sampleModel.getDataType() == DataBuffer.TYPE_BYTE)
  657. bdata = (byte[])
  658. ((DataBufferByte)raster.getDataBuffer()).getData();
  659. else if (sampleModel.getDataType() == DataBuffer.TYPE_USHORT)
  660. sdata = (short[])
  661. ((DataBufferUShort)raster.getDataBuffer()).getData();
  662. else if (sampleModel.getDataType() == DataBuffer.TYPE_INT)
  663. idata = (int[])
  664. ((DataBufferInt)raster.getDataBuffer()).getData();
  665. }
  666. // There should only be one tile.
  667. switch(imageType) {
  668. case VERSION_2_1_BIT:
  669. // no compression
  670. read1Bit(bdata);
  671. break;
  672. case VERSION_2_4_BIT:
  673. // no compression
  674. read4Bit(bdata);
  675. break;
  676. case VERSION_2_8_BIT:
  677. // no compression
  678. read8Bit(bdata);
  679. break;
  680. case VERSION_2_24_BIT:
  681. // no compression
  682. read24Bit(bdata);
  683. break;
  684. case VERSION_3_1_BIT:
  685. // 1-bit images cannot be compressed.
  686. read1Bit(bdata);
  687. break;
  688. case VERSION_3_4_BIT:
  689. switch((int)compression) {
  690. case BI_RGB:
  691. read4Bit(bdata);
  692. break;
  693. case BI_RLE4:
  694. readRLE4(bdata);
  695. break;
  696. default:
  697. throw new
  698. RuntimeException(I18N.getString("BMPImageReader1"));
  699. }
  700. break;
  701. case VERSION_3_8_BIT:
  702. switch((int)compression) {
  703. case BI_RGB:
  704. read8Bit(bdata);
  705. break;
  706. case BI_RLE8:
  707. readRLE8(bdata);
  708. break;
  709. default:
  710. throw new
  711. RuntimeException(I18N.getString("BMPImageReader1"));
  712. }
  713. break;
  714. case VERSION_3_24_BIT:
  715. // 24-bit images are not compressed
  716. read24Bit(bdata);
  717. break;
  718. case VERSION_3_NT_16_BIT:
  719. read16Bit(sdata);
  720. break;
  721. case VERSION_3_NT_32_BIT:
  722. read32Bit(idata);
  723. break;
  724. case VERSION_3_XP_EMBEDDED:
  725. case VERSION_4_XP_EMBEDDED:
  726. case VERSION_5_XP_EMBEDDED:
  727. bi = readEmbedded((int)compression, bi, param);
  728. break;
  729. case VERSION_4_1_BIT:
  730. read1Bit(bdata);
  731. break;
  732. case VERSION_4_4_BIT:
  733. switch((int)compression) {
  734. case BI_RGB:
  735. read4Bit(bdata);
  736. break;
  737. case BI_RLE4:
  738. readRLE4(bdata);
  739. break;
  740. default:
  741. throw new
  742. RuntimeException(I18N.getString("BMPImageReader1"));
  743. }
  744. case VERSION_4_8_BIT:
  745. switch((int)compression) {
  746. case BI_RGB:
  747. read8Bit(bdata);
  748. break;
  749. case BI_RLE8:
  750. readRLE8(bdata);
  751. break;
  752. default:
  753. throw new
  754. RuntimeException(I18N.getString("BMPImageReader1"));
  755. }
  756. break;
  757. case VERSION_4_16_BIT:
  758. read16Bit(sdata);
  759. break;
  760. case VERSION_4_24_BIT:
  761. read24Bit(bdata);
  762. break;
  763. case VERSION_4_32_BIT:
  764. read32Bit(idata);
  765. break;
  766. }
  767. if (abortRequested())
  768. processReadAborted();
  769. else
  770. processImageComplete();
  771. return bi;
  772. }
  773. public boolean canReadRaster() {
  774. return true;
  775. }
  776. public Raster readRaster(int imageIndex,
  777. ImageReadParam param) throws IOException {
  778. BufferedImage bi = read(imageIndex, param);
  779. return bi.getData();
  780. }
  781. private void resetHeaderInfo() {
  782. gotHeader = false;
  783. bi = null;
  784. sampleModel = originalSampleModel = null;
  785. colorModel = originalColorModel = null;
  786. }
  787. public void reset() {
  788. super.reset();
  789. iis = null;
  790. resetHeaderInfo();
  791. }
  792. // Deal with 1 Bit images using IndexColorModels
  793. private void read1Bit(byte[] bdata) throws IOException {
  794. int bytesPerScanline = (width + 7) / 8;
  795. int padding = bytesPerScanline % 4;
  796. if (padding != 0) {
  797. padding = 4 - padding;
  798. }
  799. int lineLength = bytesPerScanline + padding;
  800. if (noTransform) {
  801. int j = isBottomUp ? (height -1)*bytesPerScanline : 0;
  802. for (int i=0; i<height; i++) {
  803. if (abortRequested()) {
  804. break;
  805. }
  806. iis.readFully(bdata, j, bytesPerScanline);
  807. iis.skipBytes(padding);
  808. j += isBottomUp ? -bytesPerScanline : bytesPerScanline;
  809. processImageUpdate(bi, 0, i,
  810. destinationRegion.width, 1, 1, 1,
  811. new int[]{0});
  812. processImageProgress(100.0F * i/destinationRegion.height);
  813. }
  814. } else {
  815. byte[] buf = new byte[lineLength];
  816. int lineStride =
  817. ((MultiPixelPackedSampleModel)sampleModel).getScanlineStride();
  818. if (isBottomUp) {
  819. int lastLine =
  820. sourceRegion.y + (destinationRegion.height - 1) * scaleY;
  821. iis.skipBytes(lineLength * (height - 1 - lastLine));
  822. } else
  823. iis.skipBytes(lineLength * sourceRegion.y);
  824. int skipLength = lineLength * (scaleY - 1);
  825. // cache the values to avoid duplicated computation
  826. int[] srcOff = new int[destinationRegion.width];
  827. int[] destOff = new int[destinationRegion.width];
  828. int[] srcPos = new int[destinationRegion.width];
  829. int[] destPos = new int[destinationRegion.width];
  830. for (int i = destinationRegion.x, x = sourceRegion.x, j = 0;
  831. i < destinationRegion.x + destinationRegion.width;
  832. i++, j++, x += scaleX) {
  833. srcPos[j] = x >> 3;
  834. srcOff[j] = 7 - (x & 7);
  835. destPos[j] = i >> 3;
  836. destOff[j] = 7 - (i & 7);
  837. }
  838. int k = destinationRegion.y * lineStride;
  839. if (isBottomUp)
  840. k += (destinationRegion.height - 1) * lineStride;
  841. for (int j = 0, y = sourceRegion.y;
  842. j < destinationRegion.height; j++, y+=scaleY) {
  843. if (abortRequested())
  844. break;
  845. iis.read(buf, 0, lineLength);
  846. for (int i = 0; i < destinationRegion.width; i++) {
  847. //get the bit and assign to the data buffer of the raster
  848. int v = (buf[srcPos[i]] >> srcOff[i]) & 1;
  849. bdata[k + destPos[i]] |= v << destOff[i];
  850. }
  851. k += isBottomUp ? -lineStride : lineStride;
  852. iis.skipBytes(skipLength);
  853. processImageUpdate(bi, 0, j,
  854. destinationRegion.width, 1, 1, 1,
  855. new int[]{0});
  856. processImageProgress(100.0F*j/destinationRegion.height);
  857. }
  858. }
  859. }
  860. // Method to read a 4 bit BMP image data
  861. private void read4Bit(byte[] bdata) throws IOException {
  862. int bytesPerScanline = (width + 1) / 2;
  863. // Padding bytes at the end of each scanline
  864. int padding = bytesPerScanline % 4;
  865. if (padding != 0)
  866. padding = 4 - padding;
  867. int lineLength = bytesPerScanline + padding;
  868. if (noTransform) {
  869. int j = isBottomUp ? (height -1) * bytesPerScanline : 0;
  870. for (int i=0; i<height; i++) {
  871. if (abortRequested()) {
  872. break;
  873. }
  874. iis.readFully(bdata, j, bytesPerScanline);
  875. iis.skipBytes(padding);
  876. j += isBottomUp ? -bytesPerScanline : bytesPerScanline;
  877. processImageUpdate(bi, 0, i,
  878. destinationRegion.width, 1, 1, 1,
  879. new int[]{0});
  880. processImageProgress(100.0F * i/destinationRegion.height);
  881. }
  882. } else {
  883. byte[] buf = new byte[lineLength];
  884. int lineStride =
  885. ((MultiPixelPackedSampleModel)sampleModel).getScanlineStride();
  886. if (isBottomUp) {
  887. int lastLine =
  888. sourceRegion.y + (destinationRegion.height - 1) * scaleY;
  889. iis.skipBytes(lineLength * (height - 1 - lastLine));
  890. } else
  891. iis.skipBytes(lineLength * sourceRegion.y);
  892. int skipLength = lineLength * (scaleY - 1);
  893. // cache the values to avoid duplicated computation
  894. int[] srcOff = new int[destinationRegion.width];
  895. int[] destOff = new int[destinationRegion.width];
  896. int[] srcPos = new int[destinationRegion.width];
  897. int[] destPos = new int[destinationRegion.width];
  898. for (int i = destinationRegion.x, x = sourceRegion.x, j = 0;
  899. i < destinationRegion.x + destinationRegion.width;
  900. i++, j++, x += scaleX) {
  901. srcPos[j] = x >> 1;
  902. srcOff[j] = (1 - (x & 1)) << 2;
  903. destPos[j] = i >> 1;
  904. destOff[j] = (1 - (i & 1)) << 2;
  905. }
  906. int k = destinationRegion.y * lineStride;
  907. if (isBottomUp)
  908. k += (destinationRegion.height - 1) * lineStride;
  909. for (int j = 0, y = sourceRegion.y;
  910. j < destinationRegion.height; j++, y+=scaleY) {
  911. if (abortRequested())
  912. break;
  913. iis.read(buf, 0, lineLength);
  914. for (int i = 0; i < destinationRegion.width; i++) {
  915. //get the bit and assign to the data buffer of the raster
  916. int v = (buf[srcPos[i]] >> srcOff[i]) & 0x0F;
  917. bdata[k + destPos[i]] |= v << destOff[i];
  918. }
  919. k += isBottomUp ? -lineStride : lineStride;
  920. iis.skipBytes(skipLength);
  921. processImageUpdate(bi, 0, j,
  922. destinationRegion.width, 1, 1, 1,
  923. new int[]{0});
  924. processImageProgress(100.0F*j/destinationRegion.height);
  925. }
  926. }
  927. }
  928. // Method to read 8 bit BMP image data
  929. private void read8Bit(byte[] bdata) throws IOException {
  930. // Padding bytes at the end of each scanline
  931. int padding = width % 4;
  932. if (padding != 0) {
  933. padding = 4 - padding;
  934. }
  935. int lineLength = width + padding;
  936. if (noTransform) {
  937. int j = isBottomUp ? (height -1) * width : 0;
  938. for (int i=0; i<height; i++) {
  939. if (abortRequested()) {
  940. break;
  941. }
  942. iis.readFully(bdata, j, width);
  943. iis.skipBytes(padding);
  944. j += isBottomUp ? -width : width;
  945. processImageUpdate(bi, 0, i,
  946. destinationRegion.width, 1, 1, 1,
  947. new int[]{0});
  948. processImageProgress(100.0F * i/destinationRegion.height);
  949. }
  950. } else {
  951. byte[] buf = new byte[lineLength];
  952. int lineStride =
  953. ((ComponentSampleModel)sampleModel).getScanlineStride();
  954. if (isBottomUp) {
  955. int lastLine =
  956. sourceRegion.y + (destinationRegion.height - 1) * scaleY;
  957. iis.skipBytes(lineLength * (height - 1 - lastLine));
  958. } else
  959. iis.skipBytes(lineLength * sourceRegion.y);
  960. int skipLength = lineLength * (scaleY - 1);
  961. int k = destinationRegion.y * lineStride;
  962. if (isBottomUp)
  963. k += (destinationRegion.height - 1) * lineStride;
  964. k += destinationRegion.x;
  965. for (int j = 0, y = sourceRegion.y;
  966. j < destinationRegion.height; j++, y+=scaleY) {
  967. if (abortRequested())
  968. break;
  969. iis.read(buf, 0, lineLength);
  970. for (int i = 0, m = sourceRegion.x;
  971. i < destinationRegion.width; i++, m += scaleX) {
  972. //get the bit and assign to the data buffer of the raster
  973. bdata[k + i] = buf[m];
  974. }
  975. k += isBottomUp ? -lineStride : lineStride;
  976. iis.skipBytes(skipLength);
  977. processImageUpdate(bi, 0, j,
  978. destinationRegion.width, 1, 1, 1,
  979. new int[]{0});
  980. processImageProgress(100.0F*j/destinationRegion.height);
  981. }
  982. }
  983. }
  984. // Method to read 24 bit BMP image data
  985. private void read24Bit(byte[] bdata) throws IOException {
  986. // Padding bytes at the end of each scanline
  987. // width * bitsPerPixel should be divisible by 32
  988. int padding = width * 3 % 4;
  989. if ( padding != 0)
  990. padding = 4 - padding;
  991. int lineStride = width * 3;
  992. int lineLength = lineStride + padding;
  993. if (noTransform) {
  994. int j = isBottomUp ? (height -1) * width * 3 : 0;
  995. for (int i=0; i<height; i++) {
  996. if (abortRequested()) {
  997. break;
  998. }
  999. iis.readFully(bdata, j, lineStride);
  1000. iis.skipBytes(padding);
  1001. j += isBottomUp ? -lineStride : lineStride;
  1002. processImageUpdate(bi, 0, i,
  1003. destinationRegion.width, 1, 1, 1,
  1004. new int[]{0});
  1005. processImageProgress(100.0F * i/destinationRegion.height);
  1006. }
  1007. } else {
  1008. byte[] buf = new byte[lineLength];
  1009. lineStride =
  1010. ((ComponentSampleModel)sampleModel).getScanlineStride();
  1011. if (isBottomUp) {
  1012. int lastLine =
  1013. sourceRegion.y + (destinationRegion.height - 1) * scaleY;
  1014. iis.skipBytes(lineLength * (height - 1 - lastLine));
  1015. } else
  1016. iis.skipBytes(lineLength * sourceRegion.y);
  1017. int skipLength = lineLength * (scaleY - 1);
  1018. int k = destinationRegion.y * lineStride;
  1019. if (isBottomUp)
  1020. k += (destinationRegion.height - 1) * lineStride;
  1021. k += destinationRegion.x * 3;
  1022. for (int j = 0, y = sourceRegion.y;
  1023. j < destinationRegion.height; j++, y+=scaleY) {
  1024. if (abortRequested())
  1025. break;
  1026. iis.read(buf, 0, lineLength);
  1027. for (int i = 0, m = 3 * sourceRegion.x;
  1028. i < destinationRegion.width; i++, m += 3 * scaleX) {
  1029. //get the bit and assign to the data buffer of the raster
  1030. int n = 3 * i + k;
  1031. for (int b = 0; b < destBands.length; b++)
  1032. bdata[n + destBands[b]] = buf[m + sourceBands[b]];
  1033. }
  1034. k += isBottomUp ? -lineStride : lineStride;
  1035. iis.skipBytes(skipLength);
  1036. processImageUpdate(bi, 0, j,
  1037. destinationRegion.width, 1, 1, 1,
  1038. new int[]{0});
  1039. processImageProgress(100.0F*j/destinationRegion.height);
  1040. }
  1041. }
  1042. }
  1043. private void read16Bit(short sdata[]) throws IOException {
  1044. // Padding bytes at the end of each scanline
  1045. // width * bitsPerPixel should be divisible by 32
  1046. int padding = width * 2 % 4;
  1047. if ( padding != 0)
  1048. padding = 4 - padding;
  1049. int lineLength = width + padding / 2;
  1050. if (noTransform) {
  1051. int j = isBottomUp ? (height -1) * width : 0;
  1052. for (int i=0; i<height; i++) {
  1053. if (abortRequested()) {
  1054. break;
  1055. }
  1056. iis.readFully(sdata, j, width);
  1057. iis.skipBytes(padding);
  1058. j += isBottomUp ? -width : width;
  1059. processImageUpdate(bi, 0, i,
  1060. destinationRegion.width, 1, 1, 1,
  1061. new int[]{0});
  1062. processImageProgress(100.0F * i/destinationRegion.height);
  1063. }
  1064. } else {
  1065. short[] buf = new short[lineLength];
  1066. int lineStride =
  1067. ((SinglePixelPackedSampleModel)sampleModel).getScanlineStride();
  1068. if (isBottomUp) {
  1069. int lastLine =
  1070. sourceRegion.y + (destinationRegion.height - 1) * scaleY;
  1071. iis.skipBytes(lineLength * (height - 1 - lastLine) << 1);
  1072. } else
  1073. iis.skipBytes(lineLength * sourceRegion.y << 1);
  1074. int skipLength = lineLength * (scaleY - 1) << 1;
  1075. int k = destinationRegion.y * lineStride;
  1076. if (isBottomUp)
  1077. k += (destinationRegion.height - 1) * lineStride;
  1078. k += destinationRegion.x;
  1079. for (int j = 0, y = sourceRegion.y;
  1080. j < destinationRegion.height; j++, y+=scaleY) {
  1081. if (abortRequested())
  1082. break;
  1083. iis.readFully(buf, 0, lineLength);
  1084. for (int i = 0, m = sourceRegion.x;
  1085. i < destinationRegion.width; i++, m += scaleX) {
  1086. //get the bit and assign to the data buffer of the raster
  1087. sdata[k + i] = buf[m];
  1088. }
  1089. k += isBottomUp ? -lineStride : lineStride;
  1090. iis.skipBytes(skipLength);
  1091. processImageUpdate(bi, 0, j,
  1092. destinationRegion.width, 1, 1, 1,
  1093. new int[]{0});
  1094. processImageProgress(100.0F*j/destinationRegion.height);
  1095. }
  1096. }
  1097. }
  1098. private void read32Bit(int idata[]) throws IOException {
  1099. if (noTransform) {
  1100. int j = isBottomUp ? (height -1) * width : 0;
  1101. for (int i=0; i<height; i++) {
  1102. if (abortRequested()) {
  1103. break;
  1104. }
  1105. iis.readFully(idata, j, width);
  1106. j += isBottomUp ? -width : width;
  1107. processImageUpdate(bi, 0, i,
  1108. destinationRegion.width, 1, 1, 1,
  1109. new int[]{0});
  1110. processImageProgress(100.0F * i/destinationRegion.height);
  1111. }
  1112. } else {
  1113. int[] buf = new int[width];
  1114. int lineStride =
  1115. ((SinglePixelPackedSampleModel)sampleModel).getScanlineStride();
  1116. if (isBottomUp) {
  1117. int lastLine =
  1118. sourceRegion.y + (destinationRegion.height - 1) * scaleY;
  1119. iis.skipBytes(width * (height - 1 - lastLine) << 2);
  1120. } else
  1121. iis.skipBytes(width * sourceRegion.y << 2);
  1122. int skipLength = width * (scaleY - 1) << 2;
  1123. int k = destinationRegion.y * lineStride;
  1124. if (isBottomUp)
  1125. k += (destinationRegion.height - 1) * lineStride;
  1126. k += destinationRegion.x;
  1127. for (int j = 0, y = sourceRegion.y;
  1128. j < destinationRegion.height; j++, y+=scaleY) {
  1129. if (abortRequested())
  1130. break;
  1131. iis.readFully(buf, 0, width);
  1132. for (int i = 0, m = sourceRegion.x;
  1133. i < destinationRegion.width; i++, m += scaleX) {
  1134. //get the bit and assign to the data buffer of the raster
  1135. idata[k + i] = buf[m];
  1136. }
  1137. k += isBottomUp ? -lineStride : lineStride;
  1138. iis.skipBytes(skipLength);
  1139. processImageUpdate(bi, 0, j,
  1140. destinationRegion.width, 1, 1, 1,
  1141. new int[]{0});
  1142. processImageProgress(100.0F*j/destinationRegion.height);
  1143. }
  1144. }
  1145. }
  1146. private void readRLE8(byte bdata[]) throws IOException {
  1147. // If imageSize field is not provided, calculate it.
  1148. int imSize = (int)imageSize;
  1149. if (imSize == 0) {
  1150. imSize = (int)(bitmapFileSize - bitmapOffset);
  1151. }
  1152. int padding = 0;
  1153. // If width is not 32 bit aligned, then while uncompressing each
  1154. // scanline will have padding bytes, calculate the amount of padding
  1155. int remainder = width % 4;
  1156. if (remainder != 0) {
  1157. padding = 4 - remainder;
  1158. }
  1159. // Read till we have the whole image
  1160. byte values[] = new byte[imSize];
  1161. int bytesRead = 0;
  1162. iis.readFully(values, 0, imSize);
  1163. // Since data is compressed, decompress it
  1164. decodeRLE8(imSize, padding, values, bdata);
  1165. }
  1166. private void decodeRLE8(int imSize,
  1167. int padding,
  1168. byte[] values,
  1169. byte[] bdata) throws IOException {
  1170. byte val[] = new byte[width * height];
  1171. int count = 0, l = 0;
  1172. int value;
  1173. boolean flag = false;
  1174. int lineNo = isBottomUp ? height - 1 : 0;
  1175. int lineStride =
  1176. ((ComponentSampleModel)sampleModel).getScanlineStride();
  1177. int finished = 0;
  1178. while (count != imSize) {
  1179. value = values[count++] & 0xff;
  1180. if (value == 0) {
  1181. switch(values[count++] & 0xff) {
  1182. case 0:
  1183. // End-of-scanline marker
  1184. if (lineNo >= sourceRegion.y &&
  1185. lineNo < sourceRegion.y + sourceRegion.height) {
  1186. if (noTransform) {
  1187. int pos = lineNo * width;
  1188. for(int i = 0; i < width; i++)
  1189. bdata[pos++] = val[i];
  1190. processImageUpdate(bi, 0, lineNo,
  1191. destinationRegion.width, 1, 1, 1,
  1192. new int[]{0});
  1193. finished++;
  1194. } else if ((lineNo - sourceRegion.y) % scaleY == 0) {
  1195. int currentLine = (lineNo - sourceRegion.y) / scaleY +
  1196. destinationRegion.y;
  1197. int pos = currentLine * lineStride;
  1198. pos += destinationRegion.x;
  1199. for (int i = sourceRegion.x;
  1200. i < sourceRegion.x + sourceRegion.width;
  1201. i += scaleX)
  1202. bdata[pos++] = val[i];
  1203. processImageUpdate(bi, 0, currentLine,
  1204. destinationRegion.width, 1, 1, 1,
  1205. new int[]{0});
  1206. finished++;
  1207. }
  1208. }
  1209. processImageProgress(100.0F * finished / destinationRegion.height);
  1210. lineNo += isBottomUp ? -1 : 1;
  1211. l = 0;
  1212. if (abortRequested()) {
  1213. flag = true;
  1214. }
  1215. break;
  1216. case 1:
  1217. // End-of-RLE marker
  1218. flag = true;
  1219. break;
  1220. case 2:
  1221. // delta or vector marker
  1222. int xoff = values[count++] & 0xff;
  1223. int yoff = values[count] & 0xff;
  1224. // Move to the position xoff, yoff down
  1225. l += xoff + yoff*width;
  1226. break;
  1227. default:
  1228. int end = values[count-1] & 0xff;
  1229. for (int i=0; i<end; i++) {
  1230. val[l++] = (byte)(values[count++] & 0xff);
  1231. }
  1232. // Whenever end pixels can fit into odd number of bytes,
  1233. // an extra padding byte will be present, so skip that.
  1234. if ((end & 1) == 1) {
  1235. count++;
  1236. }
  1237. }
  1238. } else {
  1239. for (int i=0; i<value; i++) {
  1240. val[l++] = (byte)(values[count] & 0xff);
  1241. }
  1242. count++;
  1243. }
  1244. // If End-of-RLE data, then exit the while loop
  1245. if (flag) {
  1246. break;
  1247. }
  1248. }
  1249. }
  1250. private void readRLE4(byte[] bdata) throws IOException {
  1251. // If imageSize field is not specified, calculate it.
  1252. int imSize = (int)imageSize;
  1253. if (imSize == 0) {
  1254. imSize = (int)(bitmapFileSize - bitmapOffset);
  1255. }
  1256. int padding = 0;
  1257. // If width is not 32 byte aligned, then while uncompressing each
  1258. // scanline will have padding bytes, calculate the amount of padding
  1259. int remainder = width % 4;
  1260. if (remainder != 0) {
  1261. padding = 4 - remainder;
  1262. }
  1263. // Read till we have the whole image
  1264. byte[] values = new byte[imSize];
  1265. iis.readFully(values, 0, imSize);
  1266. // Decompress the RLE4 compressed data.
  1267. decodeRLE4(imSize, padding, values, bdata);
  1268. }
  1269. private void decodeRLE4(int imSize,
  1270. int padding,
  1271. byte[] values,
  1272. byte[] bdata) throws IOException {
  1273. byte[] val = new byte[width];
  1274. int count = 0, l = 0;
  1275. int value;
  1276. boolean flag = false;
  1277. int lineNo = isBottomUp ? height - 1 : 0;
  1278. int lineStride =
  1279. ((MultiPixelPackedSampleModel)sampleModel).getScanlineStride();
  1280. int finished = 0;
  1281. while (count != imSize) {
  1282. value = values[count++] & 0xFF;
  1283. if (value == 0) {
  1284. // Absolute mode
  1285. switch(values[count++] & 0xFF) {
  1286. case 0:
  1287. // End-of-scanline marker
  1288. // End-of-scanline marker
  1289. if (lineNo >= sourceRegion.y &&
  1290. lineNo < sourceRegion.y + sourceRegion.height) {
  1291. if (noTransform) {
  1292. int pos = lineNo * (width + 1 >> 1);
  1293. for(int i = 0, j = 0; i < width >> 1; i++)
  1294. bdata[pos++] =
  1295. (byte)((val[j++] << 4) | val[j++]);
  1296. if ((width & 1) == 1)
  1297. bdata[pos] |= val[width - 1] << 4;
  1298. processImageUpdate(bi, 0, lineNo,
  1299. destinationRegion.width, 1, 1, 1,
  1300. new int[]{0});
  1301. finished++;
  1302. } else if ((lineNo - sourceRegion.y) % scaleY == 0) {
  1303. int currentLine = (lineNo - sourceRegion.y) / scaleY +
  1304. destinationRegion.y;
  1305. int pos = currentLine * lineStride;
  1306. pos += destinationRegion.x >> 1;
  1307. int shift = (1 - (destinationRegion.x & 1)) << 2;
  1308. for (int i = sourceRegion.x;
  1309. i < sourceRegion.x + sourceRegion.width;
  1310. i += scaleX) {
  1311. bdata[pos] |= val[i] << shift;
  1312. shift += 4;
  1313. if (shift == 4) {
  1314. pos++;
  1315. }
  1316. shift &= 7;
  1317. }
  1318. processImageUpdate(bi, 0, currentLine,
  1319. destinationRegion.width, 1, 1, 1,
  1320. new int[]{0});
  1321. finished++;
  1322. }
  1323. }
  1324. processImageProgress(100.0F * finished / destinationRegion.height);
  1325. lineNo += isBottomUp ? -1 : 1;
  1326. l = 0;
  1327. if (abortRequested()) {
  1328. flag = true;
  1329. }
  1330. break;
  1331. case 1:
  1332. // End-of-RLE marker
  1333. flag = true;
  1334. break;
  1335. case 2:
  1336. // delta or vector marker
  1337. int xoff = values[count++] & 0xFF;
  1338. int yoff = values[count] & 0xFF;
  1339. // Move to the position xoff, yoff down
  1340. l += xoff + yoff*width;
  1341. break;
  1342. default:
  1343. int end = values[count-1] & 0xFF;
  1344. for (int i=0; i<end; i++) {
  1345. val[l++] = (byte)(((i & 1) == 0) ? (values[count] & 0xf0) >> 4
  1346. : (values[count++] & 0x0f));
  1347. }
  1348. // When end is odd, the above for loop does not
  1349. // increment count, so do it now.
  1350. if ((end & 1) == 1) {
  1351. count++;
  1352. }
  1353. // Whenever end pixels can fit into odd number of bytes,
  1354. // an extra padding byte will be present, so skip that.
  1355. if ((((int)Math.ceil(end/2)) & 1) ==1 ) {
  1356. count++;
  1357. }
  1358. break;
  1359. }
  1360. } else {
  1361. // Encoded mode
  1362. int alternate[] = { (values[count] & 0xf0) >> 4,
  1363. values[count] & 0x0f };
  1364. for (int i=0; (i < value) && (l < width); i++) {
  1365. val[l++] = (byte)alternate[i & 1];
  1366. }
  1367. count++;
  1368. }
  1369. // If End-of-RLE data, then exit the while loop
  1370. if (flag) {
  1371. break;
  1372. }
  1373. }
  1374. }
  1375. /** Decodes the jpeg/png image embedded in the bitmap using any jpeg
  1376. * ImageIO-style plugin.
  1377. *
  1378. * @param bi The destination <code>BufferedImage</code>.
  1379. * @param bmpParam The <code>ImageReadParam</code> for decoding this
  1380. * BMP image. The parameters for subregion, band selection and
  1381. * subsampling are used in decoding the jpeg image.
  1382. */
  1383. private BufferedImage readEmbedded(int type,
  1384. BufferedImage bi, ImageReadParam bmpParam)
  1385. throws IOException {
  1386. String format;
  1387. switch(type) {
  1388. case BI_JPEG:
  1389. format = "JPEG";
  1390. break;
  1391. case BI_PNG:
  1392. format = "PNG";
  1393. break;
  1394. default:
  1395. throw new
  1396. IOException("Unexpected compression type: " + type);
  1397. }
  1398. ImageReader reader =
  1399. ImageIO.getImageReadersByFormatName(format).next();
  1400. if (reader == null) {
  1401. throw new RuntimeException(I18N.getString("BMPImageReader4") +
  1402. " " + format);
  1403. }
  1404. // prepare input
  1405. byte[] buff = new byte[(int)imageSize];
  1406. iis.read(buff);
  1407. reader.setInput(ImageIO.createImageInputStream(new ByteArrayInputStream(buff)));
  1408. if (bi == null) {
  1409. ImageTypeSpecifier embType = reader.getImageTypes(0).next();
  1410. bi = embType.createBufferedImage(destinationRegion.x +
  1411. destinationRegion.width,
  1412. destinationRegion.y +
  1413. destinationRegion.height);
  1414. }
  1415. reader.addIIOReadProgressListener(new EmbeddedProgressAdapter() {
  1416. public void imageProgress(ImageReader source,
  1417. float percentageDone)
  1418. {
  1419. processImageProgress(percentageDone);
  1420. }
  1421. });
  1422. reader.addIIOReadUpdateListener(new IIOReadUpdateListener() {
  1423. public void imageUpdate(ImageReader source,
  1424. BufferedImage theImage,
  1425. int minX, int minY,
  1426. int width, int height,
  1427. int periodX, int periodY,
  1428. int[] bands)
  1429. {
  1430. processImageUpdate(theImage, minX, minY,
  1431. width, height,
  1432. periodX, periodY, bands);
  1433. }
  1434. public void passComplete(ImageReader source,
  1435. BufferedImage theImage)
  1436. {
  1437. processPassComplete(theImage);
  1438. }
  1439. public void passStarted(ImageReader source,
  1440. BufferedImage theImage,
  1441. int pass,
  1442. int minPass, int maxPass,
  1443. int minX, int minY,
  1444. int periodX, int periodY,
  1445. int[] bands)
  1446. {
  1447. processPassStarted(theImage, pass, minPass, maxPass,
  1448. minX, minY, periodX, periodY,
  1449. bands);
  1450. }
  1451. public void thumbnailPassComplete(ImageReader source,
  1452. BufferedImage thumb) {}
  1453. public void thumbnailPassStarted(ImageReader source,
  1454. BufferedImage thumb,
  1455. int pass,
  1456. int minPass, int maxPass,
  1457. int minX, int minY,
  1458. int periodX, int periodY,
  1459. int[] bands) {}
  1460. public void thumbnailUpdate(ImageReader source,
  1461. BufferedImage theThumbnail,
  1462. int minX, int minY,
  1463. int width, int height,
  1464. int periodX, int periodY,
  1465. int[] bands) {}
  1466. });
  1467. reader.addIIOReadWarningListener(new IIOReadWarningListener() {
  1468. public void warningOccurred(ImageReader source, String warning)
  1469. {
  1470. processWarningOccurred(warning);
  1471. }
  1472. });
  1473. ImageReadParam param = reader.getDefaultReadParam();
  1474. param.setDestination(bi);
  1475. param.setDestinationBands(bmpParam.getDestinationBands());
  1476. param.setDestinationOffset(bmpParam.getDestinationOffset());
  1477. param.setSourceBands(bmpParam.getSourceBands());
  1478. param.setSourceRegion(bmpParam.getSourceRegion());
  1479. param.setSourceSubsampling(bmpParam.getSourceXSubsampling(),
  1480. bmpParam.getSourceYSubsampling(),
  1481. bmpParam.getSubsamplingXOffset(),
  1482. bmpParam.getSubsamplingYOffset());
  1483. reader.read(0, param);
  1484. return bi;
  1485. }
  1486. private class EmbeddedProgressAdapter implements IIOReadProgressListener {
  1487. public void imageComplete(ImageReader src) {}
  1488. public void imageProgress(ImageReader src, float percentageDone) {}
  1489. public void imageStarted(ImageReader src, int imageIndex) {}
  1490. public void thumbnailComplete(ImageReader src) {}
  1491. public void thumbnailProgress(ImageReader src, float percentageDone) {}
  1492. public void thumbnailStarted(ImageReader src, int iIdx, int tIdx) {}
  1493. public void sequenceComplete(ImageReader src) {}
  1494. public void sequenceStarted(ImageReader src, int minIndex) {}
  1495. public void readAborted(ImageReader src) {}
  1496. }
  1497. private static Boolean isLinkedProfileDisabled = null;
  1498. private static boolean isLinkedProfileAllowed() {
  1499. if (isLinkedProfileDisabled == null) {
  1500. PrivilegedAction<Boolean> a = new PrivilegedAction<Boolean>() {
  1501. public Boolean run() {
  1502. return Boolean.getBoolean("sun.imageio.plugins.bmp.disableLinkedProfiles");
  1503. }
  1504. };
  1505. isLinkedProfileDisabled = AccessController.doPrivileged(a);
  1506. }
  1507. return !isLinkedProfileDisabled;
  1508. }
  1509. private static Boolean isWindowsPlatform = null;
  1510. /**
  1511. * Verifies whether the byte array contans a unc path.
  1512. * Non-UNC path examples:
  1513. * c:\path\to\file - simple notation
  1514. * \\?\c:\path\to\file - long notation
  1515. *
  1516. * UNC path examples:
  1517. * \\server\share - a UNC path in simple notation
  1518. * \\?\UNC\server\share - a UNC path in long notation
  1519. * \\.\some\device - a path to device.
  1520. */
  1521. private static boolean isUncOrDevicePath(byte[] p) {
  1522. if (isWindowsPlatform == null) {
  1523. PrivilegedAction<Boolean> a = new PrivilegedAction<Boolean>() {
  1524. public Boolean run() {
  1525. String osname = System.getProperty("os.name");
  1526. return (osname != null &&
  1527. osname.toLowerCase().startsWith("win"));
  1528. }
  1529. };
  1530. isWindowsPlatform = AccessController.doPrivileged(a);
  1531. }
  1532. if (!isWindowsPlatform) {
  1533. /* no need for the check on platforms except windows */
  1534. return false;
  1535. }
  1536. /* normalize prefix of the path */
  1537. if (p[0] == '/') p[0] = '\\';
  1538. if (p[1] == '/') p[1] = '\\';
  1539. if (p[3] == '/') p[3] = '\\';
  1540. if ((p[0] == '\\') && (p[1] == '\\')) {
  1541. if ((p[2] == '?') && (p[3] == '\\')) {
  1542. // long path: whether unc or local
  1543. return ((p[4] == 'U' || p[4] == 'u') &&
  1544. (p[5] == 'N' || p[5] == 'n') &&
  1545. (p[6] == 'C' || p[6] == 'c'));
  1546. } else {
  1547. // device path or short unc notation
  1548. return true;
  1549. }
  1550. } else {
  1551. return false;
  1552. }
  1553. }
  1554. }