001: /*
002: * $RCSfile: FCTmediaLib.java,v $
003: *
004: * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
005: *
006: * Use is subject to license terms.
007: *
008: * $Revision: 1.1 $
009: * $Date: 2005/02/11 04:55:46 $
010: * $State: Exp $
011: */
012: package com.sun.media.jai.mlib;
013:
014: import java.awt.image.DataBuffer;
015: import java.util.Arrays;
016: import com.sun.media.jai.opimage.FCT;
017: import com.sun.media.jai.util.MathJAI;
018:
019: import com.sun.medialib.mlib.*;
020:
021: /**
022: * The Fast Cosine Transform (FCT) class. This classes calculates the FCT
023: * using mediaLib's 1D double precision FFT.
024: *
025: * @since EA4
026: */
027: public class FCTmediaLib extends FCT {
028: /** The length of the FCT. */
029: private int length;
030:
031: /** Initialization flag. */
032: private boolean lengthIsSet = false;
033:
034: /** Lookup table of cosine scale factors. */
035: private double[] wr;
036:
037: /** Lookup table of sine scale factors. */
038: private double[] wi;
039:
040: /** Work array for real part. */
041: protected double[] real;
042:
043: /** Work array for imaginary part. */
044: protected double[] imag;
045:
046: /**
047: * Construct a new FCT object.
048: *
049: * @param length The length of the FCT; must be a positive power of 2.
050: */
051: public FCTmediaLib(boolean isForwardTransform, int length) {
052: this .isForwardTransform = isForwardTransform;
053: setLength(length);
054: }
055:
056: // ***** FCT inner class public methods. *****
057:
058: /**
059: * Initialize the length-dependent fields.
060: *
061: * @param length The length of the FCT; must be a positive power of 2.
062: */
063: public void setLength(int length) {
064: // Check whether it's necessary to continue.
065: if (lengthIsSet && length == this .length) {
066: return;
067: }
068:
069: // Ensure that the length is a positive power of two.
070: if (!MathJAI.isPositivePowerOf2(length)) {
071: throw new RuntimeException(JaiI18N
072: .getString("FCTmediaLib0"));
073: }
074:
075: // Cache the length.
076: this .length = length;
077:
078: // Allocate cache memory.
079: if (real == null || length != real.length) {
080: real = new double[length];
081: imag = new double[length];
082: }
083:
084: // Calculate lookup tables of the cosine coefficients.
085: calculateFCTLUTs();
086:
087: // Set initialization flag.
088: lengthIsSet = true;
089: }
090:
091: /**
092: * Calculate the FCT sine and cosine lookup tables.
093: */
094: private void calculateFCTLUTs() {
095: wr = new double[length];
096: wi = new double[length];
097:
098: for (int i = 0; i < length; i++) {
099: double factor = ((i == 0) ? Math.sqrt(1.0 / length) : Math
100: .sqrt(2.0 / length));
101: double freq = Math.PI * i / (2.0 * length);
102: wr[i] = factor * Math.cos(freq);
103: wi[i] = factor * Math.sin(freq);
104: }
105: }
106:
107: /**
108: * Set the internal work data array of the FCT object.
109: *
110: * @param dataType The data type of the source data according to
111: * one of the DataBuffer TYPE_* flags. This should be either
112: * DataBuffer.TYPE_FLOAT or DataBuffer.TYPE_DOUBLE.
113: * @param data Float or double array of data.
114: * @param offset Offset into the data array.
115: * @param stride The data array stride value.
116: * @param count The number of values to copy.
117: */
118: public void setData(int dataType, Object data, int offset,
119: int stride, int count) {
120: if (isForwardTransform) {
121: setFCTData(dataType, data, offset, stride, count);
122: } else {
123: setIFCTData(dataType, data, offset, stride, count);
124: }
125: }
126:
127: /**
128: * Get data from the internal work data array of the FCT object.
129: *
130: * @param dataType The data type of the source data according to
131: * one of the DataBuffer TYPE_* flags. This should be either
132: * DataBuffer.TYPE_FLOAT or DataBuffer.TYPE_DOUBLE.
133: * @param data Float or double array of data.
134: * @param offset Offset into the data array.
135: * @param stride The data array stride value.
136: */
137: public void getData(int dataType, Object data, int offset,
138: int stride) {
139: if (isForwardTransform) {
140: getFCTData(dataType, data, offset, stride);
141: } else {
142: getIFCTData(dataType, data, offset, stride);
143: }
144: }
145:
146: /**
147: * Set the internal work data arrays of the FFT object.
148: *
149: * @param dataType The data type of the source data according to
150: * one of the DataBuffer TYPE_* flags. This should be either
151: * DataBuffer.TYPE_FLOAT or DataBuffer.TYPE_DOUBLE.
152: * @param data Float or double array of data.
153: * @param offset Offset into the data array.
154: * @param stride The data array stride value.
155: * @param count The number of values to copy.
156: */
157: private void setFCTData(int dataType, Object data, int offset,
158: int stride, int count) {
159: // Copy the parameter arrays.
160: switch (dataType) {
161: case DataBuffer.TYPE_FLOAT: {
162: float[] realFloat = (float[]) data;
163: for (int i = 0; i < count; i++) {
164: imag[i] = realFloat[offset];
165: offset += stride;
166: }
167: for (int i = count; i < length; i++) {
168: imag[i] = 0.0;
169: }
170: int k = length - 1;
171: int j = 0;
172: for (int i = 0; i < k; i++) {
173: real[i] = imag[j++];
174: real[k--] = imag[j++];
175: }
176: }
177: break;
178: case DataBuffer.TYPE_DOUBLE: {
179: double[] realDouble = (double[]) data;
180: for (int i = 0; i < count; i++) {
181: imag[i] = realDouble[offset];
182: offset += stride;
183: }
184: for (int i = count; i < length; i++) {
185: imag[i] = 0.0;
186: }
187: int k = length - 1;
188: int j = 0;
189: for (int i = 0; i < k; i++) {
190: real[i] = imag[j++];
191: real[k--] = imag[j++];
192: }
193: }
194: break;
195: default:
196: // NB: This statement should be unreachable as the destination
197: // image is required to be a floating point type and the
198: // RasterAccessor is supposed to promote the data type of
199: // all rasters to the "minimum" data type of all source
200: // and destination rasters involved.
201: throw new RuntimeException(dataType
202: + JaiI18N.getString("FCTmediaLib1"));
203: }
204:
205: // Always clear imaginary part.
206: Arrays.fill(imag, 0, length, 0.0);
207: }
208:
209: /**
210: * Get data from the internal work data arrays of the FFT object.
211: *
212: * @param dataType The data type of the source data according to
213: * one of the DataBuffer TYPE_* flags. This should be either
214: * DataBuffer.TYPE_FLOAT or DataBuffer.TYPE_DOUBLE.
215: * @param data The data as a float[] or double[].
216: * @param offset Offset into the data array.
217: * @param stride The array stride value.
218: * @param count The number of values to copy.
219: */
220: private void getFCTData(int dataType, Object data, int offset,
221: int stride) {
222: switch (dataType) {
223: case DataBuffer.TYPE_FLOAT: {
224: float[] realFloat = (float[]) data;
225: for (int i = 0; i < length; i++) {
226: realFloat[offset] = (float) (wr[i] * real[i] + wi[i]
227: * imag[i]);
228: offset += stride;
229: }
230: }
231: break;
232: case DataBuffer.TYPE_DOUBLE: {
233: double[] realDouble = (double[]) data;
234: for (int i = 0; i < length; i++) {
235: realDouble[offset] = wr[i] * real[i] + wi[i] * imag[i];
236: offset += stride;
237: }
238: }
239: break;
240: default:
241: // NB: This statement should be unreachable as the destination
242: // image is required to be a floating point type and the
243: // RasterAccessor is supposed to promote the data type of
244: // all rasters to the "minimum" data type of all source
245: // and destination rasters involved.
246: throw new RuntimeException(dataType
247: + JaiI18N.getString("FCTmediaLib1"));
248: }
249: }
250:
251: /**
252: * Set the internal work data arrays of the FFT object.
253: *
254: * @param dataType The data type of the source data according to
255: * one of the DataBuffer TYPE_* flags. This should be either
256: * DataBuffer.TYPE_FLOAT or DataBuffer.TYPE_DOUBLE.
257: * @param data The data as a float[] or double[].
258: * @param offset Offset into the data array.
259: * @param stride The array stride value.
260: * @param count The number of values to copy.
261: */
262: private void setIFCTData(int dataType, Object data, int offset,
263: int stride, int count) {
264: // Copy the parameter arrays.
265: switch (dataType) {
266: case DataBuffer.TYPE_FLOAT: {
267: float[] realFloat = (float[]) data;
268: for (int i = 0; i < count; i++) {
269: float r = realFloat[offset];
270: real[i] = r * wr[i];
271: imag[i] = r * wi[i];
272: offset += stride;
273: }
274: }
275: break;
276: case DataBuffer.TYPE_DOUBLE: {
277: double[] realDouble = (double[]) data;
278: for (int i = 0; i < count; i++) {
279: double r = realDouble[offset];
280: real[i] = r * wr[i];
281: imag[i] = r * wi[i];
282: offset += stride;
283: }
284: }
285: break;
286: default:
287: // NB: This statement should be unreachable as the destination
288: // image is required to be a floating point type and the
289: // RasterAccessor is supposed to promote the data type of
290: // all rasters to the "minimum" data type of all source
291: // and destination rasters involved.
292: throw new RuntimeException(dataType
293: + JaiI18N.getString("FCTmediaLib1"));
294: }
295:
296: // If fewer input than target points fill target with zeros.
297: if (count < length) {
298: Arrays.fill(real, count, length, 0.0);
299: Arrays.fill(imag, count, length, 0.0);
300: }
301: }
302:
303: /**
304: * Get data from the internal work data arrays of the FFT object.
305: *
306: * @param dataType The data type of the source data according to
307: * one of the DataBuffer TYPE_* flags. This should be either
308: * DataBuffer.TYPE_FLOAT or DataBuffer.TYPE_DOUBLE.
309: * @param data The data as a float[] or double[].
310: * @param offset Offset into the data array.
311: * @param stride The array stride value.
312: * @param count The number of values to copy.
313: */
314: private void getIFCTData(int dataType, Object data, int offset,
315: int stride) {
316: switch (dataType) {
317: case DataBuffer.TYPE_FLOAT: {
318: float[] realFloat = (float[]) data;
319: int k = length - 1;
320: for (int i = 0; i < k; i++) {
321: realFloat[offset] = (float) real[i];
322: offset += stride;
323: realFloat[offset] = (float) real[k--];
324: offset += stride;
325: }
326: }
327: break;
328: case DataBuffer.TYPE_DOUBLE: {
329: double[] realDouble = (double[]) data;
330: int k = length - 1;
331: for (int i = 0; i < k; i++) {
332: realDouble[offset] = (float) real[i];
333: offset += stride;
334: realDouble[offset] = (float) real[k--];
335: offset += stride;
336: }
337: }
338: break;
339: default:
340: // NB: This statement should be unreachable as the destination
341: // image is required to be a floating point type and the
342: // RasterAccessor is supposed to promote the data type of
343: // all rasters to the "minimum" data type of all source
344: // and destination rasters involved.
345: throw new RuntimeException(dataType
346: + JaiI18N.getString("FCTmediaLib1"));
347: }
348: }
349:
350: /**
351: * Calculate the DCT of a sequence using the FFT algorithm.
352: */
353: public void transform() {
354: if (isForwardTransform) {
355: Image.FFT_1(real, imag);
356: } else {
357: Image.IFFT_2(real, imag);
358: }
359: }
360: }
|