1. /*
  2. * @(#)BandedSampleModel.java 1.22 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 image data which is stored in a band interleaved
  19. * fashion and for
  20. * which each sample of a pixel occupies one data element of the DataBuffer.
  21. * It subclasses ComponentSampleModel but provides a more efficent
  22. * implementation for accessing band interleaved image data than is provided
  23. * by ComponentSampleModel. This class should typically be used when working
  24. * with images which store sample data for each band in a different bank of the
  25. * DataBuffer. Accessor methods are provided so that image data can be
  26. * manipulated directly. Pixel stride is the number of
  27. * data array elements between two samples for the same band on the same
  28. * scanline. Scanline stride is the number of data array elements between
  29. * a given sample and the corresponding sample in the same column of the next
  30. * scanline. Band offsets denote the number
  31. * of data array elements from the first data array element of the bank
  32. * of the DataBuffer holding each band to the first sample of the band.
  33. * The bands are numbered from 0 to N-1.
  34. * Bank indices denote the correspondence between a bank of the data buffer
  35. * and a band of image data.
  36. */
  37. public final class BandedSampleModel extends ComponentSampleModel
  38. {
  39. /**
  40. * Constructs a BandedSampleModel with the specified parameters.
  41. * The pixel stride will be one data element. The scanline stride
  42. * will be the same as the width. Each band will be stored in
  43. * a separate bank and all band offsets will be zero.
  44. * @param dataType The data type for storing samples.
  45. * @param w The width (in pixels) of the region of
  46. * image data described.
  47. * @param h The height (in pixels) of the region of image
  48. * data described.
  49. * @param numBands The number of bands for the image data.
  50. */
  51. public BandedSampleModel(int dataType, int w, int h, int numBands) {
  52. super(dataType, w, h, 1, w,
  53. BandedSampleModel.createIndiciesArray(numBands),
  54. BandedSampleModel.createOffsetArray(numBands));
  55. }
  56. /**
  57. * Constructs a BandedSampleModel with the specified parameters.
  58. * The number of bands will be inferred from the lengths of the
  59. * bandOffsets bankIndices arrays, which must be equal. The pixel
  60. * stride will be one data element.
  61. * @param dataType The data type for storing samples.
  62. * @param w The width (in pixels) of the region of
  63. * image data described.
  64. * @param h The height (in pixels) of the region of
  65. * image data described.
  66. * @param numBands The number of bands for the image data.
  67. * @param scanlineStride The line stride of the of the image data.
  68. * @param bankIndices The bank index for each band.
  69. * @param bandOffsets The band offset for each band.
  70. */
  71. public BandedSampleModel(int dataType,
  72. int w, int h,
  73. int scanlineStride,
  74. int bankIndices[],
  75. int bandOffsets[]) {
  76. super(dataType, w, h, 1,scanlineStride, bankIndices, bandOffsets);
  77. }
  78. /**
  79. * Creates a new BandedSampleModel with the specified
  80. * width and height. The new BandedSampleModel will have the same
  81. * number of bands, storage data type, and bank indices
  82. * as this BandedSampleModel. The band offsets will be compressed
  83. * such that the offset between bands will be w*pixelStride and
  84. * the minimum of all of the band offsets is zero.
  85. */
  86. public SampleModel createCompatibleSampleModel(int w, int h) {
  87. int[] bandOffs = orderBands(bandOffsets, w*pixelStride);
  88. SampleModel sampleModel =
  89. new BandedSampleModel(dataType, w, h, w, bankIndices, bandOffs);
  90. return sampleModel;
  91. }
  92. /**
  93. * Creates a new BandedSampleModel with a subset of the bands of this
  94. * BandedSampleModel. The new BandedSampleModel can be
  95. * used with any DataBuffer that the existing BandedSampleModel
  96. * can be used with. The new BandedSampleModel/DataBuffer
  97. * combination will represent an image with a subset of the bands
  98. * of the original BandedSampleModel/DataBuffer combination.
  99. * @throws RasterFormatException if the number of bands is greater than
  100. * the number of banks in this sample model.
  101. */
  102. public SampleModel createSubsetSampleModel(int bands[]) {
  103. if (bands.length > bankIndices.length)
  104. throw new RasterFormatException("There are only " +
  105. bankIndices.length +
  106. " bands");
  107. int newBankIndices[] = new int[bands.length];
  108. int newBandOffsets[] = new int[bands.length];
  109. for (int i=0; i<bands.length; i++) {
  110. newBankIndices[i] = bankIndices[bands[i]];
  111. newBandOffsets[i] = bandOffsets[bands[i]];
  112. }
  113. return new BandedSampleModel(this.dataType, width, height,
  114. this.scanlineStride,
  115. newBankIndices, newBandOffsets);
  116. }
  117. /**
  118. * Creates a DataBuffer that corresponds to this BandedSampleModel,
  119. * The DataBuffer's data type, number of banks, and size
  120. * will be consistent with this BandedSampleModel.
  121. */
  122. public DataBuffer createDataBuffer() {
  123. DataBuffer dataBuffer = null;
  124. int size = scanlineStride * height;
  125. switch (dataType) {
  126. case DataBuffer.TYPE_BYTE:
  127. dataBuffer = new DataBufferByte(size, numBands);
  128. break;
  129. case DataBuffer.TYPE_USHORT:
  130. dataBuffer = new DataBufferUShort(size, numBands);
  131. break;
  132. case DataBuffer.TYPE_INT:
  133. dataBuffer = new DataBufferInt(size, numBands);
  134. break;
  135. }
  136. return dataBuffer;
  137. }
  138. /**
  139. * Returns data for a single pixel in a primitive array of type
  140. * TransferType. For a BandedSampleModel, this will be the same
  141. * as the data type, and samples will be returned one per array
  142. * element. Generally, obj
  143. * should be passed in as null, so that the Object will be created
  144. * automatically and will be of the right primitive data type.
  145. * <p>
  146. * The following code illustrates transferring data for one pixel from
  147. * DataBuffer <code>db1</code>, whose storage layout is described by
  148. * BandedSampleModel <code>bsm1</code>, to DataBuffer <code>db2</code>,
  149. * whose storage layout is described by
  150. * BandedSampleModel <code>bsm2</code>.
  151. * The transfer will generally be more efficient than using
  152. * getPixel/setPixel.
  153. * <pre>
  154. * BandedSampleModel bsm1, bsm2;
  155. * DataBufferInt db1, db2;
  156. * bsm2.setDataElements(x, y, bsm1.getDataElements(x, y, null, db1),
  157. * db2);
  158. * </pre>
  159. * Using getDataElements/setDataElements to transfer between two
  160. * DataBuffer/SampleModel pairs is legitimate if the SampleModels have
  161. * the same number of bands, corresponding bands have the same number of
  162. * bits per sample, and the TransferTypes are the same.
  163. * <p>
  164. * If obj is non-null, it should be a primitive array of type TransferType.
  165. * Otherwise, a ClassCastException is thrown. An
  166. * ArrayIndexOutOfBoundsException may be thrown if the coordinates are
  167. * not in bounds, or if obj is non-null and is not large enough to hold
  168. * the pixel data.
  169. * @param x The X coordinate of the pixel location.
  170. * @param y The Y coordinate of the pixel location.
  171. * @param obj If non-null, a primitive array in which to return
  172. * the pixel data.
  173. * @param data The DataBuffer containing the image data.
  174. */
  175. public Object getDataElements(int x, int y, Object obj, DataBuffer data) {
  176. int type = getTransferType();
  177. int numDataElems = getNumDataElements();
  178. int pixelOffset = y*scanlineStride + x;
  179. switch(type) {
  180. case DataBuffer.TYPE_BYTE:
  181. byte[] bdata;
  182. if (obj == null) {
  183. bdata = new byte[numDataElems];
  184. } else {
  185. bdata = (byte[])obj;
  186. }
  187. for (int i=0; i<numDataElems; i++) {
  188. bdata[i] = (byte)data.getElem(bankIndices[i],
  189. pixelOffset + bandOffsets[i]);
  190. }
  191. obj = (Object)bdata;
  192. break;
  193. case DataBuffer.TYPE_USHORT:
  194. short[] sdata;
  195. if (obj == null) {
  196. sdata = new short[numDataElems];
  197. } else {
  198. sdata = (short[])obj;
  199. }
  200. for (int i=0; i<numDataElems; i++) {
  201. sdata[i] = (short)data.getElem(bankIndices[i],
  202. pixelOffset + bandOffsets[i]);
  203. }
  204. obj = (Object)sdata;
  205. break;
  206. case DataBuffer.TYPE_INT:
  207. int[] idata;
  208. if (obj == null) {
  209. idata = new int[numDataElems];
  210. } else {
  211. idata = (int[])obj;
  212. }
  213. for (int i=0; i<numDataElems; i++) {
  214. idata[i] = data.getElem(bankIndices[i],
  215. pixelOffset + bandOffsets[i]);
  216. }
  217. obj = (Object)idata;
  218. break;
  219. }
  220. return obj;
  221. }
  222. /**
  223. * Returns all samples for the specified pixel in an int array.
  224. * ArrayIndexOutOfBoundsException may be thrown if the coordinates are
  225. * not in bounds.
  226. * @param x The X coordinate of the pixel location.
  227. * @param y The Y coordinate of the pixel location.
  228. * @param iArray If non-null, returns the samples in this array.
  229. * @param data The DataBuffer containing the image data.
  230. */
  231. public int[] getPixel(int x, int y, int iArray[], DataBuffer data) {
  232. int[] pixels;
  233. if (iArray != null) {
  234. pixels = iArray;
  235. } else {
  236. pixels = new int [numBands];
  237. }
  238. int pixelOffset = y*scanlineStride + x;
  239. for (int i=0; i<numBands; i++) {
  240. pixels[i] = data.getElem(bankIndices[i],
  241. pixelOffset + bandOffsets[i]);
  242. }
  243. return pixels;
  244. }
  245. /**
  246. * Returns all samples for the specified rectangle of pixels in
  247. * an int array, one sample per data array element.
  248. * ArrayIndexOutOfBoundsException may be thrown if the coordinates are
  249. * not in bounds.
  250. * @param x The X coordinate of the upper left pixel location.
  251. * @param y The Y coordinate of the upper left pixel location.
  252. * @param w The width of the pixel rectangle.
  253. * @param h The height of the pixel rectangle.
  254. * @param iArray If non-null, returns the samples in this array.
  255. * @param data The DataBuffer containing the image data.
  256. */
  257. public int[] getPixels(int x, int y, int w, int h,
  258. int iArray[], DataBuffer data) {
  259. int[] pixels;
  260. if (iArray != null) {
  261. pixels = iArray;
  262. } else {
  263. pixels = new int[w*h*numBands];
  264. }
  265. for (int k = 0; k < numBands; k++) {
  266. int lineOffset = y*scanlineStride + x + bandOffsets[k];
  267. int srcOffset = k;
  268. int bank = bankIndices[k];
  269. for (int i = 0; i < h; i++) {
  270. int pixelOffset = lineOffset;
  271. for (int j = 0; j < w; j++) {
  272. pixels[srcOffset] = data.getElem(bank, pixelOffset++);
  273. srcOffset += numBands;
  274. }
  275. lineOffset += scanlineStride;
  276. }
  277. }
  278. return pixels;
  279. }
  280. /**
  281. * Returns as int the sample in a specified band for the pixel
  282. * located at (x,y).
  283. * ArrayIndexOutOfBoundsException may be thrown if the coordinates are
  284. * not in bounds.
  285. * @param x The X coordinate of the pixel location.
  286. * @param y The Y coordinate of the pixel location.
  287. * @param b The band to return.
  288. * @param data The DataBuffer containing the image data.
  289. */
  290. public int getSample(int x, int y, int b, DataBuffer data) {
  291. int sample =
  292. data.getElem(bankIndices[b],
  293. y*scanlineStride + x + bandOffsets[b]);
  294. return sample;
  295. }
  296. /**
  297. * Returns the samples in a specified band for the specified rectangle
  298. * of pixels in an int array, one sample per data array element.
  299. * ArrayIndexOutOfBoundsException may be thrown if the coordinates are
  300. * not in bounds.
  301. * @param x The X coordinate of the upper left pixel location.
  302. * @param y The Y coordinate of the upper left pixel location.
  303. * @param w The width of the pixel rectangle.
  304. * @param h The height of the pixel rectangle.
  305. * @param b The band to return.
  306. * @param iArray If non-null, returns the samples in this array.
  307. * @param data The DataBuffer containing the image data.
  308. */
  309. public int[] getSamples(int x, int y, int w, int h, int b,
  310. int iArray[], DataBuffer data) {
  311. int samples[];
  312. if (iArray != null) {
  313. samples = iArray;
  314. } else {
  315. samples = new int [w*h];
  316. }
  317. int lineOffset = y*scanlineStride + x + bandOffsets[b];
  318. int srcOffset = 0;
  319. int bank = bankIndices[b];
  320. for (int i = 0; i < h; i++) {
  321. int sampleOffset = lineOffset;
  322. for (int j = 0; j < w; j++) {
  323. samples[srcOffset++] = data.getElem(bank, sampleOffset++);
  324. }
  325. lineOffset += scanlineStride;
  326. }
  327. return samples;
  328. }
  329. /**
  330. * Sets the data for a single pixel in the specified DataBuffer from a
  331. * primitive array of type TransferType. For a BandedSampleModel,
  332. * this will be the same as the data type, and samples are transferred
  333. * one per array element.
  334. * <p>
  335. * The following code illustrates transferring data for one pixel from
  336. * DataBuffer <code>db1</code>, whose storage layout is described by
  337. * BandedSampleModel <code>bsm1</code>, to DataBuffer <code>db2</code>,
  338. * whose storage layout is described by
  339. * BandedSampleModel <code>bsm2</code>.
  340. * The transfer will generally be more efficient than using
  341. * getPixel/setPixel.
  342. * <pre>
  343. * BandedSampleModel bsm1, bsm2;
  344. * DataBufferInt db1, db2;
  345. * bsm2.setDataElements(x, y, bsm1.getDataElements(x, y, null, db1),
  346. * db2);
  347. * </pre>
  348. * Using getDataElements/setDataElements to transfer between two
  349. * DataBuffer/SampleModel pairs is legitimate if the SampleModels have
  350. * the same number of bands, corresponding bands have the same number of
  351. * bits per sample, and the TransferTypes are the same.
  352. * <p>
  353. * obj must be a primitive array of type TransferType. Otherwise,
  354. * a ClassCastException is thrown. An
  355. * ArrayIndexOutOfBoundsException may be thrown if the coordinates are
  356. * not in bounds, or if obj is not large enough to hold the pixel data.
  357. * @param x The X coordinate of the pixel location.
  358. * @param y The Y coordinate of the pixel location.
  359. * @param obj If non-null, returns the primitive array in this object.
  360. * @param data The DataBuffer containing the image data.
  361. */
  362. public void setDataElements(int x, int y, Object obj, DataBuffer data) {
  363. int type = getTransferType();
  364. int numDataElems = getNumDataElements();
  365. int pixelOffset = y*scanlineStride + x;
  366. switch(type) {
  367. case DataBuffer.TYPE_BYTE:
  368. byte[] barray = (byte[])obj;
  369. for (int i=0; i<numDataElems; i++) {
  370. data.setElem(bankIndices[i], pixelOffset + bandOffsets[i],
  371. ((int)barray[i])&0xff);
  372. }
  373. break;
  374. case DataBuffer.TYPE_USHORT:
  375. short[] sarray = (short[])obj;
  376. for (int i=0; i<numDataElems; i++) {
  377. data.setElem(bankIndices[i], pixelOffset + bandOffsets[i],
  378. ((int)sarray[i])&0xffff);
  379. }
  380. break;
  381. case DataBuffer.TYPE_INT:
  382. int[] iarray = (int[])obj;
  383. for (int i=0; i<numDataElems; i++) {
  384. data.setElem(bankIndices[i], pixelOffset + bandOffsets[i],
  385. iarray[i]);
  386. }
  387. break;
  388. }
  389. }
  390. /**
  391. * Sets a pixel in the DataBuffer using an int array of samples for input.
  392. * ArrayIndexOutOfBoundsException may be thrown if the coordinates are
  393. * not in bounds.
  394. * @param x The X coordinate of the pixel location.
  395. * @param y The Y coordinate of the pixel location.
  396. * @param iArray The input samples in an int array.
  397. * @param data The DataBuffer containing the image data.
  398. */
  399. public void setPixel(int x, int y, int iArray[], DataBuffer data) {
  400. int pixelOffset = y*scanlineStride + x;
  401. for (int i=0; i<numBands; i++) {
  402. data.setElem(bankIndices[i], pixelOffset + bandOffsets[i],
  403. iArray[i]);
  404. }
  405. }
  406. /**
  407. * Sets all samples for a rectangle of pixels from an int array containing
  408. * one sample per array element.
  409. * ArrayIndexOutOfBoundsException may be thrown if the coordinates are
  410. * not in bounds.
  411. * @param x The X coordinate of the upper left pixel location.
  412. * @param y The Y coordinate of the upper left pixel location.
  413. * @param w The width of the pixel rectangle.
  414. * @param h The height of the pixel rectangle.
  415. * @param iArray The input samples in an int array.
  416. * @param data The DataBuffer containing the image data.
  417. */
  418. public void setPixels(int x, int y, int w, int h,
  419. int iArray[], DataBuffer data) {
  420. for (int k = 0; k < numBands; k++) {
  421. int lineOffset = y*scanlineStride + x + bandOffsets[k];
  422. int srcOffset = k;
  423. int bank = bankIndices[k];
  424. for (int i = 0; i < h; i++) {
  425. int pixelOffset = lineOffset;
  426. for (int j = 0; j < w; j++) {
  427. data.setElem(bank, pixelOffset++, iArray[srcOffset]);
  428. srcOffset += numBands;
  429. }
  430. lineOffset += scanlineStride;
  431. }
  432. }
  433. }
  434. /**
  435. * Sets a sample in the specified band for the pixel located at (x,y)
  436. * in the DataBuffer using an int for input.
  437. * ArrayIndexOutOfBoundsException may be thrown if the coordinates are
  438. * not in bounds.
  439. * @param x The X coordinate of the pixel location.
  440. * @param y The Y coordinate of the pixel location.
  441. * @param b The band to set.
  442. * @param s The input sample as an int.
  443. * @param data The DataBuffer containing the image data.
  444. */
  445. public void setSample(int x, int y, int b, int s,
  446. DataBuffer data) {
  447. data.setElem(bankIndices[b],
  448. y*scanlineStride + x + bandOffsets[b], s);
  449. }
  450. /**
  451. * Sets the samples in the specified band for the specified rectangle
  452. * of pixels from an int array containing one sample per data array element.
  453. * ArrayIndexOutOfBoundsException may be thrown if the coordinates are
  454. * not in bounds.
  455. * @param x The X coordinate of the upper left pixel location.
  456. * @param y The Y coordinate of the upper left pixel location.
  457. * @param w The width of the pixel rectangle.
  458. * @param h The height of the pixel rectangle.
  459. * @param b The band to set.
  460. * @param iArray The input sample array.
  461. * @param data The DataBuffer containing the image data.
  462. */
  463. public void setSamples(int x, int y, int w, int h, int b,
  464. int iArray[], DataBuffer data) {
  465. int lineOffset = y*scanlineStride + x + bandOffsets[b];
  466. int srcOffset = 0;
  467. int bank = bankIndices[b];
  468. for (int i = 0; i < h; i++) {
  469. int sampleOffset = lineOffset;
  470. for (int j = 0; j < w; j++) {
  471. data.setElem(bank, sampleOffset++, iArray[srcOffset++]);
  472. }
  473. lineOffset += scanlineStride;
  474. }
  475. }
  476. private static int[] createOffsetArray(int numBands) {
  477. int[] bandOffsets = new int[numBands];
  478. for (int i=0; i < numBands; i++) {
  479. bandOffsets[i] = 0;
  480. }
  481. return bandOffsets;
  482. }
  483. private static int[] createIndiciesArray(int numBands) {
  484. int[] bankIndicies = new int[numBands];
  485. for (int i=0; i < numBands; i++) {
  486. bankIndicies[i] = i;
  487. }
  488. return bankIndicies;
  489. }
  490. }