KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > net > myvietnam > mvncore > thirdparty > JpegEncoder


1 package net.myvietnam.mvncore.thirdparty;
2 // Version 1.0a
3
// Copyright (C) 1998, James R. Weeks and BioElectroMech.
4
// Visit BioElectroMech at www.obrador.com. Email James@obrador.com.
5

6 // See license.txt for details about the allowed used of this software.
7
// This software is based in part on the work of the Independent JPEG Group.
8
// See IJGreadme.txt for details about the Independent JPEG Group's license.
9

10 // This encoder is inspired by the Java Jpeg encoder by Florian Raemy,
11
// studwww.eurecom.fr/~raemy.
12
// It borrows a great deal of code and structure from the Independent
13
// Jpeg Group's Jpeg 6a library, Copyright Thomas G. Lane.
14
// See license.txt for details.
15

16 import java.awt.AWTException JavaDoc;
17 import java.awt.Frame JavaDoc;
18 import java.awt.Image JavaDoc;
19 import java.awt.MediaTracker JavaDoc;
20 import java.awt.image.PixelGrabber JavaDoc;
21 import java.io.BufferedOutputStream JavaDoc;
22 import java.io.IOException JavaDoc;
23 import java.io.OutputStream JavaDoc;
24 import java.util.Vector JavaDoc;
25
26 /*
27 * JpegEncoder - The JPEG main program which performs a jpeg compression of
28 * an image.
29 */

30
31 public class JpegEncoder extends Frame JavaDoc
32 {
33     Thread JavaDoc runner;
34     BufferedOutputStream JavaDoc outStream;
35     Image JavaDoc image;
36     JpegInfo JpegObj;
37     Huffman Huf;
38     DCT dct;
39     int imageHeight, imageWidth;
40     int Quality;
41     int code;
42     public static int[] jpegNaturalOrder = {
43           0, 1, 8, 16, 9, 2, 3, 10,
44          17, 24, 32, 25, 18, 11, 4, 5,
45          12, 19, 26, 33, 40, 48, 41, 34,
46          27, 20, 13, 6, 7, 14, 21, 28,
47          35, 42, 49, 56, 57, 50, 43, 36,
48          29, 22, 15, 23, 30, 37, 44, 51,
49          58, 59, 52, 45, 38, 31, 39, 46,
50          53, 60, 61, 54, 47, 55, 62, 63,
51         };
52
53     public JpegEncoder(Image JavaDoc image, int quality, OutputStream JavaDoc out)
54     {
55                 MediaTracker JavaDoc tracker = new MediaTracker JavaDoc(this);
56                 tracker.addImage(image, 0);
57                 try {
58                         tracker.waitForID(0);
59                 }
60                 catch (InterruptedException JavaDoc e) {
61                     //TODO
62
}
63         /*
64         * Quality of the image.
65         * 0 to 100 and from bad image quality, high compression to good
66         * image quality low compression
67         */

68         Quality=quality;
69
70         /*
71         * Getting picture information
72         * It takes the Width, Height and RGB scans of the image.
73         */

74         JpegObj = new JpegInfo(image);
75
76         imageHeight=JpegObj.imageHeight;
77         imageWidth=JpegObj.imageWidth;
78         outStream = new BufferedOutputStream JavaDoc(out);
79         dct = new DCT(Quality);
80         Huf=new Huffman(imageWidth,imageHeight);
81     }
82
83     public void setQuality(int quality) {
84         dct = new DCT(quality);
85     }
86
87     public int getQuality() {
88         return Quality;
89     }
90
91     public void Compress() {
92         WriteHeaders(outStream);
93         WriteCompressedData(outStream);
94         WriteEOI(outStream);
95         try {
96                 outStream.flush();
97         } catch (IOException JavaDoc e) {
98             //TODO
99
System.out.println("IO Error: " + e.getMessage());
100         }
101     }
102
103     public void WriteCompressedData(BufferedOutputStream JavaDoc outStream) {
104         int i, j, r, c,a ,b;
105         int comp, xpos, ypos, xblockoffset, yblockoffset;
106         float inputArray[][];
107         float dctArray1[][] = new float[8][8];
108         double dctArray2[][] = new double[8][8];
109         int dctArray3[] = new int[8*8];
110
111         /*
112          * This method controls the compression of the image.
113          * Starting at the upper left of the image, it compresses 8x8 blocks
114          * of data until the entire image has been compressed.
115          */

116
117         int lastDCvalue[] = new int[JpegObj.NumberOfComponents];
118         //int zeroArray[] = new int[64]; // initialized to hold all zeros
119
//int Width = 0, Height = 0;
120
//int nothing = 0, not;
121
int MinBlockWidth, MinBlockHeight;
122 // This initial setting of MinBlockWidth and MinBlockHeight is done to
123
// ensure they start with values larger than will actually be the case.
124
MinBlockWidth = ((imageWidth%8 != 0) ? (int) (Math.floor(imageWidth/8d) + 1)*8 : imageWidth);
125         MinBlockHeight = ((imageHeight%8 != 0) ? (int) (Math.floor(imageHeight/8d) + 1)*8: imageHeight);
126         for (comp = 0; comp < JpegObj.NumberOfComponents; comp++) {
127                 MinBlockWidth = Math.min(MinBlockWidth, JpegObj.BlockWidth[comp]);
128                 MinBlockHeight = Math.min(MinBlockHeight, JpegObj.BlockHeight[comp]);
129         }
130         xpos = 0;
131         for (r = 0; r < MinBlockHeight; r++) {
132            for (c = 0; c < MinBlockWidth; c++) {
133                xpos = c*8;
134                ypos = r*8;
135                for (comp = 0; comp < JpegObj.NumberOfComponents; comp++) {
136                   //Width = JpegObj.BlockWidth[comp];
137
//Height = JpegObj.BlockHeight[comp];
138
inputArray = JpegObj.Components[comp];
139
140                   for(i = 0; i < JpegObj.VsampFactor[comp]; i++) {
141                      for(j = 0; j < JpegObj.HsampFactor[comp]; j++) {
142                         xblockoffset = j * 8;
143                         yblockoffset = i * 8;
144                         for (a = 0; a < 8; a++) {
145                            for (b = 0; b < 8; b++) {
146
147 // I believe this is where the dirty line at the bottom of the image is
148
// coming from. I need to do a check here to make sure I'm not reading past
149
// image data.
150
// This seems to not be a big issue right now. (04/04/98)
151

152                               dctArray1[a][b] = inputArray[ypos + yblockoffset + a][xpos + xblockoffset + b];
153                            }
154                         }
155 // The following code commented out because on some images this technique
156
// results in poor right and bottom borders.
157
// if ((!JpegObj.lastColumnIsDummy[comp] || c < Width - 1) && (!JpegObj.lastRowIsDummy[comp] || r < Height - 1)) {
158
dctArray2 = dct.forwardDCT(dctArray1);
159                            dctArray3 = dct.quantizeBlock(dctArray2, JpegObj.QtableNumber[comp]);
160 // }
161
// else {
162
// zeroArray[0] = dctArray3[0];
163
// zeroArray[0] = lastDCvalue[comp];
164
// dctArray3 = zeroArray;
165
// }
166
Huf.HuffmanBlockEncoder(outStream, dctArray3, lastDCvalue[comp], JpegObj.DCtableNumber[comp], JpegObj.ACtableNumber[comp]);
167                         lastDCvalue[comp] = dctArray3[0];
168                      }
169                   }
170                }
171             }
172         }
173         Huf.flushBuffer(outStream);
174     }
175
176     public void WriteEOI(BufferedOutputStream JavaDoc out) {
177         byte[] EOI = {(byte) 0xFF, (byte) 0xD9};
178         WriteMarker(EOI, out);
179     }
180
181     public void WriteHeaders(BufferedOutputStream JavaDoc out) {
182         int i, j, index, offset, length;
183         int tempArray[];
184
185 // the SOI marker
186
byte[] SOI = {(byte) 0xFF, (byte) 0xD8};
187         WriteMarker(SOI, out);
188
189 // The order of the following headers is quiet inconsequential.
190
// the JFIF header
191
byte JFIF[] = new byte[18];
192         JFIF[0] = (byte) 0xff;
193         JFIF[1] = (byte) 0xe0;
194         JFIF[2] = (byte) 0x00;
195         JFIF[3] = (byte) 0x10;
196         JFIF[4] = (byte) 0x4a;
197         JFIF[5] = (byte) 0x46;
198         JFIF[6] = (byte) 0x49;
199         JFIF[7] = (byte) 0x46;
200         JFIF[8] = (byte) 0x00;
201         JFIF[9] = (byte) 0x01;
202         JFIF[10] = (byte) 0x00;
203         JFIF[11] = (byte) 0x00;
204         JFIF[12] = (byte) 0x00;
205         JFIF[13] = (byte) 0x01;
206         JFIF[14] = (byte) 0x00;
207         JFIF[15] = (byte) 0x01;
208         JFIF[16] = (byte) 0x00;
209         JFIF[17] = (byte) 0x00;
210         WriteArray(JFIF, out);
211
212 // Comment Header
213
String JavaDoc comment = new String JavaDoc();
214         comment = JpegObj.getComment();
215         length = comment.length();
216         byte COM[] = new byte[length + 4];
217         COM[0] = (byte) 0xFF;
218         COM[1] = (byte) 0xFE;
219         COM[2] = (byte) ((length >> 8) & 0xFF);
220         COM[3] = (byte) (length & 0xFF);
221         java.lang.System.arraycopy(JpegObj.Comment.getBytes(), 0, COM, 4, JpegObj.Comment.length());
222         WriteArray(COM, out);
223
224 // The DQT header
225
// 0 is the luminance index and 1 is the chrominance index
226
byte DQT[] = new byte[134];
227         DQT[0] = (byte) 0xFF;
228         DQT[1] = (byte) 0xDB;
229         DQT[2] = (byte) 0x00;
230         DQT[3] = (byte) 0x84;
231         offset = 4;
232         for (i = 0; i < 2; i++) {
233                 DQT[offset++] = (byte) ((0 << 4) + i);
234                 tempArray = dct.quantum[i];
235                 for (j = 0; j < 64; j++) {
236                         DQT[offset++] = (byte) tempArray[jpegNaturalOrder[j]];
237                 }
238         }
239         WriteArray(DQT, out);
240
241 // Start of Frame Header
242
byte SOF[] = new byte[19];
243         SOF[0] = (byte) 0xFF;
244         SOF[1] = (byte) 0xC0;
245         SOF[2] = (byte) 0x00;
246         SOF[3] = (byte) 17;
247         SOF[4] = (byte) JpegObj.Precision;
248         SOF[5] = (byte) ((JpegObj.imageHeight >> 8) & 0xFF);
249         SOF[6] = (byte) ((JpegObj.imageHeight) & 0xFF);
250         SOF[7] = (byte) ((JpegObj.imageWidth >> 8) & 0xFF);
251         SOF[8] = (byte) ((JpegObj.imageWidth) & 0xFF);
252         SOF[9] = (byte) JpegObj.NumberOfComponents;
253         index = 10;
254         for (i = 0; i < SOF[9]; i++) {
255                 SOF[index++] = (byte) JpegObj.CompID[i];
256                 SOF[index++] = (byte) ((JpegObj.HsampFactor[i] << 4) + JpegObj.VsampFactor[i]);
257                 SOF[index++] = (byte) JpegObj.QtableNumber[i];
258         }
259         WriteArray(SOF, out);
260
261 // The DHT Header
262
byte DHT1[], DHT2[], DHT3[], DHT4[];
263         int bytes, temp, oldindex, intermediateindex;
264         length = 2;
265         index = 4;
266         oldindex = 4;
267         DHT1 = new byte[17];
268         DHT4 = new byte[4];
269         DHT4[0] = (byte) 0xFF;
270         DHT4[1] = (byte) 0xC4;
271         for (i = 0; i < 4; i++ ) {
272                 bytes = 0;
273                 DHT1[index++ - oldindex] = (byte) ((int[]) Huf.bits.elementAt(i))[0];
274                 for (j = 1; j < 17; j++) {
275                         temp = ((int[]) Huf.bits.elementAt(i))[j];
276                         DHT1[index++ - oldindex] =(byte) temp;
277                         bytes += temp;
278                 }
279                 intermediateindex = index;
280                 DHT2 = new byte[bytes];
281                 for (j = 0; j < bytes; j++) {
282                         DHT2[index++ - intermediateindex] = (byte) ((int[]) Huf.val.elementAt(i))[j];
283                 }
284                 DHT3 = new byte[index];
285                 java.lang.System.arraycopy(DHT4, 0, DHT3, 0, oldindex);
286                 java.lang.System.arraycopy(DHT1, 0, DHT3, oldindex, 17);
287                 java.lang.System.arraycopy(DHT2, 0, DHT3, oldindex + 17, bytes);
288                 DHT4 = DHT3;
289                 oldindex = index;
290         }
291         DHT4[2] = (byte) (((index - 2) >> 8)& 0xFF);
292         DHT4[3] = (byte) ((index -2) & 0xFF);
293         WriteArray(DHT4, out);
294
295
296 // Start of Scan Header
297
byte SOS[] = new byte[14];
298         SOS[0] = (byte) 0xFF;
299         SOS[1] = (byte) 0xDA;
300         SOS[2] = (byte) 0x00;
301         SOS[3] = (byte) 12;
302         SOS[4] = (byte) JpegObj.NumberOfComponents;
303         index = 5;
304         for (i = 0; i < SOS[4]; i++) {
305                 SOS[index++] = (byte) JpegObj.CompID[i];
306                 SOS[index++] = (byte) ((JpegObj.DCtableNumber[i] << 4) + JpegObj.ACtableNumber[i]);
307         }
308         SOS[index++] = (byte) JpegObj.Ss;
309         SOS[index++] = (byte) JpegObj.Se;
310         SOS[index++] = (byte) ((JpegObj.Ah << 4) + JpegObj.Al);
311         WriteArray(SOS, out);
312
313     }
314
315     void WriteMarker(byte[] data, BufferedOutputStream JavaDoc out) {
316         try {
317                 out.write(data, 0, 2);
318         } catch (IOException JavaDoc e) {
319             //TODO
320
System.out.println("IO Error: " + e.getMessage());
321         }
322     }
323
324     void WriteArray(byte[] data, BufferedOutputStream JavaDoc out) {
325         int length;
326         try {
327                 length = ((data[2] & 0xFF) << 8) + (data[3] & 0xFF) + 2;
328                 out.write(data, 0, length);
329         } catch (IOException JavaDoc e) {
330             //TODO
331
System.out.println("IO Error: " + e.getMessage());
332         }
333     }
334 }
335
336 // This class incorporates quality scaling as implemented in the JPEG-6a
337
// library.
338

339  /*
340  * DCT - A Java implementation of the Discreet Cosine Transform
341  */

342
343 class DCT
344 {
345     /**
346      * DCT Block Size - default 8
347      */

348     public int N = 8;
349
350     /**
351      * Image Quality (0-100) - default 80 (good image / good compression)
352      */

353     public int QUALITY = 80;
354
355     public int quantum[][] = new int[2][];
356     public double Divisors[][] = new double[2][];
357
358     /**
359      * Quantitization Matrix for luminace.
360      */

361     public int quantum_luminance[] = new int[N*N];
362     public double DivisorsLuminance[] = new double[N*N];
363
364     /**
365      * Quantitization Matrix for chrominance.
366      */

367     public int quantum_chrominance[] = new int[N*N];
368     public double DivisorsChrominance[] = new double[N*N];
369
370     /**
371      * Constructs a new DCT object. Initializes the cosine transform matrix
372      * these are used when computing the DCT and it's inverse. This also
373      * initializes the run length counters and the ZigZag sequence. Note that
374      * the image quality can be worse than 25 however the image will be
375      * extemely pixelated, usually to a block size of N.
376      *
377      * @param QUALITY The quality of the image (0 worst - 100 best)
378      *
379      */

380     public DCT(int QUALITY)
381     {
382         initMatrix(QUALITY);
383     }
384
385
386     /*
387      * This method sets up the quantization matrix for luminance and
388      * chrominance using the Quality parameter.
389      */

390     private void initMatrix(int quality)
391     {
392         double[] AANscaleFactor = { 1.0, 1.387039845, 1.306562965, 1.175875602,
393                                     1.0, 0.785694958, 0.541196100, 0.275899379};
394         int i;
395         int j;
396         int index;
397         int Quality;
398         int temp;
399
400 // converting quality setting to that specified in the jpeg_quality_scaling
401
// method in the IJG Jpeg-6a C libraries
402

403         Quality = quality;
404         if (Quality <= 0)
405                 Quality = 1;
406         if (Quality > 100)
407                 Quality = 100;
408         if (Quality < 50)
409                 Quality = 5000 / Quality;
410         else
411                 Quality = 200 - Quality * 2;
412
413 // Creating the luminance matrix
414

415         quantum_luminance[0]=16;
416         quantum_luminance[1]=11;
417         quantum_luminance[2]=10;
418         quantum_luminance[3]=16;
419         quantum_luminance[4]=24;
420         quantum_luminance[5]=40;
421         quantum_luminance[6]=51;
422         quantum_luminance[7]=61;
423         quantum_luminance[8]=12;
424         quantum_luminance[9]=12;
425         quantum_luminance[10]=14;
426         quantum_luminance[11]=19;
427         quantum_luminance[12]=26;
428         quantum_luminance[13]=58;
429         quantum_luminance[14]=60;
430         quantum_luminance[15]=55;
431         quantum_luminance[16]=14;
432         quantum_luminance[17]=13;
433         quantum_luminance[18]=16;
434         quantum_luminance[19]=24;
435         quantum_luminance[20]=40;
436         quantum_luminance[21]=57;
437         quantum_luminance[22]=69;
438         quantum_luminance[23]=56;
439         quantum_luminance[24]=14;
440         quantum_luminance[25]=17;
441         quantum_luminance[26]=22;
442         quantum_luminance[27]=29;
443         quantum_luminance[28]=51;
444         quantum_luminance[29]=87;
445         quantum_luminance[30]=80;
446         quantum_luminance[31]=62;
447         quantum_luminance[32]=18;
448         quantum_luminance[33]=22;
449         quantum_luminance[34]=37;
450         quantum_luminance[35]=56;
451         quantum_luminance[36]=68;
452         quantum_luminance[37]=109;
453         quantum_luminance[38]=103;
454         quantum_luminance[39]=77;
455         quantum_luminance[40]=24;
456         quantum_luminance[41]=35;
457         quantum_luminance[42]=55;
458         quantum_luminance[43]=64;
459         quantum_luminance[44]=81;
460         quantum_luminance[45]=104;
461         quantum_luminance[46]=113;
462         quantum_luminance[47]=92;
463         quantum_luminance[48]=49;
464         quantum_luminance[49]=64;
465         quantum_luminance[50]=78;
466         quantum_luminance[51]=87;
467         quantum_luminance[52]=103;
468         quantum_luminance[53]=121;
469         quantum_luminance[54]=120;
470         quantum_luminance[55]=101;
471         quantum_luminance[56]=72;
472         quantum_luminance[57]=92;
473         quantum_luminance[58]=95;
474         quantum_luminance[59]=98;
475         quantum_luminance[60]=112;
476         quantum_luminance[61]=100;
477         quantum_luminance[62]=103;
478         quantum_luminance[63]=99;
479
480         for (j = 0; j < 64; j++)
481         {
482                 temp = (quantum_luminance[j] * Quality + 50) / 100;
483                 if ( temp <= 0) temp = 1;
484                 if (temp > 255) temp = 255;
485                 quantum_luminance[j] = temp;
486         }
487         index = 0;
488         for (i = 0; i < 8; i++) {
489                 for (j = 0; j < 8; j++) {
490 // The divisors for the LL&M method (the slow integer method used in
491
// jpeg 6a library). This method is currently (04/04/98) incompletely
492
// implemented.
493
// DivisorsLuminance[index] = ((double) quantum_luminance[index]) << 3;
494
// The divisors for the AAN method (the float method used in jpeg 6a library.
495
DivisorsLuminance[index] = 1d/(8d * quantum_luminance[index] * AANscaleFactor[i] * AANscaleFactor[j]);
496                         index++;
497                 }
498         }
499
500
501 // Creating the chrominance matrix
502

503         quantum_chrominance[0]=17;
504         quantum_chrominance[1]=18;
505         quantum_chrominance[2]=24;
506         quantum_chrominance[3]=47;
507         quantum_chrominance[4]=99;
508         quantum_chrominance[5]=99;
509         quantum_chrominance[6]=99;
510         quantum_chrominance[7]=99;
511         quantum_chrominance[8]=18;
512         quantum_chrominance[9]=21;
513         quantum_chrominance[10]=26;
514         quantum_chrominance[11]=66;
515         quantum_chrominance[12]=99;
516         quantum_chrominance[13]=99;
517         quantum_chrominance[14]=99;
518         quantum_chrominance[15]=99;
519         quantum_chrominance[16]=24;
520         quantum_chrominance[17]=26;
521         quantum_chrominance[18]=56;
522         quantum_chrominance[19]=99;
523         quantum_chrominance[20]=99;
524         quantum_chrominance[21]=99;
525         quantum_chrominance[22]=99;
526         quantum_chrominance[23]=99;
527         quantum_chrominance[24]=47;
528         quantum_chrominance[25]=66;
529         quantum_chrominance[26]=99;
530         quantum_chrominance[27]=99;
531         quantum_chrominance[28]=99;
532         quantum_chrominance[29]=99;
533         quantum_chrominance[30]=99;
534         quantum_chrominance[31]=99;
535         quantum_chrominance[32]=99;
536         quantum_chrominance[33]=99;
537         quantum_chrominance[34]=99;
538         quantum_chrominance[35]=99;
539         quantum_chrominance[36]=99;
540         quantum_chrominance[37]=99;
541         quantum_chrominance[38]=99;
542         quantum_chrominance[39]=99;
543         quantum_chrominance[40]=99;
544         quantum_chrominance[41]=99;
545         quantum_chrominance[42]=99;
546         quantum_chrominance[43]=99;
547         quantum_chrominance[44]=99;
548         quantum_chrominance[45]=99;
549         quantum_chrominance[46]=99;
550         quantum_chrominance[47]=99;
551         quantum_chrominance[48]=99;
552         quantum_chrominance[49]=99;
553         quantum_chrominance[50]=99;
554         quantum_chrominance[51]=99;
555         quantum_chrominance[52]=99;
556         quantum_chrominance[53]=99;
557         quantum_chrominance[54]=99;
558         quantum_chrominance[55]=99;
559         quantum_chrominance[56]=99;
560         quantum_chrominance[57]=99;
561         quantum_chrominance[58]=99;
562         quantum_chrominance[59]=99;
563         quantum_chrominance[60]=99;
564         quantum_chrominance[61]=99;
565         quantum_chrominance[62]=99;
566         quantum_chrominance[63]=99;
567
568         for (j = 0; j < 64; j++)
569         {
570                 temp = (quantum_chrominance[j] * Quality + 50) / 100;
571                 if ( temp <= 0) temp = 1;
572                 if (temp >= 255) temp = 255;
573                 quantum_chrominance[j] = temp;
574         }
575         index = 0;
576         for (i = 0; i < 8; i++) {
577                 for (j = 0; j < 8; j++) {
578 // The divisors for the LL&M method (the slow integer method used in
579
// jpeg 6a library). This method is currently (04/04/98) incompletely
580
// implemented.
581
// DivisorsChrominance[index] = ((double) quantum_chrominance[index]) << 3;
582
// The divisors for the AAN method (the float method used in jpeg 6a library.
583
DivisorsChrominance[index] = 1d/(8d * quantum_chrominance[index] * AANscaleFactor[i] * AANscaleFactor[j]);
584                         index++;
585                 }
586         }
587
588 // quantum and Divisors are objects used to hold the appropriate matices
589

590         quantum[0] = quantum_luminance;
591         Divisors[0] = DivisorsLuminance;
592         quantum[1] = quantum_chrominance;
593         Divisors[1] = DivisorsChrominance;
594
595
596     }
597
598     /*
599      * This method preforms forward DCT on a block of image data using
600      * the literal method specified for a 2-D Discrete Cosine Transform.
601      * It is included as a curiosity and can give you an idea of the
602      * difference in the compression result (the resulting image quality)
603      * by comparing its output to the output of the AAN method below.
604      * It is ridiculously inefficient.
605      */

606
607 // For now the final output is unusable. The associated quantization step
608
// needs some tweaking. If you get this part working, please let me know.
609

610     public double[][] forwardDCTExtreme(float input[][])
611     {
612         double output[][] = new double[N][N];
613         //double tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7;
614
//double tmp10, tmp11, tmp12, tmp13;
615
//double z1, z2, z3, z4, z5, z11, z13;
616
//int i;
617
//int j;
618
int v, u, x, y;
619         for (v = 0; v < 8; v++) {
620                 for (u = 0; u < 8; u++) {
621                         for (x = 0; x < 8; x++) {
622                                 for (y = 0; y < 8; y++) {
623                                         output[v][u] += input[x][y]*Math.cos(((2*x + 1)*(double)u*Math.PI)/16d)*Math.cos(((2*y + 1)*(double)v*Math.PI)/16d);
624                                 }
625                         }
626                         output[v][u] *= 0.25d*((u == 0) ? (1d/Math.sqrt(2)) : 1d)*((v == 0) ? (1d/Math.sqrt(2)) : 1d);
627                 }
628         }
629         return output;
630     }
631
632
633     /*
634      * This method preforms a DCT on a block of image data using the AAN
635      * method as implemented in the IJG Jpeg-6a library.
636      */

637     public double[][] forwardDCT(float input[][])
638     {
639         double output[][] = new double[N][N];
640         double tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7;
641         double tmp10, tmp11, tmp12, tmp13;
642         double z1, z2, z3, z4, z5, z11, z13;
643         int i;
644         int j;
645
646 // Subtracts 128 from the input values
647
for (i = 0; i < 8; i++) {
648                 for(j = 0; j < 8; j++) {
649                         output[i][j] = input[i][j] - 128d;
650 // input[i][j] -= 128;
651

652                 }
653         }
654
655         for (i = 0; i < 8; i++) {
656                 tmp0 = output[i][0] + output[i][7];
657                 tmp7 = output[i][0] - output[i][7];
658                 tmp1 = output[i][1] + output[i][6];
659                 tmp6 = output[i][1] - output[i][6];
660                 tmp2 = output[i][2] + output[i][5];
661                 tmp5 = output[i][2] - output[i][5];
662                 tmp3 = output[i][3] + output[i][4];
663                 tmp4 = output[i][3] - output[i][4];
664
665                 tmp10 = tmp0 + tmp3;
666                 tmp13 = tmp0 - tmp3;
667                 tmp11 = tmp1 + tmp2;
668                 tmp12 = tmp1 - tmp2;
669
670                 output[i][0] = tmp10 + tmp11;
671                 output[i][4] = tmp10 - tmp11;
672
673                 z1 = (tmp12 + tmp13) * 0.707106781d;
674                 output[i][2] = tmp13 + z1;
675                 output[i][6] = tmp13 - z1;
676
677                 tmp10 = tmp4 + tmp5;
678                 tmp11 = tmp5 + tmp6;
679                 tmp12 = tmp6 + tmp7;
680
681                 z5 = (tmp10 - tmp12) * 0.382683433d;
682                 z2 = 0.541196100d * tmp10 + z5;
683                 z4 = 1.306562965d * tmp12 + z5;
684                 z3 = tmp11 * 0.707106781d;
685
686                 z11 = tmp7 + z3;
687                 z13 = tmp7 - z3;
688
689                 output[i][5] = z13 + z2;
690                 output[i][3] = z13 - z2;
691                 output[i][1] = z11 + z4;
692                 output[i][7] = z11 - z4;
693         }
694
695         for (i = 0; i < 8; i++) {
696                 tmp0 = output[0][i] + output[7][i];
697                 tmp7 = output[0][i] - output[7][i];
698                 tmp1 = output[1][i] + output[6][i];
699                 tmp6 = output[1][i] - output[6][i];
700                 tmp2 = output[2][i] + output[5][i];
701                 tmp5 = output[2][i] - output[5][i];
702                 tmp3 = output[3][i] + output[4][i];
703                 tmp4 = output[3][i] - output[4][i];
704
705                 tmp10 = tmp0 + tmp3;
706                 tmp13 = tmp0 - tmp3;
707                 tmp11 = tmp1 + tmp2;
708                 tmp12 = tmp1 - tmp2;
709
710                 output[0][i] = tmp10 + tmp11;
711                 output[4][i] = tmp10 - tmp11;
712
713                 z1 = (tmp12 + tmp13) * 0.707106781d;
714                 output[2][i] = tmp13 + z1;
715                 output[6][i] = tmp13 - z1;
716
717                 tmp10 = tmp4 + tmp5;
718                 tmp11 = tmp5 + tmp6;
719                 tmp12 = tmp6 + tmp7;
720
721                 z5 = (tmp10 - tmp12) * 0.382683433d;
722                 z2 = 0.541196100d * tmp10 + z5;
723                 z4 = 1.306562965d * tmp12 + z5;
724                 z3 = tmp11 * 0.707106781d;
725
726                 z11 = tmp7 + z3;
727                 z13 = tmp7 - z3;
728
729                 output[5][i] = z13 + z2;
730                 output[3][i] = z13 - z2;
731                 output[1][i] = z11 + z4;
732                 output[7][i] = z11 - z4;
733         }
734
735         return output;
736     }
737
738     /*
739     * This method quantitizes data and rounds it to the nearest integer.
740     */

741     public int[] quantizeBlock(double inputData[][], int code)
742     {
743         int outputData[] = new int[N*N];
744         int i, j;
745         int index;
746         index = 0;
747         for (i = 0; i < 8; i++) {
748                 for (j = 0; j < 8; j++) {
749 // The second line results in significantly better compression.
750
outputData[index] = (int)(Math.round(inputData[i][j] * Divisors[code][index]));
751 // outputData[index] = (int)(((inputData[i][j] * (((double[]) (Divisors[code]))[index])) + 16384.5) -16384);
752
index++;
753                 }
754         }
755
756         return outputData;
757     }
758
759     /*
760     * This is the method for quantizing a block DCT'ed with forwardDCTExtreme
761     * This method quantitizes data and rounds it to the nearest integer.
762     */

763     public int[] quantizeBlockExtreme(double inputData[][], int code)
764     {
765         int outputData[] = new int[N*N];
766         int i, j;
767         int index;
768         index = 0;
769         for (i = 0; i < 8; i++) {
770                 for (j = 0; j < 8; j++) {
771                         outputData[index] = (int)(Math.round(inputData[i][j] / quantum[code][index]));
772                         index++;
773                 }
774         }
775
776         return outputData;
777     }
778 }
779
780 // This class was modified by James R. Weeks on 3/27/98.
781
// It now incorporates Huffman table derivation as in the C jpeg library
782
// from the IJG, Jpeg-6a.
783

784 class Huffman
785 {
786     int bufferPutBits, bufferPutBuffer;
787     public int ImageHeight;
788     public int ImageWidth;
789     public int DC_matrix0[][];
790     public int AC_matrix0[][];
791     public int DC_matrix1[][];
792     public int AC_matrix1[][];
793     public int DC_matrix[][][];
794     public int AC_matrix[][][];
795     public int code;
796     public int NumOfDCTables;
797     public int NumOfACTables;
798     public int[] bitsDCluminance = { 0x00, 0, 1, 5, 1, 1,1,1,1,1,0,0,0,0,0,0,0};
799     public int[] valDCluminance = { 0,1,2,3,4,5,6,7,8,9,10,11 };
800     public int[] bitsDCchrominance = { 0x01,0,3,1,1,1,1,1,1,1,1,1,0,0,0,0,0 };
801     public int[] valDCchrominance = { 0,1,2,3,4,5,6,7,8,9,10,11 };
802     public int[] bitsACluminance = {0x10,0,2,1,3,3,2,4,3,5,5,4,4,0,0,1,0x7d };
803     public int[] valACluminance =
804         { 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12,
805           0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07,
806           0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08,
807           0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0,
808           0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16,
809           0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28,
810           0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
811           0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
812           0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
813           0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
814           0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
815           0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
816           0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
817           0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
818           0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
819           0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5,
820           0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4,
821           0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2,
822           0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea,
823           0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
824           0xf9, 0xfa };
825     public int[] bitsACchrominance = { 0x11,0,2,1,2,4,4,3,4,7,5,4,4,0,1,2,0x77 };
826     public int[] valACchrominance =
827         { 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21,
828           0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71,
829           0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91,
830           0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0,
831           0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34,
832           0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26,
833           0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38,
834           0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
835           0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
836           0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
837           0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
838           0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
839           0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96,
840           0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5,
841           0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4,
842           0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3,
843           0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2,
844           0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda,
845           0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9,
846           0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
847           0xf9, 0xfa };
848     public Vector JavaDoc bits;
849     public Vector JavaDoc val;
850
851     /*
852      * jpegNaturalOrder[i] is the natural-order position of the i'th element
853      * of zigzag order.
854      */

855     public static int[] jpegNaturalOrder = {
856           0, 1, 8, 16, 9, 2, 3, 10,
857          17, 24, 32, 25, 18, 11, 4, 5,
858          12, 19, 26, 33, 40, 48, 41, 34,
859          27, 20, 13, 6, 7, 14, 21, 28,
860          35, 42, 49, 56, 57, 50, 43, 36,
861          29, 22, 15, 23, 30, 37, 44, 51,
862          58, 59, 52, 45, 38, 31, 39, 46,
863          53, 60, 61, 54, 47, 55, 62, 63,
864         };
865     /*
866     * The Huffman class constructor
867     */

868         public Huffman(int Width,int Height)
869     {
870
871             bits = new Vector JavaDoc();
872             bits.addElement(bitsDCluminance);
873             bits.addElement(bitsACluminance);
874             bits.addElement(bitsDCchrominance);
875             bits.addElement(bitsACchrominance);
876             val = new Vector JavaDoc();
877             val.addElement(valDCluminance);
878             val.addElement(valACluminance);
879             val.addElement(valDCchrominance);
880             val.addElement(valACchrominance);
881             initHuf();
882             //code=code;
883
ImageWidth=Width;
884             ImageHeight=Height;
885
886     }
887
888    /**
889    * HuffmanBlockEncoder run length encodes and Huffman encodes the quantized
890    * data.
891    **/

892
893         public void HuffmanBlockEncoder(BufferedOutputStream JavaDoc outStream, int zigzag[], int prec, int DCcode, int ACcode)
894     {
895         int temp, temp2, nbits, k, r, i;
896
897         NumOfDCTables = 2;
898         NumOfACTables = 2;
899
900 // The DC portion
901

902         temp = temp2 = zigzag[0] - prec;
903         if(temp < 0) {
904                 temp = -temp;
905                 temp2--;
906         }
907         nbits = 0;
908         while (temp != 0) {
909                 nbits++;
910                 temp >>= 1;
911         }
912 // if (nbits > 11) nbits = 11;
913
bufferIt(outStream, DC_matrix[DCcode][nbits][0], DC_matrix[DCcode][nbits][1]);
914         // The arguments in bufferIt are code and size.
915
if (nbits != 0) {
916                 bufferIt(outStream, temp2, nbits);
917         }
918
919 // The AC portion
920

921         r = 0;
922
923         for (k = 1; k < 64; k++) {
924                 if ((temp = zigzag[jpegNaturalOrder[k]]) == 0) {
925                         r++;
926                 }
927                 else {
928                         while (r > 15) {
929                                 bufferIt(outStream, AC_matrix[ACcode][0xF0][0], AC_matrix[ACcode][0xF0][1]);
930                                 r -= 16;
931                         }
932                         temp2 = temp;
933                         if (temp < 0) {
934                                 temp = -temp;
935                                 temp2--;
936                         }
937                         nbits = 1;
938                         while ((temp >>= 1) != 0) {
939                                 nbits++;
940                         }
941                         i = (r << 4) + nbits;
942                         bufferIt(outStream, AC_matrix[ACcode][i][0], AC_matrix[ACcode][i][1]);
943                         bufferIt(outStream, temp2, nbits);
944
945                         r = 0;
946                 }
947         }
948
949         if (r > 0) {
950                 bufferIt(outStream, AC_matrix[ACcode][0][0], AC_matrix[ACcode][0][1]);
951         }
952
953     }
954
955 // Uses an integer long (32 bits) buffer to store the Huffman encoded bits
956
// and sends them to outStream by the byte.
957

958         void bufferIt(BufferedOutputStream JavaDoc outStream, int code,int size)
959     {
960         int PutBuffer = code;
961         int PutBits = bufferPutBits;
962
963         PutBuffer &= (1 << size) - 1;
964         PutBits += size;
965         PutBuffer <<= 24 - PutBits;
966         PutBuffer |= bufferPutBuffer;
967
968         while(PutBits >= 8) {
969                 int c = ((PutBuffer >> 16) & 0xFF);
970                 try
971                 {
972                         outStream.write(c);
973                 }
974                 catch (IOException JavaDoc e) {
975                     //TODO
976
System.out.println("IO Error: " + e.getMessage());
977                 }
978                 if (c == 0xFF) {
979                         try
980                         {
981                                 outStream.write(0);
982                         }
983                         catch (IOException JavaDoc e) {
984                             //TODO
985
System.out.println("IO Error: " + e.getMessage());
986                         }
987                 }
988                 PutBuffer <<= 8;
989                 PutBits -= 8;
990         }
991         bufferPutBuffer = PutBuffer;
992         bufferPutBits = PutBits;
993
994         }
995
996         void flushBuffer(BufferedOutputStream JavaDoc outStream) {
997                 int PutBuffer = bufferPutBuffer;
998                 int PutBits = bufferPutBits;
999                 while (PutBits >= 8) {
1000                        int c = ((PutBuffer >> 16) & 0xFF);
1001                        try
1002                        {
1003                                outStream.write(c);
1004                        }
1005                        catch (IOException JavaDoc e) {
1006                            //TODO
1007
System.out.println("IO Error: " + e.getMessage());
1008                        }
1009                        if (c == 0xFF) {
1010                                try {
1011                                        outStream.write(0);
1012                                }
1013                                catch (IOException JavaDoc e) {
1014                                    //TODO
1015
System.out.println("IO Error: " + e.getMessage());
1016                                }
1017                        }
1018                        PutBuffer <<= 8;
1019                        PutBits -= 8;
1020                }
1021                if (PutBits > 0) {
1022                        int c = ((PutBuffer >> 16) & 0xFF);
1023                        try
1024                        {
1025                                outStream.write(c);
1026                        }
1027                        catch (IOException JavaDoc e) {
1028                            //TODO
1029
System.out.println("IO Error: " + e.getMessage());
1030                        }
1031                }
1032        }
1033
1034    /*
1035    * Initialisation of the Huffman codes for Luminance and Chrominance.
1036    * This code results in the same tables created in the IJG Jpeg-6a
1037    * library.
1038    */

1039
1040    public void initHuf()
1041    {
1042        DC_matrix0=new int[12][2];
1043        DC_matrix1=new int[12][2];
1044        AC_matrix0=new int[255][2];
1045        AC_matrix1=new int[255][2];
1046        DC_matrix = new int[2][][];
1047        AC_matrix = new int[2][][];
1048        int p, l, i, lastp, si, code;
1049        int[] huffsize = new int[257];
1050        int[] huffcode= new int[257];
1051
1052        /*
1053        * init of the DC values for the chrominance
1054        * [][0] is the code [][1] is the number of bit
1055        */

1056
1057        p = 0;
1058        for (l = 1; l <= 16; l++)
1059        {
1060                for (i = 1; i <= bitsDCchrominance[l]; i++)
1061                {
1062                        huffsize[p++] = l;
1063                }
1064        }
1065        huffsize[p] = 0;
1066        lastp = p;
1067
1068        code = 0;
1069        si = huffsize[0];
1070        p = 0;
1071        while(huffsize[p] != 0)
1072        {
1073                while(huffsize[p] == si)
1074                {
1075                        huffcode[p++] = code;
1076                        code++;
1077                }
1078                code <<= 1;
1079                si++;
1080        }
1081
1082        for (p = 0; p < lastp; p++)
1083        {
1084                DC_matrix1[valDCchrominance[p]][0] = huffcode[p];
1085                DC_matrix1[valDCchrominance[p]][1] = huffsize[p];
1086        }
1087
1088        /*
1089        * Init of the AC hufmann code for the chrominance
1090        * matrix [][][0] is the code & matrix[][][1] is the number of bit needed
1091        */

1092
1093        p = 0;
1094        for (l = 1; l <= 16; l++)
1095        {
1096                for (i = 1; i <= bitsACchrominance[l]; i++)
1097                {
1098                        huffsize[p++] = l;
1099                }
1100        }
1101        huffsize[p] = 0;
1102        lastp = p;
1103
1104        code = 0;
1105        si = huffsize[0];
1106        p = 0;
1107        while(huffsize[p] != 0)
1108        {
1109                while(huffsize[p] == si)
1110                {
1111                        huffcode[p++] = code;
1112                        code++;
1113                }
1114                code <<= 1;
1115                si++;
1116        }
1117
1118        for (p = 0; p < lastp; p++)
1119        {
1120                AC_matrix1[valACchrominance[p]][0] = huffcode[p];
1121                AC_matrix1[valACchrominance[p]][1] = huffsize[p];
1122        }
1123
1124        /*
1125        * init of the DC values for the luminance
1126        * [][0] is the code [][1] is the number of bit
1127        */

1128        p = 0;
1129        for (l = 1; l <= 16; l++)
1130        {
1131                for (i = 1; i <= bitsDCluminance[l]; i++)
1132                {
1133                        huffsize[p++] = l;
1134                }
1135        }
1136        huffsize[p] = 0;
1137        lastp = p;
1138
1139        code = 0;
1140        si = huffsize[0];
1141        p = 0;
1142        while(huffsize[p] != 0)
1143        {
1144                while(huffsize[p] == si)
1145                {
1146                        huffcode[p++] = code;
1147                        code++;
1148                }
1149                code <<= 1;
1150                si++;
1151        }
1152
1153        for (p = 0; p < lastp; p++)
1154        {
1155                DC_matrix0[valDCluminance[p]][0] = huffcode[p];
1156                DC_matrix0[valDCluminance[p]][1] = huffsize[p];
1157        }
1158
1159        /*
1160        * Init of the AC hufmann code for luminance
1161        * matrix [][][0] is the code & matrix[][][1] is the number of bit
1162        */

1163
1164        p = 0;
1165        for (l = 1; l <= 16; l++)
1166        {
1167                for (i = 1; i <= bitsACluminance[l]; i++)
1168                {
1169                        huffsize[p++] = l;
1170                }
1171        }
1172        huffsize[p] = 0;
1173        lastp = p;
1174
1175        code = 0;
1176        si = huffsize[0];
1177        p = 0;
1178        while(huffsize[p] != 0)
1179        {
1180                while(huffsize[p] == si)
1181                {
1182                        huffcode[p++] = code;
1183                        code++;
1184                }
1185                code <<= 1;
1186                si++;
1187        }
1188        for (int q = 0; q < lastp; q++)
1189        {
1190                AC_matrix0[valACluminance[q]][0] = huffcode[q];
1191                AC_matrix0[valACluminance[q]][1] = huffsize[q];
1192        }
1193
1194        DC_matrix[0] = DC_matrix0;
1195        DC_matrix[1] = DC_matrix1;
1196        AC_matrix[0] = AC_matrix0;
1197        AC_matrix[1] = AC_matrix1;
1198    }
1199
1200}
1201
1202/*
1203 * JpegInfo - Given an image, sets default information about it and divides
1204 * it into its constituant components, downsizing those that need to be.
1205 */

1206
1207class JpegInfo
1208{
1209    String JavaDoc Comment;
1210    public Image JavaDoc imageobj;
1211    public int imageHeight;
1212    public int imageWidth;
1213    public int BlockWidth[];
1214    public int BlockHeight[];
1215
1216// the following are set as the default
1217
public int Precision = 8;
1218    public int NumberOfComponents = 3;
1219    public float Components[][][];
1220    public int[] CompID = {1, 2, 3};
1221    public int[] HsampFactor = {1, 1, 1};
1222    public int[] VsampFactor = {1, 1, 1};
1223    public int[] QtableNumber = {0, 1, 1};
1224    public int[] DCtableNumber = {0, 1, 1};
1225    public int[] ACtableNumber = {0, 1, 1};
1226    public boolean[] lastColumnIsDummy = {false, false, false};
1227    public boolean[] lastRowIsDummy = {false, false, false};
1228    public int Ss = 0;
1229    public int Se = 63;
1230    public int Ah = 0;
1231    public int Al = 0;
1232    public int compWidth[], compHeight[];
1233    public int MaxHsampFactor;
1234    public int MaxVsampFactor;
1235
1236
1237    public JpegInfo(Image JavaDoc image)
1238    {
1239        Components = new float[NumberOfComponents][][];
1240        compWidth = new int[NumberOfComponents];
1241        compHeight = new int[NumberOfComponents];
1242        BlockWidth = new int[NumberOfComponents];
1243        BlockHeight = new int[NumberOfComponents];
1244        imageobj = image;
1245        imageWidth = image.getWidth(null);
1246        imageHeight = image.getHeight(null);
1247        Comment = "JPEG Encoder Copyright 1998, James R. Weeks and BioElectroMech. ";
1248        getYCCArray();
1249    }
1250
1251    public void setComment(String JavaDoc comment) {
1252        Comment.concat(comment);
1253    }
1254
1255    public String JavaDoc getComment() {
1256        return Comment;
1257    }
1258
1259    /*
1260     * This method creates and fills three arrays, Y, Cb, and Cr using the
1261     * input image.
1262     */

1263
1264    private void getYCCArray()
1265    {
1266        int values[] = new int[imageWidth * imageHeight];
1267        int r, g, b, y, x;
1268// In order to minimize the chance that grabPixels will throw an exception
1269
// it may be necessary to grab some pixels every few scanlines and process
1270
// those before going for more. The time expense may be prohibitive.
1271
// However, for a situation where memory overhead is a concern, this may be
1272
// the only choice.
1273
PixelGrabber JavaDoc grabber = new PixelGrabber JavaDoc(imageobj.getSource(), 0, 0, imageWidth, imageHeight, values, 0, imageWidth);
1274        MaxHsampFactor = 1;
1275        MaxVsampFactor = 1;
1276        for (y = 0; y < NumberOfComponents; y++) {
1277                MaxHsampFactor = Math.max(MaxHsampFactor, HsampFactor[y]);
1278                MaxVsampFactor = Math.max(MaxVsampFactor, VsampFactor[y]);
1279        }
1280        for (y = 0; y < NumberOfComponents; y++) {
1281                compWidth[y] = (((imageWidth%8 != 0) ? ((int) Math.ceil(imageWidth/8d))*8 : imageWidth)/MaxHsampFactor)*HsampFactor[y];
1282                if (compWidth[y] != ((imageWidth/MaxHsampFactor)*HsampFactor[y])) {
1283                        lastColumnIsDummy[y] = true;
1284                }
1285                // results in a multiple of 8 for compWidth
1286
// this will make the rest of the program fail for the unlikely
1287
// event that someone tries to compress an 16 x 16 pixel image
1288
// which would of course be worse than pointless
1289
BlockWidth[y] = (int) Math.ceil(compWidth[y]/8d);
1290                compHeight[y] = (((imageHeight%8 != 0) ? ((int) Math.ceil(imageHeight/8d))*8: imageHeight)/MaxVsampFactor)*VsampFactor[y];
1291                if (compHeight[y] != ((imageHeight/MaxVsampFactor)*VsampFactor[y])) {
1292                        lastRowIsDummy[y] = true;
1293                }
1294                BlockHeight[y] = (int) Math.ceil(compHeight[y]/8d);
1295        }
1296        try
1297        {
1298            if(grabber.grabPixels() != true)
1299            {
1300                try
1301                {
1302                    throw new AWTException JavaDoc("Grabber returned false: " + grabber.status());
1303                }
1304                catch (Exception JavaDoc e)
1305                {
1306                    //TODO
1307
}
1308            }
1309        }
1310        catch (InterruptedException JavaDoc e)
1311        {
1312            //TODO
1313
}
1314        float Y[][] = new float[compHeight[0]][compWidth[0]];
1315        float Cr1[][] = new float[compHeight[0]][compWidth[0]];
1316        float Cb1[][] = new float[compHeight[0]][compWidth[0]];
1317        //float Cb2[][] = new float[compHeight[1]][compWidth[1]];
1318
//float Cr2[][] = new float[compHeight[2]][compWidth[2]];
1319
int index = 0;
1320        for (y = 0; y < imageHeight; ++y)
1321        {
1322            for (x = 0; x < imageWidth; ++x)
1323            {
1324                r = ((values[index] >> 16) & 0xff);
1325                g = ((values[index] >> 8) & 0xff);
1326                b = (values[index] & 0xff);
1327
1328// The following three lines are a more correct color conversion but
1329
// the current conversion technique is sufficient and results in a higher
1330
// compression rate.
1331
// Y[y][x] = 16 + (float)(0.8588*(0.299 * (float)r + 0.587 * (float)g + 0.114 * (float)b ));
1332
// Cb1[y][x] = 128 + (float)(0.8784*(-0.16874 * (float)r - 0.33126 * (float)g + 0.5 * (float)b));
1333
// Cr1[y][x] = 128 + (float)(0.8784*(0.5 * (float)r - 0.41869 * (float)g - 0.08131 * (float)b));
1334
Y[y][x] = (float)(0.299 * r + 0.587 * g + 0.114 * b);
1335                Cb1[y][x] = 128 + (float)(-0.16874 * r - 0.33126 * g + 0.5 * b);
1336                Cr1[y][x] = 128 + (float)(0.5 * r - 0.41869 * g - 0.08131 * b);
1337                index++;
1338            }
1339        }
1340
1341// Need a way to set the H and V sample factors before allowing downsampling.
1342
// For now (04/04/98) downsampling must be hard coded.
1343
// Until a better downsampler is implemented, this will not be done.
1344
// Downsampling is currently supported. The downsampling method here
1345
// is a simple box filter.
1346

1347        Components[0] = Y;
1348// Cb2 = DownSample(Cb1, 1);
1349
Components[1] = Cb1;
1350// Cr2 = DownSample(Cr1, 2);
1351
Components[2] = Cr1;
1352    }
1353
1354    float[][] DownSample(float[][] C, int comp)
1355    {
1356        int inrow, incol;
1357        int outrow, outcol;
1358        float output[][];
1359        //int temp;
1360
int bias;
1361        inrow = 0;
1362        incol = 0;
1363        output = new float[compHeight[comp]][compWidth[comp]];
1364        for (outrow = 0; outrow < compHeight[comp]; outrow++) {
1365                bias = 1;
1366                for (outcol = 0; outcol < compWidth[comp]; outcol++) {
1367                        output[outrow][outcol] = (C[inrow][incol++] + C[inrow++][incol--] + C[inrow][incol++] + C[inrow--][incol++] + bias)/4f;
1368                        bias ^= 3;
1369                }
1370                inrow += 2;
1371                incol = 0;
1372        }
1373        return output;
1374    }
1375}
1376
Popular Tags