Source code: com/obrador/JpegInfo.java
1 /*
2 * JpegInfo - Given an image, sets default information about it and divides
3 * it into its constituant components, downsizing those that need to be.
4 */
5 package com.obrador;
6
7 import java.awt.AWTException;
8 import java.awt.Image;
9 import java.awt.image.PixelGrabber;
10
11
12 class JpegInfo
13 {
14 //~ Instance fields ////////////////////////////////////////////////////////
15
16 public Image imageobj;
17 public int[] ACtableNumber = {0, 1, 1};
18 public int[] BlockHeight;
19 public int[] BlockWidth;
20 public int[] CompID = {1, 2, 3};
21 public Object[] Components;
22 public int[] DCtableNumber = {0, 1, 1};
23 public int[] HsampFactor = {1, 1, 1};
24 public int[] QtableNumber = {0, 1, 1};
25 public int[] VsampFactor = {1, 1, 1};
26 public int[] compHeight;
27 public int[] compWidth;
28 public boolean[] lastColumnIsDummy = {false, false, false};
29 public boolean[] lastRowIsDummy = {false, false, false};
30 public int Ah = 0;
31 public int Al = 0;
32 public int MaxHsampFactor;
33 public int MaxVsampFactor;
34 public int NumberOfComponents = 3;
35
36 // the following are set as the default
37 public int Precision = 8;
38 public int Se = 63;
39 public int Ss = 0;
40 public int imageHeight;
41 public int imageWidth;
42 String Comment;
43
44 //~ Constructors ///////////////////////////////////////////////////////////
45
46 public JpegInfo(Image image)
47 {
48 Components = new Object[NumberOfComponents];
49 compWidth = new int[NumberOfComponents];
50 compHeight = new int[NumberOfComponents];
51 BlockWidth = new int[NumberOfComponents];
52 BlockHeight = new int[NumberOfComponents];
53 imageobj = image;
54 imageWidth = image.getWidth(null);
55 imageHeight = image.getHeight(null);
56 Comment = "JPEG Encoder Copyright 1998, James R. Weeks and BioElectroMech. ";
57 getYCCArray();
58 }
59
60 //~ Methods ////////////////////////////////////////////////////////////////
61
62 public void setComment(String comment)
63 {
64 Comment.concat(comment);
65 }
66
67 public String getComment()
68 {
69 return Comment;
70 }
71
72 float[][] DownSample(float[][] C, int comp)
73 {
74 int inrow;
75 int incol;
76 int outrow;
77 int outcol;
78 float[][] output;
79 int temp;
80 int bias;
81 inrow = 0;
82 incol = 0;
83 output = new float[compHeight[comp]][compWidth[comp]];
84
85 for (outrow = 0; outrow < compHeight[comp]; outrow++)
86 {
87 bias = 1;
88
89 for (outcol = 0; outcol < compWidth[comp]; outcol++)
90 {
91 output[outrow][outcol] = (C[inrow][incol++] +
92 C[inrow++][incol--] + C[inrow][incol++] +
93 C[inrow--][incol++] + (float) bias) / (float) 4.0;
94 bias ^= 3;
95 }
96
97 inrow += 2;
98 incol = 0;
99 }
100
101 return output;
102 }
103
104 /*
105 * This method creates and fills three arrays, Y, Cb, and Cr using the
106 * input image.
107 */
108 private void getYCCArray()
109 {
110 int[] values = new int[imageWidth * imageHeight];
111 int r;
112 int g;
113 int b;
114 int y;
115 int x;
116
117 // In order to minimize the chance that grabPixels will throw an exception
118 // it may be necessary to grab some pixels every few scanlines and process
119 // those before going for more. The time expense may be prohibitive.
120 // However, for a situation where memory overhead is a concern, this may be
121 // the only choice.
122 PixelGrabber grabber = new PixelGrabber(imageobj.getSource(), 0, 0,
123 imageWidth, imageHeight, values, 0, imageWidth);
124 MaxHsampFactor = 1;
125 MaxVsampFactor = 1;
126
127 for (y = 0; y < NumberOfComponents; y++)
128 {
129 MaxHsampFactor = Math.max(MaxHsampFactor, HsampFactor[y]);
130 MaxVsampFactor = Math.max(MaxVsampFactor, VsampFactor[y]);
131 }
132
133 for (y = 0; y < NumberOfComponents; y++)
134 {
135 compWidth[y] = ((((imageWidth % 8) != 0)
136 ? (((int) Math.ceil((double) imageWidth / 8.0)) * 8) : imageWidth) / MaxHsampFactor) * HsampFactor[y];
137
138 if (compWidth[y] != ((imageWidth / MaxHsampFactor) * HsampFactor[y]))
139 {
140 lastColumnIsDummy[y] = true;
141 }
142
143 // results in a multiple of 8 for compWidth
144 // this will make the rest of the program fail for the unlikely
145 // event that someone tries to compress an 16 x 16 pixel image
146 // which would of course be worse than pointless
147 BlockWidth[y] = (int) Math.ceil((double) compWidth[y] / 8.0);
148 compHeight[y] = ((((imageHeight % 8) != 0)
149 ? (((int) Math.ceil((double) imageHeight / 8.0)) * 8)
150 : imageHeight) / MaxVsampFactor) * VsampFactor[y];
151
152 if (compHeight[y] != ((imageHeight / MaxVsampFactor) * VsampFactor[y]))
153 {
154 lastRowIsDummy[y] = true;
155 }
156
157 BlockHeight[y] = (int) Math.ceil((double) compHeight[y] / 8.0);
158 }
159
160 try
161 {
162 if (grabber.grabPixels() != true)
163 {
164 try
165 {
166 throw new AWTException("Grabber returned false: " +
167 grabber.status());
168 }
169 catch (Exception e)
170 {
171 }
172
173 ;
174 }
175 }
176 catch (InterruptedException e)
177 {
178 }
179
180 ;
181
182 float[][] Y = new float[compHeight[0]][compWidth[0]];
183 float[][] Cr1 = new float[compHeight[0]][compWidth[0]];
184 float[][] Cb1 = new float[compHeight[0]][compWidth[0]];
185 float[][] Cb2 = new float[compHeight[1]][compWidth[1]];
186 float[][] Cr2 = new float[compHeight[2]][compWidth[2]];
187 int index = 0;
188
189 for (y = 0; y < imageHeight; ++y)
190 {
191 for (x = 0; x < imageWidth; ++x)
192 {
193 r = ((values[index] >> 16) & 0xff);
194 g = ((values[index] >> 8) & 0xff);
195 b = (values[index] & 0xff);
196
197 // The following three lines are a more correct color conversion but
198 // the current conversion technique is sufficient and results in a higher
199 // compression rate.
200 // Y[y][x] = 16 + (float)(0.8588*(0.299 * (float)r + 0.587 * (float)g + 0.114 * (float)b ));
201 // Cb1[y][x] = 128 + (float)(0.8784*(-0.16874 * (float)r - 0.33126 * (float)g + 0.5 * (float)b));
202 // Cr1[y][x] = 128 + (float)(0.8784*(0.5 * (float)r - 0.41869 * (float)g - 0.08131 * (float)b));
203 Y[y][x] = (float) (((0.299 * (float) r) + (0.587 * (float) g) +
204 (0.114 * (float) b)));
205 Cb1[y][x] = 128 +
206 (float) (((-0.16874 * (float) r) - (0.33126 * (float) g) +
207 (0.5 * (float) b)));
208 Cr1[y][x] = 128 +
209 (float) (((0.5 * (float) r) - (0.41869 * (float) g) -
210 (0.08131 * (float) b)));
211 index++;
212 }
213 }
214
215 // Need a way to set the H and V sample factors before allowing downsampling.
216 // For now (04/04/98) downsampling must be hard coded.
217 // Until a better downsampler is implemented, this will not be done.
218 // Downsampling is currently supported. The downsampling method here
219 // is a simple box filter.
220 Components[0] = Y;
221
222 // Cb2 = DownSample(Cb1, 1);
223 Components[1] = Cb1;
224
225 // Cr2 = DownSample(Cr1, 2);
226 Components[2] = Cr1;
227 }
228 }
229 ///////////////////////////////////////////////////////////////////////////////
230 // END OF FILE.
231 ///////////////////////////////////////////////////////////////////////////////