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

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

https://bitbucket.org/adoptopenjdk/jdk8-jdk
Java | 1860 lines | 1411 code | 267 blank | 182 comment | 329 complexity | b07fd32ab68a27336885f1069982232a MD5 | raw file
Possible License(s): LGPL-3.0, GPL-2.0, BSD-3-Clause-No-Nuclear-License-2014, BSD-3-Clause

Large files files are truncated, but you can click here to view the full file

  1. /*
  2. * Copyright (c) 2003, 2013, 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. @Override
  163. public int getWidth(int imageIndex) throws IOException {
  164. checkIndex(imageIndex);
  165. try {
  166. readHeader();
  167. } catch (IllegalArgumentException e) {
  168. throw new IIOException(I18N.getString("BMPImageReader6"), e);
  169. }
  170. return width;
  171. }
  172. public int getHeight(int imageIndex) throws IOException {
  173. checkIndex(imageIndex);
  174. try {
  175. readHeader();
  176. } catch (IllegalArgumentException e) {
  177. throw new IIOException(I18N.getString("BMPImageReader6"), e);
  178. }
  179. return height;
  180. }
  181. private void checkIndex(int imageIndex) {
  182. if (imageIndex != 0) {
  183. throw new IndexOutOfBoundsException(I18N.getString("BMPImageReader0"));
  184. }
  185. }
  186. /**
  187. * Process the image header.
  188. *
  189. * @exception IllegalStateException if source stream is not set.
  190. *
  191. * @exception IOException if image stream is corrupted.
  192. *
  193. * @exception IllegalArgumentException if the image stream does not contain
  194. * a BMP image, or if a sample model instance to describe the
  195. * image can not be created.
  196. */
  197. protected void readHeader() throws IOException, IllegalArgumentException {
  198. if (gotHeader)
  199. return;
  200. if (iis == null) {
  201. throw new IllegalStateException("Input source not set!");
  202. }
  203. int profileData = 0, profileSize = 0;
  204. this.metadata = new BMPMetadata();
  205. iis.mark();
  206. // read and check the magic marker
  207. byte[] marker = new byte[2];
  208. iis.read(marker);
  209. if (marker[0] != 0x42 || marker[1] != 0x4d)
  210. throw new IllegalArgumentException(I18N.getString("BMPImageReader1"));
  211. // Read file size
  212. bitmapFileSize = iis.readUnsignedInt();
  213. // skip the two reserved fields
  214. iis.skipBytes(4);
  215. // Offset to the bitmap from the beginning
  216. bitmapOffset = iis.readUnsignedInt();
  217. // End File Header
  218. // Start BitmapCoreHeader
  219. long size = iis.readUnsignedInt();
  220. if (size == 12) {
  221. width = iis.readShort();
  222. height = iis.readShort();
  223. } else {
  224. width = iis.readInt();
  225. height = iis.readInt();
  226. }
  227. metadata.width = width;
  228. metadata.height = height;
  229. int planes = iis.readUnsignedShort();
  230. bitsPerPixel = iis.readUnsignedShort();
  231. //metadata.colorPlane = planes;
  232. metadata.bitsPerPixel = (short)bitsPerPixel;
  233. // As BMP always has 3 rgb bands, except for Version 5,
  234. // which is bgra
  235. numBands = 3;
  236. if (size == 12) {
  237. // Windows 2.x and OS/2 1.x
  238. metadata.bmpVersion = VERSION_2;
  239. // Classify the image type
  240. if (bitsPerPixel == 1) {
  241. imageType = VERSION_2_1_BIT;
  242. } else if (bitsPerPixel == 4) {
  243. imageType = VERSION_2_4_BIT;
  244. } else if (bitsPerPixel == 8) {
  245. imageType = VERSION_2_8_BIT;
  246. } else if (bitsPerPixel == 24) {
  247. imageType = VERSION_2_24_BIT;
  248. }
  249. // Read in the palette
  250. int numberOfEntries = (int)((bitmapOffset - 14 - size) / 3);
  251. int sizeOfPalette = numberOfEntries*3;
  252. palette = new byte[sizeOfPalette];
  253. iis.readFully(palette, 0, sizeOfPalette);
  254. metadata.palette = palette;
  255. metadata.paletteSize = numberOfEntries;
  256. } else {
  257. compression = iis.readUnsignedInt();
  258. imageSize = iis.readUnsignedInt();
  259. long xPelsPerMeter = iis.readInt();
  260. long yPelsPerMeter = iis.readInt();
  261. long colorsUsed = iis.readUnsignedInt();
  262. long colorsImportant = iis.readUnsignedInt();
  263. metadata.compression = (int)compression;
  264. metadata.xPixelsPerMeter = (int)xPelsPerMeter;
  265. metadata.yPixelsPerMeter = (int)yPelsPerMeter;
  266. metadata.colorsUsed = (int)colorsUsed;
  267. metadata.colorsImportant = (int)colorsImportant;
  268. if (size == 40) {
  269. // Windows 3.x and Windows NT
  270. switch((int)compression) {
  271. case BI_JPEG:
  272. case BI_PNG:
  273. metadata.bmpVersion = VERSION_3;
  274. imageType = VERSION_3_XP_EMBEDDED;
  275. break;
  276. case BI_RGB: // No compression
  277. case BI_RLE8: // 8-bit RLE compression
  278. case BI_RLE4: // 4-bit RLE compression
  279. // Read in the palette
  280. if (bitmapOffset < (size + 14)) {
  281. throw new IIOException(I18N.getString("BMPImageReader7"));
  282. }
  283. int numberOfEntries = (int)((bitmapOffset-14-size) / 4);
  284. int sizeOfPalette = numberOfEntries * 4;
  285. palette = new byte[sizeOfPalette];
  286. iis.readFully(palette, 0, sizeOfPalette);
  287. metadata.palette = palette;
  288. metadata.paletteSize = numberOfEntries;
  289. if (bitsPerPixel == 1) {
  290. imageType = VERSION_3_1_BIT;
  291. } else if (bitsPerPixel == 4) {
  292. imageType = VERSION_3_4_BIT;
  293. } else if (bitsPerPixel == 8) {
  294. imageType = VERSION_3_8_BIT;
  295. } else if (bitsPerPixel == 24) {
  296. imageType = VERSION_3_24_BIT;
  297. } else if (bitsPerPixel == 16) {
  298. imageType = VERSION_3_NT_16_BIT;
  299. redMask = 0x7C00;
  300. greenMask = 0x3E0;
  301. blueMask = (1 << 5) - 1;// 0x1F;
  302. metadata.redMask = redMask;
  303. metadata.greenMask = greenMask;
  304. metadata.blueMask = blueMask;
  305. } else if (bitsPerPixel == 32) {
  306. imageType = VERSION_3_NT_32_BIT;
  307. redMask = 0x00FF0000;
  308. greenMask = 0x0000FF00;
  309. blueMask = 0x000000FF;
  310. metadata.redMask = redMask;
  311. metadata.greenMask = greenMask;
  312. metadata.blueMask = blueMask;
  313. }
  314. metadata.bmpVersion = VERSION_3;
  315. break;
  316. case BI_BITFIELDS:
  317. if (bitsPerPixel == 16) {
  318. imageType = VERSION_3_NT_16_BIT;
  319. } else if (bitsPerPixel == 32) {
  320. imageType = VERSION_3_NT_32_BIT;
  321. }
  322. // BitsField encoding
  323. redMask = (int)iis.readUnsignedInt();
  324. greenMask = (int)iis.readUnsignedInt();
  325. blueMask = (int)iis.readUnsignedInt();
  326. metadata.redMask = redMask;
  327. metadata.greenMask = greenMask;
  328. metadata.blueMask = blueMask;
  329. if (colorsUsed != 0) {
  330. // there is a palette
  331. sizeOfPalette = (int)colorsUsed*4;
  332. palette = new byte[sizeOfPalette];
  333. iis.readFully(palette, 0, sizeOfPalette);
  334. metadata.palette = palette;
  335. metadata.paletteSize = (int)colorsUsed;
  336. }
  337. metadata.bmpVersion = VERSION_3_NT;
  338. break;
  339. default:
  340. throw new
  341. IIOException(I18N.getString("BMPImageReader2"));
  342. }
  343. } else if (size == 108 || size == 124) {
  344. // Windows 4.x BMP
  345. if (size == 108)
  346. metadata.bmpVersion = VERSION_4;
  347. else if (size == 124)
  348. metadata.bmpVersion = VERSION_5;
  349. // rgb masks, valid only if comp is BI_BITFIELDS
  350. redMask = (int)iis.readUnsignedInt();
  351. greenMask = (int)iis.readUnsignedInt();
  352. blueMask = (int)iis.readUnsignedInt();
  353. // Only supported for 32bpp BI_RGB argb
  354. alphaMask = (int)iis.readUnsignedInt();
  355. long csType = iis.readUnsignedInt();
  356. int redX = iis.readInt();
  357. int redY = iis.readInt();
  358. int redZ = iis.readInt();
  359. int greenX = iis.readInt();
  360. int greenY = iis.readInt();
  361. int greenZ = iis.readInt();
  362. int blueX = iis.readInt();
  363. int blueY = iis.readInt();
  364. int blueZ = iis.readInt();
  365. long gammaRed = iis.readUnsignedInt();
  366. long gammaGreen = iis.readUnsignedInt();
  367. long gammaBlue = iis.readUnsignedInt();
  368. if (size == 124) {
  369. metadata.intent = iis.readInt();
  370. profileData = iis.readInt();
  371. profileSize = iis.readInt();
  372. iis.skipBytes(4);
  373. }
  374. metadata.colorSpace = (int)csType;
  375. if (csType == LCS_CALIBRATED_RGB) {
  376. // All the new fields are valid only for this case
  377. metadata.redX = redX;
  378. metadata.redY = redY;
  379. metadata.redZ = redZ;
  380. metadata.greenX = greenX;
  381. metadata.greenY = greenY;
  382. metadata.greenZ = greenZ;
  383. metadata.blueX = blueX;
  384. metadata.blueY = blueY;
  385. metadata.blueZ = blueZ;
  386. metadata.gammaRed = (int)gammaRed;
  387. metadata.gammaGreen = (int)gammaGreen;
  388. metadata.gammaBlue = (int)gammaBlue;
  389. }
  390. // Read in the palette
  391. int numberOfEntries = (int)((bitmapOffset-14-size) / 4);
  392. int sizeOfPalette = numberOfEntries*4;
  393. palette = new byte[sizeOfPalette];
  394. iis.readFully(palette, 0, sizeOfPalette);
  395. metadata.palette = palette;
  396. metadata.paletteSize = numberOfEntries;
  397. switch ((int)compression) {
  398. case BI_JPEG:
  399. case BI_PNG:
  400. if (size == 108) {
  401. imageType = VERSION_4_XP_EMBEDDED;
  402. } else if (size == 124) {
  403. imageType = VERSION_5_XP_EMBEDDED;
  404. }
  405. break;
  406. default:
  407. if (bitsPerPixel == 1) {
  408. imageType = VERSION_4_1_BIT;
  409. } else if (bitsPerPixel == 4) {
  410. imageType = VERSION_4_4_BIT;
  411. } else if (bitsPerPixel == 8) {
  412. imageType = VERSION_4_8_BIT;
  413. } else if (bitsPerPixel == 16) {
  414. imageType = VERSION_4_16_BIT;
  415. if ((int)compression == BI_RGB) {
  416. redMask = 0x7C00;
  417. greenMask = 0x3E0;
  418. blueMask = 0x1F;
  419. }
  420. } else if (bitsPerPixel == 24) {
  421. imageType = VERSION_4_24_BIT;
  422. } else if (bitsPerPixel == 32) {
  423. imageType = VERSION_4_32_BIT;
  424. if ((int)compression == BI_RGB) {
  425. redMask = 0x00FF0000;
  426. greenMask = 0x0000FF00;
  427. blueMask = 0x000000FF;
  428. }
  429. }
  430. metadata.redMask = redMask;
  431. metadata.greenMask = greenMask;
  432. metadata.blueMask = blueMask;
  433. metadata.alphaMask = alphaMask;
  434. }
  435. } else {
  436. throw new
  437. IIOException(I18N.getString("BMPImageReader3"));
  438. }
  439. }
  440. if (height > 0) {
  441. // bottom up image
  442. isBottomUp = true;
  443. } else {
  444. // top down image
  445. isBottomUp = false;
  446. height = Math.abs(height);
  447. }
  448. // Reset Image Layout so there's only one tile.
  449. //Define the color space
  450. ColorSpace colorSpace = ColorSpace.getInstance(ColorSpace.CS_sRGB);
  451. if (metadata.colorSpace == PROFILE_LINKED ||
  452. metadata.colorSpace == PROFILE_EMBEDDED) {
  453. iis.mark();
  454. iis.skipBytes(profileData - size);
  455. byte[] profile = new byte[profileSize];
  456. iis.readFully(profile, 0, profileSize);
  457. iis.reset();
  458. try {
  459. if (metadata.colorSpace == PROFILE_LINKED &&
  460. isLinkedProfileAllowed() &&
  461. !isUncOrDevicePath(profile))
  462. {
  463. String path = new String(profile, "windows-1252");
  464. colorSpace =
  465. new ICC_ColorSpace(ICC_Profile.getInstance(path));
  466. } else {
  467. colorSpace =
  468. new ICC_ColorSpace(ICC_Profile.getInstance(profile));
  469. }
  470. } catch (Exception e) {
  471. colorSpace = ColorSpace.getInstance(ColorSpace.CS_sRGB);
  472. }
  473. }
  474. if (bitsPerPixel == 0 ||
  475. compression == BI_JPEG || compression == BI_PNG )
  476. {
  477. // the colorModel and sampleModel will be initialzed
  478. // by the reader of embedded image
  479. colorModel = null;
  480. sampleModel = null;
  481. } else if (bitsPerPixel == 1 || bitsPerPixel == 4 || bitsPerPixel == 8) {
  482. // When number of bitsPerPixel is <= 8, we use IndexColorModel.
  483. numBands = 1;
  484. if (bitsPerPixel == 8) {
  485. int[] bandOffsets = new int[numBands];
  486. for (int i = 0; i < numBands; i++) {
  487. bandOffsets[i] = numBands -1 -i;
  488. }
  489. sampleModel =
  490. new PixelInterleavedSampleModel(DataBuffer.TYPE_BYTE,
  491. width, height,
  492. numBands,
  493. numBands * width,
  494. bandOffsets);
  495. } else {
  496. // 1 and 4 bit pixels can be stored in a packed format.
  497. sampleModel =
  498. new MultiPixelPackedSampleModel(DataBuffer.TYPE_BYTE,
  499. width, height,
  500. bitsPerPixel);
  501. }
  502. // Create IndexColorModel from the palette.
  503. byte r[], g[], b[];
  504. if (imageType == VERSION_2_1_BIT ||
  505. imageType == VERSION_2_4_BIT ||
  506. imageType == VERSION_2_8_BIT) {
  507. size = palette.length/3;
  508. if (size > 256) {
  509. size = 256;
  510. }
  511. int off;
  512. r = new byte[(int)size];
  513. g = new byte[(int)size];
  514. b = new byte[(int)size];
  515. for (int i=0; i<(int)size; i++) {
  516. off = 3 * i;
  517. b[i] = palette[off];
  518. g[i] = palette[off+1];
  519. r[i] = palette[off+2];
  520. }
  521. } else {
  522. size = palette.length/4;
  523. if (size > 256) {
  524. size = 256;
  525. }
  526. int off;
  527. r = new byte[(int)size];
  528. g = new byte[(int)size];
  529. b = new byte[(int)size];
  530. for (int i=0; i<size; i++) {
  531. off = 4 * i;
  532. b[i] = palette[off];
  533. g[i] = palette[off+1];
  534. r[i] = palette[off+2];
  535. }
  536. }
  537. if (ImageUtil.isIndicesForGrayscale(r, g, b))
  538. colorModel =
  539. ImageUtil.createColorModel(null, sampleModel);
  540. else
  541. colorModel = new IndexColorModel(bitsPerPixel, (int)size, r, g, b);
  542. } else if (bitsPerPixel == 16) {
  543. numBands = 3;
  544. sampleModel =
  545. new SinglePixelPackedSampleModel(DataBuffer.TYPE_USHORT,
  546. width, height,
  547. new int[] {redMask, greenMask, blueMask});
  548. colorModel =
  549. new DirectColorModel(colorSpace,
  550. 16, redMask, greenMask, blueMask, 0,
  551. false, DataBuffer.TYPE_USHORT);
  552. } else if (bitsPerPixel == 32) {
  553. numBands = alphaMask == 0 ? 3 : 4;
  554. // The number of bands in the SampleModel is determined by
  555. // the length of the mask array passed in.
  556. int[] bitMasks = numBands == 3 ?
  557. new int[] {redMask, greenMask, blueMask} :
  558. new int[] {redMask, greenMask, blueMask, alphaMask};
  559. sampleModel =
  560. new SinglePixelPackedSampleModel(DataBuffer.TYPE_INT,
  561. width, height,
  562. bitMasks);
  563. colorModel =
  564. new DirectColorModel(colorSpace,
  565. 32, redMask, greenMask, blueMask, alphaMask,
  566. false, DataBuffer.TYPE_INT);
  567. } else {
  568. numBands = 3;
  569. // Create SampleModel
  570. int[] bandOffsets = new int[numBands];
  571. for (int i = 0; i < numBands; i++) {
  572. bandOffsets[i] = numBands -1 -i;
  573. }
  574. sampleModel =
  575. new PixelInterleavedSampleModel(DataBuffer.TYPE_BYTE,
  576. width, height,
  577. numBands,
  578. numBands * width,
  579. bandOffsets);
  580. colorModel =
  581. ImageUtil.createColorModel(colorSpace, sampleModel);
  582. }
  583. originalSampleModel = sampleModel;
  584. originalColorModel = colorModel;
  585. // Reset to the start of bitmap; then jump to the
  586. //start of image data
  587. iis.reset();
  588. iis.skipBytes(bitmapOffset);
  589. gotHeader = true;
  590. }
  591. public Iterator getImageTypes(int imageIndex)
  592. throws IOException {
  593. checkIndex(imageIndex);
  594. try {
  595. readHeader();
  596. } catch (IllegalArgumentException e) {
  597. throw new IIOException(I18N.getString("BMPImageReader6"), e);
  598. }
  599. ArrayList list = new ArrayList(1);
  600. list.add(new ImageTypeSpecifier(originalColorModel,
  601. originalSampleModel));
  602. return list.iterator();
  603. }
  604. public ImageReadParam getDefaultReadParam() {
  605. return new ImageReadParam();
  606. }
  607. public IIOMetadata getImageMetadata(int imageIndex)
  608. throws IOException {
  609. checkIndex(imageIndex);
  610. if (metadata == null) {
  611. try {
  612. readHeader();
  613. } catch (IllegalArgumentException e) {
  614. throw new IIOException(I18N.getString("BMPImageReader6"), e);
  615. }
  616. }
  617. return metadata;
  618. }
  619. public IIOMetadata getStreamMetadata() throws IOException {
  620. return null;
  621. }
  622. public boolean isRandomAccessEasy(int imageIndex) throws IOException {
  623. checkIndex(imageIndex);
  624. try {
  625. readHeader();
  626. } catch (IllegalArgumentException e) {
  627. throw new IIOException(I18N.getString("BMPImageReader6"), e);
  628. }
  629. return metadata.compression == BI_RGB;
  630. }
  631. public BufferedImage read(int imageIndex, ImageReadParam param)
  632. throws IOException {
  633. if (iis == null) {
  634. throw new IllegalStateException(I18N.getString("BMPImageReader5"));
  635. }
  636. checkIndex(imageIndex);
  637. clearAbortRequest();
  638. processImageStarted(imageIndex);
  639. if (param == null)
  640. param = getDefaultReadParam();
  641. //read header
  642. try {
  643. readHeader();
  644. } catch (IllegalArgumentException e) {
  645. throw new IIOException(I18N.getString("BMPImageReader6"), e);
  646. }
  647. sourceRegion = new Rectangle(0, 0, 0, 0);
  648. destinationRegion = new Rectangle(0, 0, 0, 0);
  649. computeRegions(param, this.width, this.height,
  650. param.getDestination(),
  651. sourceRegion,
  652. destinationRegion);
  653. scaleX = param.getSourceXSubsampling();
  654. scaleY = param.getSourceYSubsampling();
  655. // If the destination band is set used it
  656. sourceBands = param.getSourceBands();
  657. destBands = param.getDestinationBands();
  658. seleBand = (sourceBands != null) && (destBands != null);
  659. noTransform =
  660. destinationRegion.equals(new Rectangle(0, 0, width, height)) ||
  661. seleBand;
  662. if (!seleBand) {
  663. sourceBands = new int[numBands];
  664. destBands = new int[numBands];
  665. for (int i = 0; i < numBands; i++)
  666. destBands[i] = sourceBands[i] = i;
  667. }
  668. // If the destination is provided, then use it. Otherwise, create new one
  669. bi = param.getDestination();
  670. // Get the image data.
  671. WritableRaster raster = null;
  672. if (bi == null) {
  673. if (sampleModel != null && colorModel != null) {
  674. sampleModel =
  675. sampleModel.createCompatibleSampleModel(destinationRegion.x +
  676. destinationRegion.width,
  677. destinationRegion.y +
  678. destinationRegion.height);
  679. if (seleBand)
  680. sampleModel = sampleModel.createSubsetSampleModel(sourceBands);
  681. raster = Raster.createWritableRaster(sampleModel, new Point());
  682. bi = new BufferedImage(colorModel, raster, false, null);
  683. }
  684. } else {
  685. raster = bi.getWritableTile(0, 0);
  686. sampleModel = bi.getSampleModel();
  687. colorModel = bi.getColorModel();
  688. noTransform &= destinationRegion.equals(raster.getBounds());
  689. }
  690. byte bdata[] = null; // buffer for byte data
  691. short sdata[] = null; // buffer for short data
  692. int idata[] = null; // buffer for int data
  693. // the sampleModel can be null in case of embedded image
  694. if (sampleModel != null) {
  695. if (sampleModel.getDataType() == DataBuffer.TYPE_BYTE)
  696. bdata = (byte[])
  697. ((DataBufferByte)raster.getDataBuffer()).getData();
  698. else if (sampleModel.getDataType() == DataBuffer.TYPE_USHORT)
  699. sdata = (short[])
  700. ((DataBufferUShort)raster.getDataBuffer()).getData();
  701. else if (sampleModel.getDataType() == DataBuffer.TYPE_INT)
  702. idata = (int[])
  703. ((DataBufferInt)raster.getDataBuffer()).getData();
  704. }
  705. // There should only be one tile.
  706. switch(imageType) {
  707. case VERSION_2_1_BIT:
  708. // no compression
  709. read1Bit(bdata);
  710. break;
  711. case VERSION_2_4_BIT:
  712. // no compression
  713. read4Bit(bdata);
  714. break;
  715. case VERSION_2_8_BIT:
  716. // no compression
  717. read8Bit(bdata);
  718. break;
  719. case VERSION_2_24_BIT:
  720. // no compression
  721. read24Bit(bdata);
  722. break;
  723. case VERSION_3_1_BIT:
  724. // 1-bit images cannot be compressed.
  725. read1Bit(bdata);
  726. break;
  727. case VERSION_3_4_BIT:
  728. switch((int)compression) {
  729. case BI_RGB:
  730. read4Bit(bdata);
  731. break;
  732. case BI_RLE4:
  733. readRLE4(bdata);
  734. break;
  735. default:
  736. throw new
  737. IIOException(I18N.getString("BMPImageReader1"));
  738. }
  739. break;
  740. case VERSION_3_8_BIT:
  741. switch((int)compression) {
  742. case BI_RGB:
  743. read8Bit(bdata);
  744. break;
  745. case BI_RLE8:
  746. readRLE8(bdata);
  747. break;
  748. default:
  749. throw new
  750. IIOException(I18N.getString("BMPImageReader1"));
  751. }
  752. break;
  753. case VERSION_3_24_BIT:
  754. // 24-bit images are not compressed
  755. read24Bit(bdata);
  756. break;
  757. case VERSION_3_NT_16_BIT:
  758. read16Bit(sdata);
  759. break;
  760. case VERSION_3_NT_32_BIT:
  761. read32Bit(idata);
  762. break;
  763. case VERSION_3_XP_EMBEDDED:
  764. case VERSION_4_XP_EMBEDDED:
  765. case VERSION_5_XP_EMBEDDED:
  766. bi = readEmbedded((int)compression, bi, param);
  767. break;
  768. case VERSION_4_1_BIT:
  769. read1Bit(bdata);
  770. break;
  771. case VERSION_4_4_BIT:
  772. switch((int)compression) {
  773. case BI_RGB:
  774. read4Bit(bdata);
  775. break;
  776. case BI_RLE4:
  777. readRLE4(bdata);
  778. break;
  779. default:
  780. throw new
  781. IIOException(I18N.getString("BMPImageReader1"));
  782. }
  783. case VERSION_4_8_BIT:
  784. switch((int)compression) {
  785. case BI_RGB:
  786. read8Bit(bdata);
  787. break;
  788. case BI_RLE8:
  789. readRLE8(bdata);
  790. break;
  791. default:
  792. throw new
  793. IIOException(I18N.getString("BMPImageReader1"));
  794. }
  795. break;
  796. case VERSION_4_16_BIT:
  797. read16Bit(sdata);
  798. break;
  799. case VERSION_4_24_BIT:
  800. read24Bit(bdata);
  801. break;
  802. case VERSION_4_32_BIT:
  803. read32Bit(idata);
  804. break;
  805. }
  806. if (abortRequested())
  807. processReadAborted();
  808. else
  809. processImageComplete();
  810. return bi;
  811. }
  812. public boolean canReadRaster() {
  813. return true;
  814. }
  815. public Raster readRaster(int imageIndex,
  816. ImageReadParam param) throws IOException {
  817. BufferedImage bi = read(imageIndex, param);
  818. return bi.getData();
  819. }
  820. private void resetHeaderInfo() {
  821. gotHeader = false;
  822. bi = null;
  823. sampleModel = originalSampleModel = null;
  824. colorModel = originalColorModel = null;
  825. }
  826. public void reset() {
  827. super.reset();
  828. iis = null;
  829. resetHeaderInfo();
  830. }
  831. // Deal with 1 Bit images using IndexColorModels
  832. private void read1Bit(byte[] bdata) throws IOException {
  833. int bytesPerScanline = (width + 7) / 8;
  834. int padding = bytesPerScanline % 4;
  835. if (padding != 0) {
  836. padding = 4 - padding;
  837. }
  838. int lineLength = bytesPerScanline + padding;
  839. if (noTransform) {
  840. int j = isBottomUp ? (height -1)*bytesPerScanline : 0;
  841. for (int i=0; i<height; i++) {
  842. if (abortRequested()) {
  843. break;
  844. }
  845. iis.readFully(bdata, j, bytesPerScanline);
  846. iis.skipBytes(padding);
  847. j += isBottomUp ? -bytesPerScanline : bytesPerScanline;
  848. processImageUpdate(bi, 0, i,
  849. destinationRegion.width, 1, 1, 1,
  850. new int[]{0});
  851. processImageProgress(100.0F * i/destinationRegion.height);
  852. }
  853. } else {
  854. byte[] buf = new byte[lineLength];
  855. int lineStride =
  856. ((MultiPixelPackedSampleModel)sampleModel).getScanlineStride();
  857. if (isBottomUp) {
  858. int lastLine =
  859. sourceRegion.y + (destinationRegion.height - 1) * scaleY;
  860. iis.skipBytes(lineLength * (height - 1 - lastLine));
  861. } else
  862. iis.skipBytes(lineLength * sourceRegion.y);
  863. int skipLength = lineLength * (scaleY - 1);
  864. // cache the values to avoid duplicated computation
  865. int[] srcOff = new int[destinationRegion.width];
  866. int[] destOff = new int[destinationRegion.width];
  867. int[] srcPos = new int[destinationRegion.width];
  868. int[] destPos = new int[destinationRegion.width];
  869. for (int i = destinationRegion.x, x = sourceRegion.x, j = 0;
  870. i < destinationRegion.x + destinationRegion.width;
  871. i++, j++, x += scaleX) {
  872. srcPos[j] = x >> 3;
  873. srcOff[j] = 7 - (x & 7);
  874. destPos[j] = i >> 3;
  875. destOff[j] = 7 - (i & 7);
  876. }
  877. int k = destinationRegion.y * lineStride;
  878. if (isBottomUp)
  879. k += (destinationRegion.height - 1) * lineStride;
  880. for (int j = 0, y = sourceRegion.y;
  881. j < destinationRegion.height; j++, y+=scaleY) {
  882. if (abortRequested())
  883. break;
  884. iis.read(buf, 0, lineLength);
  885. for (int i = 0; i < destinationRegion.width; i++) {
  886. //get the bit and assign to the data buffer of the raster
  887. int v = (buf[srcPos[i]] >> srcOff[i]) & 1;
  888. bdata[k + destPos[i]] |= v << destOff[i];
  889. }
  890. k += isBottomUp ? -lineStride : lineStride;
  891. iis.skipBytes(skipLength);
  892. processImageUpdate(bi, 0, j,
  893. destinationRegion.width, 1, 1, 1,
  894. new int[]{0});
  895. processImageProgress(100.0F*j/destinationRegion.height);
  896. }
  897. }
  898. }
  899. // Method to read a 4 bit BMP image data
  900. private void read4Bit(byte[] bdata) throws IOException {
  901. int bytesPerScanline = (width + 1) / 2;
  902. // Padding bytes at the end of each scanline
  903. int padding = bytesPerScanline % 4;
  904. if (padding != 0)
  905. padding = 4 - padding;
  906. int lineLength = bytesPerScanline + padding;
  907. if (noTransform) {
  908. int j = isBottomUp ? (height -1) * bytesPerScanline : 0;
  909. for (int i=0; i<height; i++) {
  910. if (abortRequested()) {
  911. break;
  912. }
  913. iis.readFully(bdata, j, bytesPerScanline);
  914. iis.skipBytes(padding);
  915. j += isBottomUp ? -bytesPerScanline : bytesPerScanline;
  916. processImageUpdate(bi, 0, i,
  917. destinationRegion.width, 1, 1, 1,
  918. new int[]{0});
  919. processImageProgress(100.0F * i/destinationRegion.height);
  920. }
  921. } else {
  922. byte[] buf = new byte[lineLength];
  923. int lineStride =
  924. ((MultiPixelPackedSampleModel)sampleModel).getScanlineStride();
  925. if (isBottomUp) {
  926. int lastLine =
  927. sourceRegion.y + (destinationRegion.height - 1) * scaleY;
  928. iis.skipBytes(lineLength * (height - 1 - lastLine));
  929. } else
  930. iis.skipBytes(lineLength * sourceRegion.y);
  931. int skipLength = lineLength * (scaleY - 1);
  932. // cache the values to avoid duplicated computation
  933. int[] srcOff = new int[destinationRegion.width];
  934. int[] destOff = new int[destinationRegion.width];
  935. int[] srcPos = new int[destinationRegion.width];
  936. int[] destPos = new int[destinationRegion.width];
  937. for (int i = destinationRegion.x, x = sourceRegion.x, j = 0;
  938. i < destinationRegion.x + destinationRegion.width;
  939. i++, j++, x += scaleX) {
  940. srcPos[j] = x >> 1;
  941. srcOff[j] = (1 - (x & 1)) << 2;
  942. destPos[j] = i >> 1;
  943. destOff[j] = (1 - (i & 1)) << 2;
  944. }
  945. int k = destinationRegion.y * lineStride;
  946. if (isBottomUp)
  947. k += (destinationRegion.height - 1) * lineStride;
  948. for (int j = 0, y = sourceRegion.y;
  949. j < destinationRegion.height; j++, y+=scaleY) {
  950. if (abortRequested())
  951. break;
  952. iis.read(buf, 0, lineLength);
  953. for (int i = 0; i < destinationRegion.width; i++) {
  954. //get the bit and assign to the data buffer of the raster
  955. int v = (buf[srcPos[i]] >> srcOff[i]) & 0x0F;
  956. bdata[k + destPos[i]] |= v << destOff[i];
  957. }
  958. k += isBottomUp ? -lineStride : lineStride;
  959. iis.skipBytes(skipLength);
  960. processImageUpdate(bi, 0, j,
  961. destinationRegion.width, 1, 1, 1,
  962. new int[]{0});
  963. processImageProgress(100.0F*j/destinationRegion.height);
  964. }
  965. }
  966. }
  967. // Method to read 8 bit BMP image data
  968. private void read8Bit(byte[] bdata) throws IOException {
  969. // Padding bytes at the end of each scanline
  970. int padding = width % 4;
  971. if (padding != 0) {
  972. padding = 4 - padding;
  973. }
  974. int lineLength = width + padding;
  975. if (noTransform) {
  976. int j = isBottomUp ? (height -1) * width : 0;
  977. for (int i=0; i<height; i++) {
  978. if (abortRequested()) {
  979. break;
  980. }
  981. iis.readFully(bdata, j, width);
  982. iis.skipBytes(padding);
  983. j += isBottomUp ? -width : width;
  984. processImageUpdate(bi, 0, i,
  985. destinationRegion.width, 1, 1, 1,
  986. new int[]{0});
  987. processImageProgress(100.0F * i/destinationRegion.height);
  988. }
  989. } else {
  990. byte[] buf = new byte[lineLength];
  991. int lineStride =
  992. ((ComponentSampleModel)sampleModel).getScanlineStride();
  993. if (isBottomUp) {
  994. int lastLine =
  995. sourceRegion.y + (destinationRegion.height - 1) * scaleY;
  996. iis.skipBytes(lineLength * (height - 1 - lastLine));
  997. } else
  998. iis.skipBytes(lineLength * sourceRegion.y);
  999. int skipLength = lineLength * (scaleY - 1);
  1000. int k = destinationRegion.y * lineStride;
  1001. if (isBottomUp)
  1002. k += (destinationRegion.height - 1) * lineStride;
  1003. k += destinationRegion.x;
  1004. for (int j = 0, y = sourceRegion.y;
  1005. j < destinationRegion.height; j++, y+=scaleY) {
  1006. if (abortRequested())
  1007. break;
  1008. iis.read(buf, 0, lineLength);
  1009. for (int i = 0, m = sourceRegion.x;
  1010. i < destinationRegion.width; i++, m += scaleX) {
  1011. //get the bit and assign to the data buffer of the raster
  1012. bdata[k + i] = buf[m];
  1013. }
  1014. k += isBottomUp ? -lineStride : lineStride;
  1015. iis.skipBytes(skipLength);
  1016. processImageUpdate(bi, 0, j,
  1017. destinationRegion.width, 1, 1, 1,
  1018. new int[]{0});
  1019. processImageProgress(100.0F*j/destinationRegion.height);
  1020. }
  1021. }
  1022. }
  1023. // Method to read 24 bit BMP image data
  1024. private void read24Bit(byte[] bdata) throws IOException {
  1025. // Padding bytes at the end of each scanline
  1026. // width * bitsPerPixel should be divisible by 32
  1027. int padding = width * 3 % 4;
  1028. if ( padding != 0)
  1029. padding = 4 - padding;
  1030. int lineStride = width * 3;
  1031. int lineLength = lineStride + padding;
  1032. if (noTransform) {
  1033. int j = isBottomUp ? (height -1) * width * 3 : 0;
  1034. for (int i=0; i<height; i++) {
  1035. if (abortRequested()) {
  1036. break;
  1037. }
  1038. iis.readFully(bdata, j, lineStride);
  1039. iis.skipBytes(padding);
  1040. j += isBottomUp ? -lineStride : lineStride;
  1041. processImageUpdate(bi, 0, i,
  1042. destinationRegion.width, 1, 1, 1,
  1043. new int[]{0});
  1044. processImageProgress(100.0F * i/destinationRegion.height);
  1045. }
  1046. } else {
  1047. byte[] buf = new byte[lineLength];
  1048. lineStride =
  1049. ((ComponentSampleModel)sampleModel).getScanlineStride();
  1050. if (isBottomUp) {
  1051. int lastLine =
  1052. sourceRegion.y + (destinationRegion.height - 1) * scaleY;
  1053. iis.skipBytes(lineLength * (height - 1 - lastLine));
  1054. } else
  1055. iis.skipBytes(lineLength * sourceRegion.y);
  1056. int skipLength = lineLength * (scaleY - 1);
  1057. int k = destinationRegion.y * lineStride;
  1058. if (isBottomUp)
  1059. k += (destinationRegion.height - 1) * lineStride;
  1060. k += destinationRegion.x * 3;
  1061. for (int j = 0, y = sourceRegion.y;
  1062. j < destinationRegion.height; j++, y+=scaleY) {
  1063. if (abortRequested())
  1064. break;
  1065. iis.read(buf, 0, lineLength);
  1066. for (int i = 0, m = 3 * sourceRegion.x;
  1067. i < destinationRegion.width; i++, m += 3 * scaleX) {
  1068. //get the bit and assign to the data buffer of the raster
  1069. int n = 3 * i + k;
  1070. for (int b = 0; b < destBands.length; b++)
  1071. bdata[n + destBands[b]] = buf[m + sourceBands[b]];
  1072. }
  1073. k += isBottomUp ? -lineStride : lineStride;
  1074. iis.skipBytes(skipLength);
  1075. processImageUpdate(bi, 0, j,
  1076. destinationRegion.width, 1, 1, 1,
  1077. new int[]{0});
  1078. processImageProgress(100.0F*j/destinationRegion.height);
  1079. }
  1080. }
  1081. }
  1082. private void read16Bit(short sdata[]) throws IOException {
  1083. // Padding bytes at the end of each scanline
  1084. // width * bitsPerPixel should be divisible by 32
  1085. int padding = width * 2 % 4;
  1086. if ( padding != 0)
  1087. padding = 4 - padding;
  1088. int lineLength = width + padding / 2;
  1089. if (noTransform) {
  1090. int j = isBottomUp ? (height -1) * width : 0;
  1091. for (int i=0; i<height; i++) {
  1092. if (abortRequested()) {
  1093. break;
  1094. }
  1095. iis.readFully(sdata, j, width);
  1096. iis.skipBytes(padding);
  1097. j += isBottomUp ? -width : width;
  1098. processImageUpdate(bi, 0, i,
  1099. destinationRegion.width, 1, 1, 1,
  1100. new int[]{0});
  1101. processImageProgress(100.0F * i/destinationRegion.height);
  1102. }
  1103. } else {
  1104. short[] buf = new short[lineLength];
  1105. int lineStride =
  1106. ((SinglePixelPackedSampleModel)sampleModel).getScanlineStride();
  1107. if (isBottomUp) {
  1108. int lastLine =
  1109. sourceRegion.y + (destinationRegion.height - 1) * scaleY;
  1110. iis.skipBytes(lineLength * (height - 1 - lastLine) << 1);
  1111. } else
  1112. iis.skipBytes(lineLength * sourceRegion.y << 1);
  1113. int skipLength = lineLength * (scaleY - 1) << 1;
  1114. int k = destinationRegion.y * lineStride;
  1115. if (isBottomUp)
  1116. k += (destinationRegion.height - 1) * lineStride;
  1117. k += destinationRegion.x;
  1118. for (int j = 0, y = sourceRegion.y;
  1119. j < destinationRegion.height; j++, y+=scaleY) {
  1120. if (abortRequested())
  1121. break;
  1122. iis.readFully(buf, 0, lineLength);
  1123. for (int i = 0, m = sourceRegion.x;
  1124. i < destinationRegion.width; i++, m += scaleX) {
  1125. //get the bit and assign to the data buffer of the raster
  1126. sdata[k + i] = buf[m];
  1127. }
  1128. k += isBottomUp ? -lineStride : lineStride;
  1129. iis.skipBytes(skipLength);
  1130. processImageUpdate(bi, 0, j,
  1131. destinationRegion.width, 1, 1, 1,
  1132. new int[]{0});
  1133. processImageProgress(100.0F*j/destinationRegion.height);
  1134. }
  1135. }
  1136. }
  1137. private void read32Bit(int idata[]) throws IOException {
  1138. if (noTransform) {
  1139. int j = isBottomUp ? (height -1) * width : 0;
  1140. for (int i=0; i<height; i++) {
  1141. if (abortRequested()) {
  1142. break;
  1143. }
  1144. iis.readFully(idata, j, width);
  1145. j += isBottomUp ? -width : width;
  1146. processImageUpdate(bi, 0, i,
  1147. destinationRegion.width, 1, 1, 1,
  1148. new int[]{0});
  1149. processImageProgress(100.0F * i/destinationRegion.height);
  1150. }
  1151. } else {
  1152. int[] buf = new int[width];
  1153. int lineStride =
  1154. ((SinglePixelPackedSampleModel)sampleModel).getScanlineStride();
  1155. if (isBottomUp) {
  1156. int lastLine =
  1157. sourceRegion.y + (destinationRegion.height - 1) * scaleY;
  1158. iis.skipBytes(width * (height - 1 - lastLine) << 2);
  1159. } else
  1160. iis.skipBytes(width * sourceRegion.y << 2);
  1161. int skipLength = width * (scaleY - 1) << 2;
  1162. int k = destinationRegion.y * lineStride;
  1163. if (isBottomUp)
  1164. k += (destinationRegion.height - 1) * lineStride;
  1165. k += destinationRegion.x;
  1166. for (int j = 0, y = sourceRegion.y;
  1167. j < destinationRegion.height; j++, y+=scaleY) {
  1168. if (abortRequested())
  1169. break;
  1170. iis.readFully(buf, 0, width);
  1171. for (int i =

Large files files are truncated, but you can click here to view the full file