1. /*
  2. * @(#)SinglePixelPackedSampleModel.java 1.26 01/11/29
  3. *
  4. * Copyright 2002 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. /* ****************************************************************
  8. ******************************************************************
  9. ******************************************************************
  10. *** COPYRIGHT (c) Eastman Kodak Company, 1997
  11. *** As an unpublished work pursuant to Title 17 of the United
  12. *** States Code. All rights reserved.
  13. ******************************************************************
  14. ******************************************************************
  15. ******************************************************************/
  16. package java.awt.image;
  17. /**
  18. * This class represents pixel data packed such that the N samples which make
  19. * up a single pixel are stored in a single data array element, and each data
  20. * data array element holds samples for only one pixel.
  21. * All data array elements reside
  22. * in the first bank of a DataBuffer. Accessor methods are provided so
  23. * that the image data can be manipulated directly. Scanline stride is the
  24. * number of data array elements between a given sample and the corresponding
  25. * sample in the same column of the next scanline. Bit masks are the masks
  26. * required to extract the samples representing the bands of the pixel.
  27. * Bit offsets are the offsets in bits into the data array
  28. * element of the samples representing the bands of the pixel.
  29. * <p>
  30. * The following code illustrates extracting the bits of the sample
  31. * representing band <code>b</code> for pixel <code>x,y</code>
  32. * from DataBuffer <code>data</code>:
  33. * <pre>
  34. * int sample = data.getElem(y * scanlineStride + x);
  35. * sample = (sample & bitMasks[b]) >>> bitOffsets[b];
  36. * </pre>
  37. */
  38. public class SinglePixelPackedSampleModel extends SampleModel
  39. {
  40. /** Bit masks for all bands of the image data. */
  41. private int bitMasks[];
  42. /** Bit Offsets for all bands of the image data. */
  43. private int bitOffsets[];
  44. /** Bit sizes for all the bands of the image data. */
  45. private int bitSizes[];
  46. /** Maximum bit size. */
  47. private int maxBitSize;
  48. /** Line stride of the region of image data described by this
  49. * SinglePixelPackedSampleModel.
  50. */
  51. private int scanlineStride;
  52. private static native void initIDs();
  53. static {
  54. ColorModel.loadLibraries();
  55. initIDs();
  56. }
  57. /**
  58. * Constructs a SinglePixelPackedSampleModel with bitMasks.length bands.
  59. * Each sample is stored in a data array element in the position of
  60. * its corresponding bit mask. Each bit mask must be contiguous and
  61. * masks must not overlap.
  62. * @param dataType The data type for storing samples.
  63. * @param w The width (in pixels) of the region of the
  64. * image data described.
  65. * @param h The height (in pixels) of the region of the
  66. * image data described.
  67. * @param bitMasks The bit masks for all bands.
  68. */
  69. public SinglePixelPackedSampleModel(int dataType, int w, int h,
  70. int bitMasks[]) {
  71. this(dataType, w, h, w, bitMasks);
  72. }
  73. /**
  74. * Constructs a SinglePixelPackedSampleModel with bitMasks.length bands
  75. * and a scanline stride equal to scanlineStride data array elements.
  76. * Each sample is stored in a data array element in the position of
  77. * its corresponding bit mask. Each bit mask must be contiguous and
  78. * masks must not overlap.
  79. * @param dataType The data type for storing samples.
  80. * @param w The width (in pixels) of the region of
  81. * image data described.
  82. * @param h The height (in pixels) of the region of
  83. * image data described.
  84. * @param scanlineStride The line stride of the image data.
  85. * @param bitMasks The bit masks for all bands.
  86. * @throws IllegalArgumentException if any mask in
  87. * <code>bitMask</code> is not contiguous
  88. */
  89. public SinglePixelPackedSampleModel(int dataType, int w, int h,
  90. int scanlineStride, int bitMasks[]) {
  91. super(dataType, w, h, bitMasks.length);
  92. this.dataType = dataType;
  93. this.bitMasks = (int[]) bitMasks.clone();
  94. this.scanlineStride = scanlineStride;
  95. this.bitOffsets = new int[numBands];
  96. this.bitSizes = new int[numBands];
  97. this.maxBitSize = 0;
  98. for (int i=0; i<numBands; i++) {
  99. int bitOffset = 0, bitSize = 0, mask;
  100. mask = bitMasks[i];
  101. if (mask != 0) {
  102. while ((mask & 1) == 0) {
  103. mask = mask >>> 1;
  104. bitOffset++;
  105. }
  106. while ((mask & 1) == 1) {
  107. mask = mask >>> 1;
  108. bitSize++;
  109. }
  110. if (mask != 0) {
  111. throw new IllegalArgumentException("Mask "+bitMasks[i]+
  112. " must be contiguous");
  113. }
  114. }
  115. bitOffsets[i] = bitOffset;
  116. bitSizes[i] = bitSize;
  117. if (bitSize > maxBitSize) {
  118. maxBitSize = bitSize;
  119. }
  120. }
  121. }
  122. /**
  123. * Returns the number of data elements needed to transfer one pixel
  124. * via the getDataElements and setDataElements methods.
  125. * For a SinglePixelPackedSampleModel, this is one.
  126. */
  127. public int getNumDataElements() {
  128. return 1;
  129. }
  130. /**
  131. * Returns the size of the buffer (in data array elements)
  132. * needed for a data buffer that matches this
  133. * SinglePixelPackedSampleModel.
  134. */
  135. private long getBufferSize() {
  136. long size = scanlineStride * (height-1) + width;
  137. return size;
  138. }
  139. /**
  140. * This creates a new SinglePixelPackedSampleModel with the specified
  141. * width and height. The new SinglePixelPackedSampleModel will have the
  142. * same storage data type and bit masks as this
  143. * SinglePixelPackedSampleModel.
  144. */
  145. public SampleModel createCompatibleSampleModel(int w, int h) {
  146. SampleModel sampleModel = new SinglePixelPackedSampleModel(dataType, w, h,
  147. bitMasks);
  148. return sampleModel;
  149. }
  150. /**
  151. * Creates a DataBuffer that corresponds to this
  152. * SinglePixelPackedSampleModel. The DataBuffer's data type and size
  153. * will be consistent with this SinglePixelPackedSampleModel. The
  154. * DataBuffer will have a single bank.
  155. */
  156. public DataBuffer createDataBuffer() {
  157. DataBuffer dataBuffer = null;
  158. int size = (int)getBufferSize();
  159. switch (dataType) {
  160. case DataBuffer.TYPE_BYTE:
  161. dataBuffer = new DataBufferByte(size);
  162. break;
  163. case DataBuffer.TYPE_USHORT:
  164. dataBuffer = new DataBufferUShort(size);
  165. break;
  166. case DataBuffer.TYPE_INT:
  167. dataBuffer = new DataBufferInt(size);
  168. break;
  169. }
  170. return dataBuffer;
  171. }
  172. /** Returns the number of bits per sample for all bands. */
  173. public int[] getSampleSize() {
  174. int mask;
  175. int sampleSize[] = new int [numBands];
  176. for (int i=0; i<numBands; i++) {
  177. sampleSize[i] = 0;
  178. mask = bitMasks[i] >>> bitOffsets[i];
  179. while ((mask & 1) != 0) {
  180. sampleSize[i] ++;
  181. mask = mask >>> 1;
  182. }
  183. }
  184. return sampleSize;
  185. }
  186. /** Returns the number of bits per sample for the specified band. */
  187. public int getSampleSize(int band) {
  188. int sampleSize = 0;
  189. int mask = bitMasks[band] >>> bitOffsets[band];
  190. while ((mask & 1) != 0) {
  191. sampleSize ++;
  192. mask = mask >>> 1;
  193. }
  194. return sampleSize;
  195. }
  196. /** Returns the offset (in data array elements) of pixel (x,y).
  197. * The data element containing pixel <code>x,y</code>
  198. * can be retrieved from a DataBuffer <code>data</code> with a
  199. * SinglePixelPackedSampleModel <code>sppsm</code> as:
  200. * <pre>
  201. * data.getElem(sppsm.getOffset(x, y));
  202. * </pre>
  203. */
  204. public int getOffset(int x, int y) {
  205. int offset = y * scanlineStride + x;
  206. return offset;
  207. }
  208. /** Returns the bit offsets into the data array element representing
  209. * a pixel for all bands. */
  210. public int [] getBitOffsets() {
  211. return (int[])bitOffsets.clone();
  212. }
  213. /** Returns the bit masks for all bands. */
  214. public int [] getBitMasks() {
  215. return (int[])bitMasks.clone();
  216. }
  217. /** Returns the scanline stride of this SinglePixelPackedSampleModel. */
  218. public int getScanlineStride() {
  219. return scanlineStride;
  220. }
  221. /**
  222. * This creates a new SinglePixelPackedSampleModel with a subset of the
  223. * bands of this SinglePixelPackedSampleModel. The new
  224. * SinglePixelPackedSampleModel can be used with any DataBuffer that the
  225. * existing SinglePixelPackedSampleModel can be used with. The new
  226. * SinglePixelPackedSampleModel/DataBuffer combination will represent
  227. * an image with a subset of the bands of the original
  228. * SinglePixelPackedSampleModel/DataBuffer combination.
  229. * @exception RasterFormatException if the length of the bands argument is
  230. * greater than the number of bands in
  231. * the sample model.
  232. */
  233. public SampleModel createSubsetSampleModel(int bands[]) {
  234. if (bands.length > numBands)
  235. throw new RasterFormatException("There are only " +
  236. numBands +
  237. " bands");
  238. int newBitMasks[] = new int[bands.length];
  239. for (int i=0; i<bands.length; i++)
  240. newBitMasks[i] = bitMasks[bands[i]];
  241. return new SinglePixelPackedSampleModel(this.dataType, width, height,
  242. this.scanlineStride, newBitMasks);
  243. }
  244. /**
  245. * Returns data for a single pixel in a primitive array of type
  246. * TransferType. For a SinglePixelPackedSampleModel, the array will
  247. * have one element, and the type will be the same as the storage
  248. * data type. Generally, obj
  249. * should be passed in as null, so that the Object will be created
  250. * automatically and will be of the right primitive data type.
  251. * <p>
  252. * The following code illustrates transferring data for one pixel from
  253. * DataBuffer <code>db1</code>, whose storage layout is described by
  254. * SinglePixelPackedSampleModel <code>sppsm1</code>, to
  255. * DataBuffer <code>db2</code>, whose storage layout is described by
  256. * SinglePixelPackedSampleModel <code>sppsm2</code>.
  257. * The transfer will generally be more efficient than using
  258. * getPixel/setPixel.
  259. * <pre>
  260. * SinglePixelPackedSampleModel sppsm1, sppsm2;
  261. * DataBufferInt db1, db2;
  262. * sppsm2.setDataElements(x, y, sppsm1.getDataElements(x, y, null,
  263. * db1), db2);
  264. * </pre>
  265. * Using getDataElements/setDataElements to transfer between two
  266. * DataBuffer/SampleModel pairs is legitimate if the SampleModels have
  267. * the same number of bands, corresponding bands have the same number of
  268. * bits per sample, and the TransferTypes are the same.
  269. * <p>
  270. * If obj is non-null, it should be a primitive array of type TransferType.
  271. * Otherwise, a ClassCastException is thrown. An
  272. * ArrayIndexOutOfBoundsException may be thrown if the coordinates are
  273. * not in bounds, or if obj is non-null and is not large enough to hold
  274. * the pixel data.
  275. * @param x The X coordinate of the pixel location.
  276. * @param y The Y coordinate of the pixel location.
  277. * @param obj If non-null, a primitive array in which to return
  278. * the pixel data.
  279. * @param data The DataBuffer containing the image data.
  280. */
  281. public Object getDataElements(int x, int y, Object obj, DataBuffer data) {
  282. int type = getTransferType();
  283. switch(type) {
  284. case DataBuffer.TYPE_BYTE:
  285. byte[] bdata;
  286. if (obj == null)
  287. bdata = new byte[1];
  288. else
  289. bdata = (byte[])obj;
  290. bdata[0] = (byte)data.getElem(y * scanlineStride + x);
  291. obj = (Object)bdata;
  292. break;
  293. case DataBuffer.TYPE_USHORT:
  294. short[] sdata;
  295. if (obj == null)
  296. sdata = new short[1];
  297. else
  298. sdata = (short[])obj;
  299. sdata[0] = (short)data.getElem(y * scanlineStride + x);
  300. obj = (Object)sdata;
  301. break;
  302. case DataBuffer.TYPE_INT:
  303. int[] idata;
  304. if (obj == null)
  305. idata = new int[1];
  306. else
  307. idata = (int[])obj;
  308. idata[0] = data.getElem(y * scanlineStride + x);
  309. obj = (Object)idata;
  310. break;
  311. }
  312. return obj;
  313. }
  314. /**
  315. * Returns all samples in for the specified pixel in an int array.
  316. * ArrayIndexOutOfBoundsException may be thrown if the coordinates are
  317. * not in bounds.
  318. * @param x The X coordinate of the pixel location.
  319. * @param y The Y coordinate of the pixel location.
  320. * @param iArray If non-null, returns the samples in this array
  321. * @param data The DataBuffer containing the image data.
  322. */
  323. public int [] getPixel(int x, int y, int iArray[], DataBuffer data) {
  324. int pixels[];
  325. if (iArray == null) {
  326. pixels = new int [numBands];
  327. } else {
  328. pixels = iArray;
  329. }
  330. int value = data.getElem(y * scanlineStride + x);
  331. for (int i=0; i<numBands; i++) {
  332. pixels[i] = (value & bitMasks[i]) >>> bitOffsets[i];
  333. }
  334. return pixels;
  335. }
  336. /**
  337. * Returns all samples for the specified rectangle of pixels in
  338. * an int array, one sample per array element.
  339. * ArrayIndexOutOfBoundsException may be thrown if the coordinates are
  340. * not in bounds.
  341. * @param x The X coordinate of the upper left pixel location.
  342. * @param y The Y coordinate of the upper left pixel location.
  343. * @param w The width of the pixel rectangle.
  344. * @param h The height of the pixel rectangle.
  345. * @param iArray If non-null, returns the samples in this array.
  346. * @param data The DataBuffer containing the image data.
  347. */
  348. public int[] getPixels(int x, int y, int w, int h,
  349. int iArray[], DataBuffer data) {
  350. int pixels[];
  351. if (iArray != null) {
  352. pixels = iArray;
  353. } else {
  354. pixels = new int [w*h*numBands];
  355. }
  356. int lineOffset = y*scanlineStride + x;
  357. int dstOffset = 0;
  358. for (int i = 0; i < h; i++) {
  359. for (int j = 0; j < w; j++) {
  360. int value = data.getElem(lineOffset+j);
  361. for (int k=0; k < numBands; k++) {
  362. pixels[dstOffset++] =
  363. ((value & bitMasks[k]) >>> bitOffsets[k]);
  364. }
  365. }
  366. lineOffset += scanlineStride;
  367. }
  368. return pixels;
  369. }
  370. /**
  371. * Returns as int the sample in a specified band for the pixel
  372. * located at (x,y).
  373. * ArrayIndexOutOfBoundsException may be thrown if the coordinates are
  374. * not in bounds.
  375. * @param x The X coordinate of the pixel location.
  376. * @param y The Y coordinate of the pixel location.
  377. * @param b The band to return.
  378. * @param data The DataBuffer containing the image data.
  379. */
  380. public int getSample(int x, int y, int b, DataBuffer data) {
  381. int sample = data.getElem(y * scanlineStride + x);
  382. return ((sample & bitMasks[b]) >>> bitOffsets[b]);
  383. }
  384. /**
  385. * Returns the samples for a specified band for the specified rectangle
  386. * of pixels in an int array, one sample per array element.
  387. * ArrayIndexOutOfBoundsException may be thrown if the coordinates are
  388. * not in bounds.
  389. * @param x The X coordinate of the upper left pixel location.
  390. * @param y The Y coordinate of the upper left pixel location.
  391. * @param w The width of the pixel rectangle.
  392. * @param h The height of the pixel rectangle.
  393. * @param b The band to return.
  394. * @param iArray If non-null, returns the samples in this array.
  395. * @param data The DataBuffer containing the image data.
  396. */
  397. public int[] getSamples(int x, int y, int w, int h, int b,
  398. int iArray[], DataBuffer data) {
  399. int samples[];
  400. if (iArray != null) {
  401. samples = iArray;
  402. } else {
  403. samples = new int [w*h];
  404. }
  405. int lineOffset = y*scanlineStride + x;
  406. int dstOffset = 0;
  407. for (int i = 0; i < h; i++) {
  408. for (int j = 0; j < w; j++) {
  409. int value = data.getElem(lineOffset+j);
  410. samples[dstOffset++] =
  411. ((value & bitMasks[b]) >>> bitOffsets[b]);
  412. }
  413. lineOffset += scanlineStride;
  414. }
  415. return samples;
  416. }
  417. /**
  418. * Sets the data for a single pixel in the specified DataBuffer from a
  419. * primitive array of type TransferType. For a
  420. * SinglePixelPackedSampleModel, only the first element of the array
  421. * will hold valid data, and the type of the array must be the same as
  422. * the storage data type of the SinglePixelPackedSampleModel.
  423. * <p>
  424. * The following code illustrates transferring data for one pixel from
  425. * DataBuffer <code>db1</code>, whose storage layout is described by
  426. * SinglePixelPackedSampleModel <code>sppsm1</code>,
  427. * to DataBuffer <code>db2</code>, whose storage layout is described by
  428. * SinglePixelPackedSampleModel <code>sppsm2</code>.
  429. * The transfer will generally be more efficient than using
  430. * getPixel/setPixel.
  431. * <pre>
  432. * SinglePixelPackedSampleModel sppsm1, sppsm2;
  433. * DataBufferInt db1, db2;
  434. * sppsm2.setDataElements(x, y, sppsm1.getDataElements(x, y, null,
  435. * db1), db2);
  436. * </pre>
  437. * Using getDataElements/setDataElements to transfer between two
  438. * DataBuffer/SampleModel pairs is legitimate if the SampleModels have
  439. * the same number of bands, corresponding bands have the same number of
  440. * bits per sample, and the TransferTypes are the same.
  441. * <p>
  442. * obj must be a primitive array of type TransferType. Otherwise,
  443. * a ClassCastException is thrown. An
  444. * ArrayIndexOutOfBoundsException may be thrown if the coordinates are
  445. * not in bounds, or if obj is not large enough to hold the pixel data.
  446. * @param x The X coordinate of the pixel location.
  447. * @param y The Y coordinate of the pixel location.
  448. * @param obj A primitive array containing pixel data.
  449. * @param data The DataBuffer containing the image data.
  450. */
  451. public void setDataElements(int x, int y, Object obj, DataBuffer data) {
  452. int type = getTransferType();
  453. switch(type) {
  454. case DataBuffer.TYPE_BYTE:
  455. byte[] barray = (byte[])obj;
  456. data.setElem(y*scanlineStride+x, ((int)barray[0])&0xff);
  457. break;
  458. case DataBuffer.TYPE_USHORT:
  459. short[] sarray = (short[])obj;
  460. data.setElem(y*scanlineStride+x, ((int)sarray[0])&0xffff);
  461. break;
  462. case DataBuffer.TYPE_INT:
  463. int[] iarray = (int[])obj;
  464. data.setElem(y*scanlineStride+x, iarray[0]);
  465. break;
  466. }
  467. }
  468. /**
  469. * Sets a pixel in the DataBuffer using an int array of samples for input.
  470. * ArrayIndexOutOfBoundsException may be thrown if the coordinates are
  471. * not in bounds.
  472. * @param x The X coordinate of the pixel location.
  473. * @param y The Y coordinate of the pixel location.
  474. * @param iArray The input samples in an int array.
  475. * @param data The DataBuffer containing the image data.
  476. */
  477. public void setPixel(int x, int y,
  478. int iArray[],
  479. DataBuffer data) {
  480. int value = 0;
  481. for (int i=0; i < numBands; i++) {
  482. value |= ((iArray[i] << bitOffsets[i]) & bitMasks[i]);
  483. }
  484. data.setElem(y*scanlineStride+x, value);
  485. }
  486. /**
  487. * Sets all samples for a rectangle of pixels from an int array containing
  488. * one sample per array element.
  489. * ArrayIndexOutOfBoundsException may be thrown if the coordinates are
  490. * not in bounds.
  491. * @param x The X coordinate of the upper left pixel location.
  492. * @param y The Y coordinate of the upper left pixel location.
  493. * @param w The width of the pixel rectangle.
  494. * @param h The height of the pixel rectangle.
  495. * @param iArray The input samples in an int array.
  496. * @param data The DataBuffer containing the image data.
  497. */
  498. public void setPixels(int x, int y, int w, int h,
  499. int iArray[], DataBuffer data) {
  500. int lineOffset = y*scanlineStride + x;
  501. int srcOffset = 0;
  502. for (int i = 0; i < h; i++) {
  503. for (int j = 0; j < w; j++) {
  504. int value = 0;
  505. for (int k=0; k < numBands; k++) {
  506. value |= ((iArray[srcOffset++] << bitOffsets[k])
  507. & bitMasks[k]);
  508. }
  509. data.setElem(lineOffset+j,value);
  510. }
  511. lineOffset += scanlineStride;
  512. }
  513. }
  514. /**
  515. * Sets a sample in the specified band for the pixel located at (x,y)
  516. * in the DataBuffer using an int for input.
  517. * ArrayIndexOutOfBoundsException may be thrown if the coordinates are
  518. * not in bounds.
  519. * @param x The X coordinate of the pixel location.
  520. * @param y The Y coordinate of the pixel location.
  521. * @param b The band to set.
  522. * @param s The input sample as an int.
  523. * @param data The DataBuffer containing the image data.
  524. */
  525. public void setSample(int x, int y, int b, int s,
  526. DataBuffer data) {
  527. int value = data.getElem(y*scanlineStride + x);
  528. value &= ~bitMasks[b];
  529. value |= (s << bitOffsets[b]) & bitMasks[b];
  530. data.setElem(y*scanlineStride + x,value);
  531. }
  532. /**
  533. * Sets the samples in the specified band for the specified rectangle
  534. * of pixels from an int array containing one sample per array element.
  535. * ArrayIndexOutOfBoundsException may be thrown if the coordinates are
  536. * not in bounds.
  537. * @param x The X coordinate of the upper left pixel location.
  538. * @param y The Y coordinate of the upper left pixel location.
  539. * @param w The width of the pixel rectangle.
  540. * @param h The height of the pixel rectangle.
  541. * @param b The band to set.
  542. * @param iArray The input samples in an int array.
  543. * @param data The DataBuffer containing the image data.
  544. */
  545. public void setSamples(int x, int y, int w, int h, int b,
  546. int iArray[], DataBuffer data) {
  547. int lineOffset = y*scanlineStride + x;
  548. int srcOffset = 0;
  549. for (int i = 0; i < h; i++) {
  550. for (int j = 0; j < w; j++) {
  551. int value = data.getElem(lineOffset+j);
  552. value &= ~bitMasks[b];
  553. int sample = iArray[srcOffset++];
  554. value |= ((int)sample << bitOffsets[b]) & bitMasks[b];
  555. data.setElem(lineOffset+j,value);
  556. }
  557. lineOffset += scanlineStride;
  558. }
  559. }
  560. }