Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: Acme/JPM/Encoders/GrayJPEG.java


1   //////////////////////// DISCLAIMER \\\\\\\\\\\\\\\\\\\\\\\\\
2   //                                                         \\
3   // This software is provided by Sean Patrick Breslin for   \\
4   // your use or abuse, free of charge and royalties. This   \\
5   // software is provide 'AS IS' and as such there are no    \\
6   // warrenties expressed or implied. This software is by    \\
7   // no means robust, optimized, efficient, tight or any of  \\
8   // a number of adjectives used to describe software. This  \\
9   // in mind, this software is not to be used for nuclear    \\
10  // applications, world domination schemes or discount      \\
11  // remote laser surgery.  You may copy or modify this      \\
12  // code as you see fit.  This code works on my PC other    \\
13  // than that I cannot help you with this code in any way.  \\
14  // I have not decided whether or not I will support this   \\
15  // code with bug fixes or enhancements but I'll think      \\
16  // about it.                                               \\
17  //                                                         \\
18  // USAGE:  instanciate the class:                          \\
19  //                  GrayJPEG jpg = new GrayJPEG();         \\
20  //                                                         \\ 
21  //         and call the method:                            \\
22  //                  jpg.compress(Image i, OutputStream os) \\
23  //                                                         \\
24  //         Where 'i' is a standard Java Image object and   \\
25  //         'os' is an output stream where you want the     \\
26  //         JPEG file written.                              \\
27  //                                                         \\
28  // NOTE:   This code will only compress a grayscale image  \\
29  //         i.e. Black and White, though a color image will \\
30  //         not crash the code the results are unknown.     \\
31  //                                                         \\
32  // PS:     I have compiled this with Java 1.0.2 and 1.1.3  \\
33  //         and it works under both versions using windows  \\
34  //         95 operating system, so knock yourself out and  \\
35  //         have fun with my code.                          \\
36  //                                                         \\
37  ///////////////////////////////\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
38  package Acme.JPM.Encoders;
39  
40  import java.awt.*;
41  import java.awt.image.*;
42  
43  import java.io.*;
44  
45  import java.net.*;
46  
47  
48  /**
49   * DOCUMENT ME!
50   *
51   * @cvsversion    $Revision: 1.2 $, $Date: 2003/10/16 08:49:27 $
52   */
53  public class GrayJPEG
54  {
55      //~ Instance fields ////////////////////////////////////////////////////////
56  
57      private Image image;
58      private OutputStream fos;
59  
60      // Header data
61      private String str = "JFIF Breslin Engineering JPEG Image Compression";
62      private byte[] APP0;
63      private byte[] BE;
64      private int[] BITS = new int[17];
65  
66      // AC Huffman table
67      private byte[] Bits = {0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 125};
68      private int[] EHUFCO = new int[257];
69      private int[] EHUFSI = new int[257];
70      private byte[] EOI = {-1, -39};
71      private int[] HUFFCODE = new int[257];
72      private int[] HUFFSIZE = new int[257];
73      private int[] HUFFVAL = new int[162];
74      private byte[] HuffACHeader = {-1, -60, 0, -75, 16};
75      private byte[] HuffDC = 
76      {
77          -1, -60, 0, 31, 0, 0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1,
78          2, 3, 4, 5, 6, 7, 8, 9, 10, 11
79      };
80      private byte[] Huffval = 
81      {
82          1, 2, 3, 0, 4, 17, 5, 18, 33, 49, 65, 6, 19, 81, 97, 7, 34, 113, 20, 50,
83          -127, -111, -95, 8, 35, 66, -79, -63, 21, 82, -47, -16, 36, 51, 98, 114,
84          -126, 9, 10, 22, 23, 24, 25, 26, 37, 38, 39, 40, 41, 42, 52, 53, 54, 55,
85          56, 57, 58, 67, 68, 69, 70, 71, 72, 73, 74, 83, 84, 85, 86, 87, 88, 89,
86          90, 99, 100, 101, 102, 103, 104, 105, 106, 115, 116, 117, 118, 119, 120,
87          121, 122, -125, -124, -123, -122, -121, -120, -119, -118, -110, -109,
88          -108, -107, -106, -105, -104, -103, -102, -94, -93, -92, -91, -90, -89,
89          -88, -87, -86, -78, -77, -76, -75, -74, -73, -72, -71, -70, -62, -61,
90          -60, -59, -58, -57, -56, -55, -54, -46, -45, -44, -43, -42, -41, -40,
91          -39, -38, -31, -30, -29, -28, -27, -26, -25, -24, -23, -22, -15, -14,
92          -13, -12, -11, -10, -9, -8, -7, -6
93      };
94  
95      // quantization table in zigzag form for output file
96      private byte[] QNT = 
97      {
98          -1, -37, 0, 67, 0, 13, 9, 10, 11, 10, 8, 13, 11, 10, 11, 14, 14, 13, 15,
99          19, 32, 21, 19, 18, 18, 19, 39, 28, 30, 23, 32, 46, 41, 49, 48, 46, 41,
100         45, 44, 51, 58, 74, 62, 51, 54, 70, 55, 44, 45, 64, 87, 65, 70, 76, 78,
101         82, 83, 82, 50, 62, 90, 97, 90, 80, 96, 74, 81, 82, 79
102     };
103 
104     // table for doing quantization
105     private float[][] QT = 
106     {
107         {13, 9, 8, 13, 19, 32, 41, 49},
108         {10, 10, 11, 15, 21, 46, 48, 44},
109         {11, 10, 13, 19, 32, 46, 55, 45},
110         {11, 14, 18, 23, 41, 70, 64, 50},
111         {14, 18, 30, 45, 54, 87, 82, 62},
112         {19, 28, 44, 51, 65, 83, 90, 74},
113         {39, 51, 62, 70, 82, 97, 96, 81},
114         {58, 74, 76, 78, 90, 80, 82, 79}
115     };
116     private byte[] SOF = {-1, -64, 0, 11, 8, 0, 0, 0, 0, 1, 1, 17, 0};
117     private byte[] SOI = {-1, -40};
118     private byte[] SOS = {-1, -38, 0, 8, 1, 1, 0, 0, 63, 0};
119 
120     // Zig Zag array
121     private int[][] ZZ = 
122     {
123         {0, 1, 5, 6, 14, 15, 27, 28},
124         {2, 4, 7, 13, 16, 26, 29, 42},
125         {3, 8, 12, 17, 25, 30, 41, 43},
126         {9, 11, 18, 24, 31, 40, 44, 53},
127         {10, 19, 23, 32, 39, 45, 52, 54},
128         {20, 22, 33, 38, 46, 51, 55, 60},
129         {21, 34, 37, 47, 50, 56, 59, 61},
130         {35, 36, 48, 49, 57, 58, 62, 63}
131     };
132     private int BitCnt;
133     private int CODE;
134 
135     // Global variables
136     private int I;
137 
138     // Global variables
139     private int J;
140     private int K;
141 
142     // Global variables
143     private int LASTK;
144     private int R;
145     private int SI;
146     private int SSSS;
147 
148     // Global variables
149     private int X;
150 
151     // Global variables
152     private int Y;
153 
154     // Global variables
155     private int ln;
156     private long DATA = 0;
157 
158     //~ Constructors ///////////////////////////////////////////////////////////
159 
160     public GrayJPEG()
161     {
162         int x;
163         int y;
164         int ln = str.length();
165         BE = new byte[ln];
166         str.getBytes(0, ln, BE, 0);
167         ln += 2;
168 
169         byte[] ap = {-1, -32, 0, (byte) ln};
170         APP0 = ap;
171 
172         // Generate AC Huffman tables
173         // Get BITS data
174         BITS[0] = 0;
175 
176         for (x = 1; x < 17; x++)
177         {
178             BITS[x] = Bits[x - 1];
179         }
180 
181         // Get HUFFVAL data
182         for (x = 0; x < 162; x++)
183         {
184             HUFFVAL[x] = Huffval[x];
185 
186             if (HUFFVAL[x] < 0)
187             {
188                 HUFFVAL[x] = 256 + HUFFVAL[x];
189             }
190         }
191 
192         Generate_size_table();
193         Generate_code_table();
194         Order_codes();
195     }
196 
197     //~ Methods ////////////////////////////////////////////////////////////////
198 
199     public void compress(Image i, OutputStream os)
200     {
201         int bkk;
202         int x;
203         int y;
204         int w;
205         int h;
206         int a;
207         int b;
208         int c;
209         int d;
210         int[][] blocks;
211         int[][] blk = new int[8][8];
212 
213         image = i;
214         fos = os;
215         X = image.getWidth(null);
216         Y = image.getHeight(null);
217         ln = X * Y;
218 
219         int[] data = new int[ln];
220         w = (X >> 3) << 3;
221         h = (Y >> 3) << 3;
222         getPixels(data);
223 
224         // Set Image dimensions in Start of Frame header
225         SOF[5] = (byte) ((h & 0x0000ff00) >> 8);
226         SOF[6] = (byte) (h & 0x000000ff);
227         SOF[7] = (byte) ((w & 0x0000ff00) >> 8);
228         SOF[8] = (byte) (w & 0x000000ff);
229 
230         // Set number of blocks
231         w = X / 8;
232         h = Y / 8;
233         ln = w * h;
234         blocks = new int[ln][];
235         bkk = 0;
236 
237         // break image in to 8x8 blocks
238         for (a = 0; a < (h * 8); a += 8)
239         {
240             // Get 8 lines of image
241             for (b = 0; b < (w * 8); b += 8)
242             {
243                 // Get block for FDCT
244                 for (c = 0; c < 8; c++)
245                 {
246                     for (d = 0; d < 8; d++)
247                     {
248                         // mask off 3 upper bytes of image data
249                         blk[c][d] = (data[((a + c) * X) + b + d] & 0x000000ff) -
250                             128;
251                     }
252                 }
253 
254                 //Do FDCT on Block
255                 blocks[bkk++] = FDCT(blk);
256             }
257         }
258 
259         // Write out header data
260         writeHeaders();
261 
262         // Encode image scan
263         Huffman(blocks);
264 
265         // Write out last bits of image scan
266         writeEndData();
267 
268         // Write End of Image marker
269         writeEnd();
270     }
271 
272     private void getPixels(int[] data)
273     {
274         PixelGrabber pg = new PixelGrabber(image.getSource(), 0, 0, X, Y, data,
275                 0, X);
276 
277         try
278         {
279             if (pg.grabPixels() != true)
280             {
281                 try
282                 {
283                     throw new AWTException("Grabber returned false: " +
284                         pg.status());
285                 }
286                  catch (Exception ex)
287                 {
288                     System.err.println("System Failed to get Pixels! - " + ex);
289                     System.exit(0);
290                 }
291 
292                 ;
293             }
294         }
295          catch (InterruptedException ent)
296         {
297         }
298 
299         ;
300     }
301 
302     private void Encode_AC_coefficients(int[] ZZ)
303     {
304         boolean done = false;
305         int size;
306         int code;
307         int dat;
308         K = 0;
309         R = 0;
310 
311         while (!done)
312         {
313             K++;
314             dat = ZZ[K];
315 
316             if (dat == 0)
317             {
318                 if (K == 63)
319                 {
320                     // mark EOB
321                     code = EHUFCO[0x00];
322                     size = EHUFSI[0x00];
323                     writeData(code, size);
324                     done = true;
325 
326                     break;
327                 }
328                 else
329                 {
330                     R++;
331 
332                     continue;
333                 }
334             }
335             else
336             {
337                 while (true)
338                 {
339                     if (R > 15)
340                     {
341                         R -= 16;
342 
343                         // Mark RLZ in scan
344                         code = EHUFCO[0xf0];
345                         size = EHUFSI[0xf0];
346                         writeData(code, size);
347 
348                         continue;
349                     }
350 
351                     Encode_R(ZZ[K]);
352                     R = 0;
353 
354                     if (K == 63)
355                     {
356                         done = true;
357                     }
358 
359                     break;
360                 }
361             }
362         }
363     }
364 
365     private void Encode_R(int ZZ)
366     {
367         int dat;
368         int RS;
369         int size;
370         int code;
371         dat = ZZ;
372 
373         if (ZZ < 0)
374         {
375             dat = -dat;
376             ZZ--;
377         }
378 
379         // Get AC magnitude category
380         SSSS = MagCat(dat);
381         RS = (R << 4) + SSSS;
382 
383         // append bits
384         code = EHUFCO[RS];
385         size = EHUFSI[RS];
386         writeData(code, size);
387 
388         // Mask off upper bits of ZZ
389         ZZ &= ((1 << SSSS) - 1);
390 
391         // append SSS low order bits of ZZ(K)
392         writeData(ZZ, SSSS);
393     }
394 
395     private int[] FDCT(int[][] block)
396     {
397         int j1;
398         int i;
399         int j;
400         int[] blk = new int[64];
401         float[] b = new float[8];
402         float temp;
403         float[] b1 = new float[8];
404         float[][] d = new float[8][8];
405         float f0 = (float) 0.7071068;
406         float f1 = (float) 0.4903926;
407         float f2 = (float) 0.4619398;
408         float f3 = (float) 0.4157348;
409         float f4 = (float) 0.3535534;
410         float f5 = (float) 0.2777851;
411         float f6 = (float) 0.1913417;
412         float f7 = (float) 0.0975452;
413 
414         float df7f1 = (float) -0.3928475;
415         float sf7f1 = (float) 0.5879378;
416         float df3f5 = (float) 0.1379497;
417         float sf3f5 = (float) 0.6935199;
418         float df6f2 = (float) -0.27059805;
419         float sf6f2 = (float) .6532815;
420 
421         for (i = 0; i < 8; i++)
422         {
423             for (j = 0; j < 8; j++)
424             {
425                 b[j] = block[i][j];
426             }
427 
428             // Horizontal transform
429             for (j = 0; j < 4; j++)
430             {
431                 j1 = 7 - j;
432                 b1[j] = b[j] + b[j1];
433                 b1[j1] = b[j] - b[j1];
434             }
435 
436             b[0] = b1[0] + b1[3];
437             b[1] = b1[1] + b1[2];
438             b[2] = b1[1] - b1[2];
439             b[3] = b1[0] - b1[3];
440             b[4] = b1[4];
441             b[5] = (b1[6] - b1[5]) * f0;
442             b[6] = (b1[6] + b1[5]) * f0;
443             b[7] = b1[7];
444             d[i][0] = (b[0] + b[1]) * f4;
445             d[i][4] = (b[0] - b[1]) * f4;
446 
447             temp = (b[3] + b[2]) * f6;
448             d[i][2] = temp - (b[3] * df6f2);
449             d[i][6] = temp - (b[2] * sf6f2);
450 
451             b1[4] = b[4] + b[5];
452             b1[7] = b[7] + b[6];
453             b1[5] = b[4] - b[5];
454             b1[6] = b[7] - b[6];
455 
456             temp = (b1[7] + b1[4]) * f7;
457             d[i][1] = temp - (b1[7] * df7f1);
458             d[i][7] = temp - (b1[4] * sf7f1);
459 
460             temp = (b1[6] + b1[5]) * f3;
461             d[i][5] = temp - (b1[6] * df3f5);
462             d[i][3] = temp - (b1[5] * sf3f5);
463         }
464 
465         // Vertical transform
466         for (i = 0; i < 8; i++)
467         {
468             for (j = 0; j < 4; j++)
469             {
470                 j1 = 7 - j;
471                 b1[j] = d[j][i] + d[j1][i];
472                 b1[j1] = d[j][i] - d[j1][i];
473             }
474 
475             b[0] = b1[0] + b1[3];
476             b[1] = b1[1] + b1[2];
477             b[2] = b1[1] - b1[2];
478             b[3] = b1[0] - b1[3];
479             b[4] = b1[4];
480             b[5] = (b1[6] - b1[5]) * f0;
481             b[6] = (b1[6] + b1[5]) * f0;
482             b[7] = b1[7];
483             d[0][i] = (b[0] + b[1]) * f4;
484             d[4][i] = (b[0] - b[1]) * f4;
485 
486             temp = (b[3] + b[2]) * f6;
487             d[2][i] = temp - (b[3] * df6f2);
488             d[6][i] = temp - (b[2] * sf6f2);
489 
490             b1[4] = b[4] + b[5];
491             b1[7] = b[7] + b[6];
492             b1[5] = b[4] - b[5];
493             b1[6] = b[7] - b[6];
494 
495             temp = (b1[7] + b1[4]) * f7;
496             d[1][i] = temp - (b1[7] * df7f1);
497             d[7][i] = temp - (b1[4] * sf7f1);
498 
499             temp = (b1[6] + b1[5]) * f3;
500             d[5][i] = temp - (b1[6] * df3f5);
501             d[3][i] = temp - (b1[5] * sf3f5);
502         }
503 
504         for (i = 0; i < 8; i++)
505         {
506             for (j = 0; j < 8; j++)
507             {
508                 // Quantize and ZigZag data block
509                 blk[ZZ[i][j]] = (int) (d[i][j] / QT[i][j]);
510             }
511         }
512 
513         return blk;
514     }
515 
516     private void Generate_code_table()
517     {
518         // Generate Code table Flow Chart C.2
519         K = 0;
520         CODE = 0;
521         SI = HUFFSIZE[0];
522 
523         while (true)
524         {
525             HUFFCODE[K++] = CODE++;
526 
527             if (HUFFSIZE[K] == SI)
528             {
529                 continue;
530             }
531 
532             if (HUFFSIZE[K] == 0)
533             {
534                 break;
535             }
536 
537             while (true)
538             {
539                 CODE <<= 1;
540                 SI++;
541 
542                 if (HUFFSIZE[K] == SI)
543                 {
544                     break;
545                 }
546             }
547         }
548     }
549 
550     private void Generate_size_table()
551     {
552         // Generate HUFFSIZE table Flow Chart C.1
553         K = 0;
554         I = 1;
555         J = 1;
556 
557         while (true)
558         {
559             if (J > BITS[I])
560             {
561                 J = 1;
562                 I++;
563 
564                 if (I > 16)
565                 {
566                     break;
567                 }
568             }
569             else
570             {
571                 HUFFSIZE[K++] = I;
572                 J++;
573             }
574         }
575 
576         HUFFSIZE[K] = 0;
577         LASTK = K;
578     }
579 
580     private void Huffman(int[][] blocks)
581     {
582         int tmp;
583         int lp;
584         int DIFF;
585         int dat;
586         int PRED;
587         int bits;
588         int[] blk;
589         byte[] data = new byte[1];
590         int[][] HuffTbl = 
591         {
592             {2, 0},
593             {3, 2},
594             {3, 3},
595             {3, 4},
596             {3, 5},
597             {3, 6},
598             {4, 14},
599             {5, 30},
600             {6, 62},
601             {7, 126},
602             {8, 254},
603             {9, 510}
604         };
605         long buffer;
606 
607         // Encode data blocks
608         // Initialize predictor for new scan
609         PRED = 0;
610         BitCnt = 0;
611 
612         for (lp = 0; lp < ln; lp++)
613         {
614             blk = blocks[lp];
615             buffer = 0;
616             bits = 0;
617 
618             // Encode DC coefficient
619             tmp = DIFF = blk[0] - PRED;
620 
621             if (tmp < 0)
622             {
623                 tmp = -tmp;
624                 DIFF--;
625             }
626 
627             // find magnitude category data for DC edcoding
628             SSSS = MagCat(tmp);
629 
630             // Total number of bits output
631             bits = HuffTbl[SSSS][0] + SSSS;
632 
633             // Code word for this category shifted
634             //to accept magnitude data
635             buffer = HuffTbl[SSSS][1] << SSSS;
636 
637             // append bits to code word
638             buffer += (DIFF & ((1 << SSSS) - 1));
639 
640             // Write out data if greater then or equal to one byte
641             writeData(buffer, bits);
642 
643             // Assign PRED for next DC DIFF
644             PRED = blk[0];
645 
646             // Encode AC coefficients
647             Encode_AC_coefficients(blk);
648 
649             // free up memory for next compression
650             blocks[lp] = null;
651         }
652     }
653 
654     private int MagCat(int dat)
655     {
656         int ln;
657 
658         for (;;)
659         {
660             if (dat == 0)
661             {
662                 ln = 0;
663 
664                 break;
665             }
666 
667             if (dat == 1)
668             {
669                 ln = 1;
670 
671                 break;
672             }
673 
674             if (dat <= 3)
675             {
676                 ln = 2;
677 
678                 break;
679             }
680 
681             if (dat <= 7)
682             {
683                 ln = 3;
684 
685                 break;
686             }
687 
688             if (dat <= 15)
689             {
690                 ln = 4;
691 
692                 break;
693             }
694 
695             if (dat <= 31)
696             {
697                 ln = 5;
698 
699                 break;
700             }
701 
702             if (dat <= 63)
703             {
704                 ln = 6;
705 
706                 break;
707             }
708 
709             if (dat <= 127)
710             {
711                 ln = 7;
712 
713                 break;
714             }
715 
716             if (dat <= 255)
717             {
718                 ln = 8;
719 
720                 break;
721             }
722 
723             if (dat <= 511)
724             {
725                 ln = 9;
726 
727                 break;
728             }
729 
730             if (dat <= 1023)
731             {
732                 ln = 10;
733 
734                 break;
735             }
736 
737             if (dat <= 2047)
738             {
739                 ln = 11;
740 
741                 break;
742             }
743         }
744 
745         return ln;
746     }
747 
748     private void Order_codes()
749     {
750         // Order Codes Flow Chart C.3
751         K = 0;
752 
753         while (true)
754         {
755             I = HUFFVAL[K];
756             EHUFCO[I] = HUFFCODE[K];
757             EHUFSI[I] = HUFFSIZE[K++];
758 
759             if (K >= LASTK)
760             {
761                 break;
762             }
763         }
764     }
765 
766     private void writeData(long dat, int bits)
767     {
768         int tmp;
769         byte[] stuff = {0};
770         byte[] d = new byte[1];
771 
772         if (bits > 0)
773         {
774             DATA <<= bits;
775             DATA += dat;
776             BitCnt += bits;
777         }
778         else
779         {
780             return;
781         }
782 
783         // output bytes untill cnt is less then 8
784         while (BitCnt > 7)
785         {
786             BitCnt -= 8;
787             tmp = (int) (DATA >> BitCnt);
788             d[0] = (byte) tmp;
789 
790             // mask off 8 msb of DATA
791             DATA &= ((1 << BitCnt) - 1);
792 
793             // write out data
794             try
795             {
796                 fos.write(d); // End of Image/File
797 
798                 if (d[0] == -1)
799                 {
800                     // if 0xFF data stuff 0x00 byte
801                     fos.write(stuff);
802                 }
803             }
804              catch (IOException ioe)
805             {
806                 System.err.println("IOException: " + ioe);
807             }
808         }
809     }
810 
811     private void writeEnd()
812     {
813         try
814         {
815             fos.write(EOI); // End of Image/File
816             fos.close();
817         }
818          catch (IOException ioe)
819         {
820             System.err.println("IOException: " + ioe);
821         }
822     }
823 
824     private void writeEndData()
825     {
826         byte[] d = new byte[1];
827 
828         // finish off scan data to byte boundry
829         if (BitCnt > 0)
830         {
831             DATA <<= (8 - BitCnt);
832             DATA += ((1 << (8 - BitCnt)) - 1);
833             d[0] = (byte) DATA;
834 
835             try
836             {
837                 fos.write(d);
838             }
839              catch (IOException ioe)
840             {
841                 System.err.println("IOException: " + ioe);
842             }
843         }
844     }
845 
846     private void writeHeaders()
847     {
848         try
849         {
850             fos.write(SOI); // Start of Image marker
851             fos.write(APP0); // Application header
852             fos.write(BE); // JFIF BE jpg compression
853             fos.write(QNT); // Quantization table
854             fos.write(SOF); // Start of Frame marker
855             fos.write(HuffDC); // DC Huffman Table
856             fos.write(HuffACHeader); // AC Huffman Table Header
857             fos.write(Bits); // AC Huffman Table
858             fos.write(Huffval); // AC Huffman Table
859             fos.write(SOS); // Start of Scan header
860         }
861          catch (IOException ioe)
862         {
863             System.err.println("IOException: " + ioe);
864         }
865     }
866 }
867 ///////////////////////////////////////////////////////////////////////////////
868 //  END OF FILE.
869 ///////////////////////////////////////////////////////////////////////////////