Source code: com/obrador/DCT.java
1 // This class incorporates quality scaling as implemented in the JPEG-6a
2 // library.
3
4 /*
5 * DCT - A Java implementation of the Discreet Cosine Transform
6 */
7 package com.obrador;
8
9 class DCT
10 {
11 //~ Instance fields ////////////////////////////////////////////////////////
12
13 public Object[] Divisors = new Object[2];
14
15 /**
16 * DCT Block Size - default 8
17 */
18 public int N = 8;
19 public double[] DivisorsChrominance = new double[N * N];
20 public double[] DivisorsLuminance = new double[N * N];
21 public Object[] quantum = new Object[2];
22
23 /**
24 * Quantitization Matrix for chrominance.
25 */
26 public int[] quantum_chrominance = new int[N * N];
27
28 /**
29 * Quantitization Matrix for luminace.
30 */
31 public int[] quantum_luminance = new int[N * N];
32
33 /**
34 * Image Quality (0-100) - default 80 (good image / good compression)
35 */
36 public int QUALITY = 80;
37
38 //~ Constructors ///////////////////////////////////////////////////////////
39
40 /**
41 * Constructs a new DCT object. Initializes the cosine transform matrix
42 * these are used when computing the DCT and it's inverse. This also
43 * initializes the run length counters and the ZigZag sequence. Note that
44 * the image quality can be worse than 25 however the image will be
45 * extemely pixelated, usually to a block size of N.
46 *
47 * @param QUALITY The quality of the image (0 worst - 100 best)
48 *
49 */
50 public DCT(int QUALITY)
51 {
52 initMatrix(QUALITY);
53 }
54
55 //~ Methods ////////////////////////////////////////////////////////////////
56
57 /*
58 * This method preforms a DCT on a block of image data using the AAN
59 * method as implemented in the IJG Jpeg-6a library.
60 */
61 public double[][] forwardDCT(float[][] input)
62 {
63 double[][] output = new double[N][N];
64 double tmp0;
65 double tmp1;
66 double tmp2;
67 double tmp3;
68 double tmp4;
69 double tmp5;
70 double tmp6;
71 double tmp7;
72 double tmp10;
73 double tmp11;
74 double tmp12;
75 double tmp13;
76 double z1;
77 double z2;
78 double z3;
79 double z4;
80 double z5;
81 double z11;
82 double z13;
83 int i;
84 int j;
85
86 // Subtracts 128 from the input values
87 for (i = 0; i < 8; i++)
88 {
89 for (j = 0; j < 8; j++)
90 {
91 output[i][j] = ((double) input[i][j] - (double) 128.0);
92
93 // input[i][j] -= 128;
94 }
95 }
96
97 for (i = 0; i < 8; i++)
98 {
99 tmp0 = output[i][0] + output[i][7];
100 tmp7 = output[i][0] - output[i][7];
101 tmp1 = output[i][1] + output[i][6];
102 tmp6 = output[i][1] - output[i][6];
103 tmp2 = output[i][2] + output[i][5];
104 tmp5 = output[i][2] - output[i][5];
105 tmp3 = output[i][3] + output[i][4];
106 tmp4 = output[i][3] - output[i][4];
107
108 tmp10 = tmp0 + tmp3;
109 tmp13 = tmp0 - tmp3;
110 tmp11 = tmp1 + tmp2;
111 tmp12 = tmp1 - tmp2;
112
113 output[i][0] = tmp10 + tmp11;
114 output[i][4] = tmp10 - tmp11;
115
116 z1 = (tmp12 + tmp13) * (double) 0.707106781;
117 output[i][2] = tmp13 + z1;
118 output[i][6] = tmp13 - z1;
119
120 tmp10 = tmp4 + tmp5;
121 tmp11 = tmp5 + tmp6;
122 tmp12 = tmp6 + tmp7;
123
124 z5 = (tmp10 - tmp12) * (double) 0.382683433;
125 z2 = (((double) 0.541196100) * tmp10) + z5;
126 z4 = (((double) 1.306562965) * tmp12) + z5;
127 z3 = tmp11 * ((double) 0.707106781);
128
129 z11 = tmp7 + z3;
130 z13 = tmp7 - z3;
131
132 output[i][5] = z13 + z2;
133 output[i][3] = z13 - z2;
134 output[i][1] = z11 + z4;
135 output[i][7] = z11 - z4;
136 }
137
138 for (i = 0; i < 8; i++)
139 {
140 tmp0 = output[0][i] + output[7][i];
141 tmp7 = output[0][i] - output[7][i];
142 tmp1 = output[1][i] + output[6][i];
143 tmp6 = output[1][i] - output[6][i];
144 tmp2 = output[2][i] + output[5][i];
145 tmp5 = output[2][i] - output[5][i];
146 tmp3 = output[3][i] + output[4][i];
147 tmp4 = output[3][i] - output[4][i];
148
149 tmp10 = tmp0 + tmp3;
150 tmp13 = tmp0 - tmp3;
151 tmp11 = tmp1 + tmp2;
152 tmp12 = tmp1 - tmp2;
153
154 output[0][i] = tmp10 + tmp11;
155 output[4][i] = tmp10 - tmp11;
156
157 z1 = (tmp12 + tmp13) * (double) 0.707106781;
158 output[2][i] = tmp13 + z1;
159 output[6][i] = tmp13 - z1;
160
161 tmp10 = tmp4 + tmp5;
162 tmp11 = tmp5 + tmp6;
163 tmp12 = tmp6 + tmp7;
164
165 z5 = (tmp10 - tmp12) * (double) 0.382683433;
166 z2 = (((double) 0.541196100) * tmp10) + z5;
167 z4 = (((double) 1.306562965) * tmp12) + z5;
168 z3 = tmp11 * ((double) 0.707106781);
169
170 z11 = tmp7 + z3;
171 z13 = tmp7 - z3;
172
173 output[5][i] = z13 + z2;
174 output[3][i] = z13 - z2;
175 output[1][i] = z11 + z4;
176 output[7][i] = z11 - z4;
177 }
178
179 return output;
180 }
181
182 /*
183 * This method preforms forward DCT on a block of image data using
184 * the literal method specified for a 2-D Discrete Cosine Transform.
185 * It is included as a curiosity and can give you an idea of the
186 * difference in the compression result (the resulting image quality)
187 * by comparing its output to the output of the AAN method below.
188 * It is ridiculously inefficient.
189 */
190
191 // For now the final output is unusable. The associated quantization step
192 // needs some tweaking. If you get this part working, please let me know.
193 public double[][] forwardDCTExtreme(float[][] input)
194 {
195 double[][] output = new double[N][N];
196 double tmp0;
197 double tmp1;
198 double tmp2;
199 double tmp3;
200 double tmp4;
201 double tmp5;
202 double tmp6;
203 double tmp7;
204 double tmp10;
205 double tmp11;
206 double tmp12;
207 double tmp13;
208 double z1;
209 double z2;
210 double z3;
211 double z4;
212 double z5;
213 double z11;
214 double z13;
215 int i;
216 int j;
217 int v;
218 int u;
219 int x;
220 int y;
221
222 for (v = 0; v < 8; v++)
223 {
224 for (u = 0; u < 8; u++)
225 {
226 for (x = 0; x < 8; x++)
227 {
228 for (y = 0; y < 8; y++)
229 {
230 output[v][u] += (((double) input[x][y]) * Math.cos(((double) ((2 * x) +
231 1) * (double) u * Math.PI) / (double) 16) * Math.cos(((double) ((2 * y) +
232 1) * (double) v * Math.PI) / (double) 16));
233 }
234 }
235
236 output[v][u] *= ((double) (0.25) * ((u == 0)
237 ? ((double) 1.0 / Math.sqrt(2)) : (double) 1.0) * ((v == 0)
238 ? ((double) 1.0 / Math.sqrt(2)) : (double) 1.0));
239 }
240 }
241
242 return output;
243 }
244
245 /*
246 * This method quantitizes data and rounds it to the nearest integer.
247 */
248 public int[] quantizeBlock(double[][] inputData, int code)
249 {
250 int[] outputData = new int[N * N];
251 int i;
252 int j;
253 int index;
254 index = 0;
255
256 for (i = 0; i < 8; i++)
257 {
258 for (j = 0; j < 8; j++)
259 {
260 // The second line results in significantly better compression.
261 outputData[index] = (int) (Math.round(inputData[i][j] * (((double[]) (Divisors[code]))[index])));
262
263 // outputData[index] = (int)(((inputData[i][j] * (((double[]) (Divisors[code]))[index])) + 16384.5) -16384);
264 index++;
265 }
266 }
267
268 return outputData;
269 }
270
271 /*
272 * This is the method for quantizing a block DCT'ed with forwardDCTExtreme
273 * This method quantitizes data and rounds it to the nearest integer.
274 */
275 public int[] quantizeBlockExtreme(double[][] inputData, int code)
276 {
277 int[] outputData = new int[N * N];
278 int i;
279 int j;
280 int index;
281 index = 0;
282
283 for (i = 0; i < 8; i++)
284 {
285 for (j = 0; j < 8; j++)
286 {
287 outputData[index] = (int) (Math.round(inputData[i][j] / (double) (((int[]) (quantum[code]))[index])));
288 index++;
289 }
290 }
291
292 return outputData;
293 }
294
295 /*
296 * This method sets up the quantization matrix for luminance and
297 * chrominance using the Quality parameter.
298 */
299 private void initMatrix(int quality)
300 {
301 double[] AANscaleFactor =
302 {
303 1.0, 1.387039845, 1.306562965, 1.175875602, 1.0, 0.785694958,
304 0.541196100, 0.275899379
305 };
306 int i;
307 int j;
308 int index;
309 int Quality;
310 int temp;
311
312 // converting quality setting to that specified in the jpeg_quality_scaling
313 // method in the IJG Jpeg-6a C libraries
314 Quality = quality;
315
316 if (Quality <= 0)
317 {
318 Quality = 1;
319 }
320
321 if (Quality > 100)
322 {
323 Quality = 100;
324 }
325
326 if (Quality < 50)
327 {
328 Quality = 5000 / Quality;
329 }
330 else
331 {
332 Quality = 200 - (Quality * 2);
333 }
334
335 // Creating the luminance matrix
336 quantum_luminance[0] = 16;
337 quantum_luminance[1] = 11;
338 quantum_luminance[2] = 10;
339 quantum_luminance[3] = 16;
340 quantum_luminance[4] = 24;
341 quantum_luminance[5] = 40;
342 quantum_luminance[6] = 51;
343 quantum_luminance[7] = 61;
344 quantum_luminance[8] = 12;
345 quantum_luminance[9] = 12;
346 quantum_luminance[10] = 14;
347 quantum_luminance[11] = 19;
348 quantum_luminance[12] = 26;
349 quantum_luminance[13] = 58;
350 quantum_luminance[14] = 60;
351 quantum_luminance[15] = 55;
352 quantum_luminance[16] = 14;
353 quantum_luminance[17] = 13;
354 quantum_luminance[18] = 16;
355 quantum_luminance[19] = 24;
356 quantum_luminance[20] = 40;
357 quantum_luminance[21] = 57;
358 quantum_luminance[22] = 69;
359 quantum_luminance[23] = 56;
360 quantum_luminance[24] = 14;
361 quantum_luminance[25] = 17;
362 quantum_luminance[26] = 22;
363 quantum_luminance[27] = 29;
364 quantum_luminance[28] = 51;
365 quantum_luminance[29] = 87;
366 quantum_luminance[30] = 80;
367 quantum_luminance[31] = 62;
368 quantum_luminance[32] = 18;
369 quantum_luminance[33] = 22;
370 quantum_luminance[34] = 37;
371 quantum_luminance[35] = 56;
372 quantum_luminance[36] = 68;
373 quantum_luminance[37] = 109;
374 quantum_luminance[38] = 103;
375 quantum_luminance[39] = 77;
376 quantum_luminance[40] = 24;
377 quantum_luminance[41] = 35;
378 quantum_luminance[42] = 55;
379 quantum_luminance[43] = 64;
380 quantum_luminance[44] = 81;
381 quantum_luminance[45] = 104;
382 quantum_luminance[46] = 113;
383 quantum_luminance[47] = 92;
384 quantum_luminance[48] = 49;
385 quantum_luminance[49] = 64;
386 quantum_luminance[50] = 78;
387 quantum_luminance[51] = 87;
388 quantum_luminance[52] = 103;
389 quantum_luminance[53] = 121;
390 quantum_luminance[54] = 120;
391 quantum_luminance[55] = 101;
392 quantum_luminance[56] = 72;
393 quantum_luminance[57] = 92;
394 quantum_luminance[58] = 95;
395 quantum_luminance[59] = 98;
396 quantum_luminance[60] = 112;
397 quantum_luminance[61] = 100;
398 quantum_luminance[62] = 103;
399 quantum_luminance[63] = 99;
400
401 for (j = 0; j < 64; j++)
402 {
403 temp = ((quantum_luminance[j] * Quality) + 50) / 100;
404
405 if (temp <= 0)
406 {
407 temp = 1;
408 }
409
410 if (temp > 255)
411 {
412 temp = 255;
413 }
414
415 quantum_luminance[j] = temp;
416 }
417
418 index = 0;
419
420 for (i = 0; i < 8; i++)
421 {
422 for (j = 0; j < 8; j++)
423 {
424 // The divisors for the LL&M method (the slow integer method used in
425 // jpeg 6a library). This method is currently (04/04/98) incompletely
426 // implemented.
427 // DivisorsLuminance[index] = ((double) quantum_luminance[index]) << 3;
428 // The divisors for the AAN method (the float method used in jpeg 6a library.
429 DivisorsLuminance[index] = (double) ((double) 1.0 / ((double) quantum_luminance[index] * AANscaleFactor[i] * AANscaleFactor[j] * (double) 8.0));
430 index++;
431 }
432 }
433
434 // Creating the chrominance matrix
435 quantum_chrominance[0] = 17;
436 quantum_chrominance[1] = 18;
437 quantum_chrominance[2] = 24;
438 quantum_chrominance[3] = 47;
439 quantum_chrominance[4] = 99;
440 quantum_chrominance[5] = 99;
441 quantum_chrominance[6] = 99;
442 quantum_chrominance[7] = 99;
443 quantum_chrominance[8] = 18;
444 quantum_chrominance[9] = 21;
445 quantum_chrominance[10] = 26;
446 quantum_chrominance[11] = 66;
447 quantum_chrominance[12] = 99;
448 quantum_chrominance[13] = 99;
449 quantum_chrominance[14] = 99;
450 quantum_chrominance[15] = 99;
451 quantum_chrominance[16] = 24;
452 quantum_chrominance[17] = 26;
453 quantum_chrominance[18] = 56;
454 quantum_chrominance[19] = 99;
455 quantum_chrominance[20] = 99;
456 quantum_chrominance[21] = 99;
457 quantum_chrominance[22] = 99;
458 quantum_chrominance[23] = 99;
459 quantum_chrominance[24] = 47;
460 quantum_chrominance[25] = 66;
461 quantum_chrominance[26] = 99;
462 quantum_chrominance[27] = 99;
463 quantum_chrominance[28] = 99;
464 quantum_chrominance[29] = 99;
465 quantum_chrominance[30] = 99;
466 quantum_chrominance[31] = 99;
467 quantum_chrominance[32] = 99;
468 quantum_chrominance[33] = 99;
469 quantum_chrominance[34] = 99;
470 quantum_chrominance[35] = 99;
471 quantum_chrominance[36] = 99;
472 quantum_chrominance[37] = 99;
473 quantum_chrominance[38] = 99;
474 quantum_chrominance[39] = 99;
475 quantum_chrominance[40] = 99;
476 quantum_chrominance[41] = 99;
477 quantum_chrominance[42] = 99;
478 quantum_chrominance[43] = 99;
479 quantum_chrominance[44] = 99;
480 quantum_chrominance[45] = 99;
481 quantum_chrominance[46] = 99;
482 quantum_chrominance[47] = 99;
483 quantum_chrominance[48] = 99;
484 quantum_chrominance[49] = 99;
485 quantum_chrominance[50] = 99;
486 quantum_chrominance[51] = 99;
487 quantum_chrominance[52] = 99;
488 quantum_chrominance[53] = 99;
489 quantum_chrominance[54] = 99;
490 quantum_chrominance[55] = 99;
491 quantum_chrominance[56] = 99;
492 quantum_chrominance[57] = 99;
493 quantum_chrominance[58] = 99;
494 quantum_chrominance[59] = 99;
495 quantum_chrominance[60] = 99;
496 quantum_chrominance[61] = 99;
497 quantum_chrominance[62] = 99;
498 quantum_chrominance[63] = 99;
499
500 for (j = 0; j < 64; j++)
501 {
502 temp = ((quantum_chrominance[j] * Quality) + 50) / 100;
503
504 if (temp <= 0)
505 {
506 temp = 1;
507 }
508
509 if (temp >= 255)
510 {
511 temp = 255;
512 }
513
514 quantum_chrominance[j] = temp;
515 }
516
517 index = 0;
518
519 for (i = 0; i < 8; i++)
520 {
521 for (j = 0; j < 8; j++)
522 {
523 // The divisors for the LL&M method (the slow integer method used in
524 // jpeg 6a library). This method is currently (04/04/98) incompletely
525 // implemented.
526 // DivisorsChrominance[index] = ((double) quantum_chrominance[index]) << 3;
527 // The divisors for the AAN method (the float method used in jpeg 6a library.
528 DivisorsChrominance[index] = (double) ((double) 1.0 / ((double) quantum_chrominance[index] * AANscaleFactor[i] * AANscaleFactor[j] * (double) 8.0));
529 index++;
530 }
531 }
532
533 // quantum and Divisors are objects used to hold the appropriate matices
534 quantum[0] = quantum_luminance;
535 Divisors[0] = DivisorsLuminance;
536 quantum[1] = quantum_chrominance;
537 Divisors[1] = DivisorsChrominance;
538 }
539 }
540 ///////////////////////////////////////////////////////////////////////////////
541 // END OF FILE.
542 ///////////////////////////////////////////////////////////////////////////////