001: /*
002: * $RCSfile: ImgDataConverter.java,v $
003: * $Revision: 1.1 $
004: * $Date: 2005/02/11 05:02:13 $
005: * $State: Exp $
006: *
007: * Interface: ImgDataConverter
008: *
009: * Description: The abstract class for classes that provide
010: * Image Data Convertres (int -> float, float->int).
011: *
012: *
013: *
014: * COPYRIGHT:
015: *
016: * This software module was originally developed by Raphaël Grosbois and
017: * Diego Santa Cruz (Swiss Federal Institute of Technology-EPFL); Joel
018: * Askelöf (Ericsson Radio Systems AB); and Bertrand Berthelot, David
019: * Bouchard, Félix Henry, Gerard Mozelle and Patrice Onno (Canon Research
020: * Centre France S.A) in the course of development of the JPEG2000
021: * standard as specified by ISO/IEC 15444 (JPEG 2000 Standard). This
022: * software module is an implementation of a part of the JPEG 2000
023: * Standard. Swiss Federal Institute of Technology-EPFL, Ericsson Radio
024: * Systems AB and Canon Research Centre France S.A (collectively JJ2000
025: * Partners) agree not to assert against ISO/IEC and users of the JPEG
026: * 2000 Standard (Users) any of their rights under the copyright, not
027: * including other intellectual property rights, for this software module
028: * with respect to the usage by ISO/IEC and Users of this software module
029: * or modifications thereof for use in hardware or software products
030: * claiming conformance to the JPEG 2000 Standard. Those intending to use
031: * this software module in hardware or software products are advised that
032: * their use may infringe existing patents. The original developers of
033: * this software module, JJ2000 Partners and ISO/IEC assume no liability
034: * for use of this software module or modifications thereof. No license
035: * or right to this software module is granted for non JPEG 2000 Standard
036: * conforming products. JJ2000 Partners have full right to use this
037: * software module for his/her own purpose, assign or donate this
038: * software module to any third party and to inhibit third parties from
039: * using this software module for non JPEG 2000 Standard conforming
040: * products. This copyright notice must be included in all copies or
041: * derivative works of this software module.
042: *
043: * Copyright (c) 1999/2000 JJ2000 Partners.
044: * */
045: package jj2000.j2k.image;
046:
047: import jj2000.j2k.image.*;
048: import jj2000.j2k.*;
049:
050: /**
051: * This class is responsible of all data type conversions. It should be used,
052: * at encoder side, between Tiler and ForwardWT modules and, at decoder side,
053: * between InverseWT/CompDemixer and ImgWriter modules. The conversion is
054: * realized when a block of data is requested: if source and destination data
055: * type are the same one, it does nothing, else appropriate cast is done. All
056: * the methods of the 'ImgData' interface are implemented by the
057: * 'ImgDataAdapter' class that is the superclass of this one, so they don't
058: * need to be reimplemented by subclasses.
059: * */
060: public class ImgDataConverter extends ImgDataAdapter implements
061: BlkImgDataSrc {
062:
063: /** The block used to request data from the source in the case that a
064: * conversion seems necessary. It can be either int or float at
065: * initialization time. It will be checked (and corrected if necessary) by
066: * the source whenever necessary */
067: private DataBlk srcBlk = new DataBlkInt();
068:
069: /** The source of image data */
070: private BlkImgDataSrc src;
071:
072: /** The number of fraction bits in the casted ints */
073: private int fp;
074:
075: /**
076: * Constructs a new ImgDataConverter object that operates on the specified
077: * source of image data.
078: *
079: * @param imgSrc The source from where to get the data to be transformed
080: *
081: * @param fp The number of fraction bits in the casted ints
082: *
083: * @see BlkImgDataSrc
084: * */
085: public ImgDataConverter(BlkImgDataSrc imgSrc, int fp) {
086: super (imgSrc);
087: src = imgSrc;
088: this .fp = fp;
089: }
090:
091: /**
092: * Constructs a new ImgDataConverter object that operates on the specified
093: * source of image data.
094: *
095: * @param imgSrc The source from where to get the data to be transformed
096: *
097: * @see BlkImgDataSrc
098: * */
099: public ImgDataConverter(BlkImgDataSrc imgSrc) {
100: super (imgSrc);
101: src = imgSrc;
102: fp = 0;
103: }
104:
105: /**
106: * Returns the position of the fixed point in the specified
107: * component. This is the position of the least significant integral
108: * (i.e. non-fractional) bit, which is equivalent to the number of
109: * fractional bits. For instance, for fixed-point values with 2 fractional
110: * bits, 2 is returned. For floating-point data this value does not apply
111: * and 0 should be returned. Position 0 is the position of the least
112: * significant bit in the data.
113: *
114: * @param c The index of the component.
115: *
116: * @return The position of the fixed-point, which is the same as the
117: * number of fractional bits.
118: * */
119: public int getFixedPoint(int c) {
120: return fp;
121: }
122:
123: /**
124: * Returns, in the blk argument, a block of image data containing the
125: * specifed rectangular area, in the specified component, using the
126: * 'transfer type' specified in the block given as argument. The data is
127: * returned, as a copy of the internal data, therefore the returned data
128: * can be modified "in place".
129: *
130: * <P>The rectangular area to return is specified by the 'ulx', 'uly', 'w'
131: * and 'h' members of the 'blk' argument, relative to the current
132: * tile. These members are not modified by this method. The 'offset' of
133: * the returned data is 0, and the 'scanw' is the same as the block's
134: * width. See the 'DataBlk' class.
135: *
136: * <P>This method, in general, is less efficient than the
137: * 'getInternCompData()' method since, in general, it copies the
138: * data. However if the array of returned data is to be modified by the
139: * caller then this method is preferable.
140: *
141: * <P>If the data array in 'blk' is 'null', then a new one is created. If
142: * the data array is not 'null' then it is reused, and it must be large
143: * enough to contain the block's data. Otherwise an 'ArrayStoreException'
144: * or an 'IndexOutOfBoundsException' is thrown by the Java system.
145: *
146: * <P>The returned data may have its 'progressive' attribute set. In this
147: * case the returned data is only an approximation of the "final" data.
148: *
149: * @param blk Its coordinates and dimensions specify the area to return,
150: * relative to the current tile. If it contains a non-null data array,
151: * then it must be large enough. If it contains a null data array a new
152: * one is created. Some fields in this object are modified to return the
153: * data.
154: *
155: * @param c The index of the component from which to get the data.
156: *
157: * @see #getInternCompData
158: * */
159: public DataBlk getCompData(DataBlk blk, int c) {
160: return getData(blk, c, false);
161: }
162:
163: /**
164: * Returns, in the blk argument, a block of image data containing the
165: * specifed rectangular area, in the specified component, using the
166: * 'transfer type' defined in the block given as argument. The data is
167: * returned, as a reference to the internal data, if any, instead of as a
168: * copy, therefore the returned data should not be modified.
169: *
170: * <P>The rectangular area to return is specified by the 'ulx', 'uly', 'w'
171: * and 'h' members of the 'blk' argument, relative to the current
172: * tile. These members are not modified by this method. The 'offset' and
173: * 'scanw' of the returned data can be arbitrary. See the 'DataBlk' class.
174: *
175: * <P> If source data and expected data (blk) are using the same type,
176: * block returned without any modification. If not appropriate cast is
177: * used.
178: *
179: * <P>This method, in general, is more efficient than the 'getCompData()'
180: * method since it may not copy the data. However if the array of returned
181: * data is to be modified by the caller then the other method is probably
182: * preferable.
183: *
184: * <P>If the data array in <tt>blk</tt> is <tt>null</tt>, then a new one
185: * is created if necessary. The implementation of this interface may
186: * choose to return the same array or a new one, depending on what is more
187: * efficient. Therefore, the data array in <tt>blk</tt> prior to the
188: * method call should not be considered to contain the returned data, a
189: * new array may have been created. Instead, get the array from
190: * <tt>blk</tt> after the method has returned.
191: *
192: * <P>The returned data may have its 'progressive' attribute set. In this
193: * case the returned data is only an approximation of the "final" data.
194: *
195: * @param blk Its coordinates and dimensions specify the area to return,
196: * relative to the current tile. Some fields in this object are modified
197: * to return the data.
198: *
199: * @param c The index of the component from which to get the data.
200: *
201: * @return The requested DataBlk
202: *
203: * @see #getCompData
204: * */
205: public final DataBlk getInternCompData(DataBlk blk, int c) {
206: return getData(blk, c, true);
207: }
208:
209: /**
210: * Implements the 'getInternCompData()' and the 'getCompData()'
211: * methods. The 'intern' flag signals which of the two methods should run
212: * as.
213: *
214: * @param blk The data block to get.
215: *
216: * @param c The index of the component from which to get the data.
217: *
218: * @param intern If true behave as 'getInternCompData(). Otherwise behave
219: * as 'getCompData()'
220: *
221: * @return The requested data block
222: *
223: * @see #getInternCompData
224: *
225: * @see #getCompData
226: * */
227: private DataBlk getData(DataBlk blk, int c, boolean intern) {
228: DataBlk reqBlk; // Reference to block used in request to source
229:
230: // Keep request data type
231: int otype = blk.getDataType();
232:
233: if (otype == srcBlk.getDataType()) {
234: // Probably requested type is same as source type
235: reqBlk = blk;
236: } else {
237: // Probably requested type is not the same as source type
238: reqBlk = srcBlk;
239: // We need to copy requested coordinates and size
240: reqBlk.ulx = blk.ulx;
241: reqBlk.uly = blk.uly;
242: reqBlk.w = blk.w;
243: reqBlk.h = blk.h;
244: }
245:
246: // Get source data block
247: if (intern) {
248: // We can use the intern variant
249: srcBlk = src.getInternCompData(reqBlk, c);
250: } else {
251: // Do not use the intern variant. Note that this is not optimal
252: // since if we are going to convert below then we could have used
253: // the intern variant. But there is currently no way to know if we
254: // will need to do conversion or not before getting the data.
255: srcBlk = src.getCompData(reqBlk, c);
256: }
257:
258: // Check if casting is needed
259: if (srcBlk.getDataType() == otype) {
260: return srcBlk;
261: }
262:
263: int i;
264: int k, kSrc, kmin;
265: float mult;
266: int w = srcBlk.w;
267: int h = srcBlk.h;
268:
269: switch (otype) {
270: case DataBlk.TYPE_FLOAT: // Cast INT -> FLOAT
271:
272: float farr[];
273: int srcIArr[];
274:
275: // Get data array from resulting blk
276: farr = (float[]) blk.getData();
277: if (farr == null || farr.length < w * h) {
278: farr = new float[w * h];
279: blk.setData(farr);
280: }
281:
282: blk.scanw = srcBlk.w;
283: blk.offset = 0;
284: blk.progressive = srcBlk.progressive;
285: srcIArr = (int[]) srcBlk.getData();
286:
287: // Cast data from source to blk
288: fp = src.getFixedPoint(c);
289: if (fp != 0) {
290: mult = 1.0f / (1 << fp);
291: for (i = h - 1, k = w * h - 1, kSrc = srcBlk.offset
292: + (h - 1) * srcBlk.scanw + w - 1; i >= 0; i--) {
293: for (kmin = k - w; k > kmin; k--, kSrc--) {
294: farr[k] = ((srcIArr[kSrc] * mult));
295: }
296: // Jump to geggining of next line in source
297: kSrc -= srcBlk.scanw - w;
298: }
299: } else {
300: for (i = h - 1, k = w * h - 1, kSrc = srcBlk.offset
301: + (h - 1) * srcBlk.scanw + w - 1; i >= 0; i--) {
302: for (kmin = k - w; k > kmin; k--, kSrc--) {
303: farr[k] = ((float) (srcIArr[kSrc]));
304: }
305: // Jump to geggining of next line in source
306: kSrc -= srcBlk.scanw - w;
307: }
308: }
309: break; // End of cast INT-> FLOAT
310:
311: case DataBlk.TYPE_INT: // cast FLOAT -> INT
312: int iarr[];
313: float srcFArr[];
314:
315: // Get data array from resulting blk
316: iarr = (int[]) blk.getData();
317: if (iarr == null || iarr.length < w * h) {
318: iarr = new int[w * h];
319: blk.setData(iarr);
320: }
321: blk.scanw = srcBlk.w;
322: blk.offset = 0;
323: blk.progressive = srcBlk.progressive;
324: srcFArr = (float[]) srcBlk.getData();
325:
326: // Cast data from source to blk
327: if (fp != 0) {
328: mult = (float) (1 << fp);
329: for (i = h - 1, k = w * h - 1, kSrc = srcBlk.offset
330: + (h - 1) * srcBlk.scanw + w - 1; i >= 0; i--) {
331: for (kmin = k - w; k > kmin; k--, kSrc--) {
332: if (srcFArr[kSrc] > 0.0f) {
333: iarr[k] = (int) (srcFArr[kSrc] * mult + 0.5f);
334: } else {
335: iarr[k] = (int) (srcFArr[kSrc] * mult - 0.5f);
336: }
337: }
338: // Jump to geggining of next line in source
339: kSrc -= srcBlk.scanw - w;
340: }
341: } else {
342: for (i = h - 1, k = w * h - 1, kSrc = srcBlk.offset
343: + (h - 1) * srcBlk.scanw + w - 1; i >= 0; i--) {
344: for (kmin = k - w; k > kmin; k--, kSrc--) {
345: if (srcFArr[kSrc] > 0.0f) {
346: iarr[k] = (int) (srcFArr[kSrc] + 0.5f);
347: } else {
348: iarr[k] = (int) (srcFArr[kSrc] - 0.5f);
349: }
350: }
351: // Jump to geggining of next line in source
352: kSrc -= srcBlk.scanw - w;
353: }
354: }
355: break; // End cast FLOAT -> INT
356: default:
357: throw new IllegalArgumentException(
358: "Only integer and float data " + "are "
359: + "supported by JJ2000");
360: }
361: return blk;
362: }
363: }
|