corrade-vassal – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | vero | 1 | /* |
2 | * |
||
3 | * Class: ImgWriterGDI |
||
4 | * |
||
5 | * Description: Image writer for System.Drawing.GDI streams |
||
6 | * |
||
7 | * */ |
||
8 | |||
9 | using System; |
||
10 | using System.Drawing; |
||
11 | using System.Drawing.Imaging; |
||
12 | using System.IO; |
||
13 | using CSJ2K.j2k.image; |
||
14 | using CSJ2K.j2k.io; |
||
15 | using CSJ2K.j2k; |
||
16 | |||
17 | namespace CSJ2K.j2k.image.input |
||
18 | { |
||
19 | public class ImgReaderGDI : ImgReader |
||
20 | { |
||
21 | /// <summary>The number of bits that determine the nominal dynamic range </summary> |
||
22 | private int rb; |
||
23 | |||
24 | /// <summary>Buffer for the components of each pixel(in the current block) </summary> |
||
25 | private int[][] barr; |
||
26 | |||
27 | /// <summary>Data block used only to store coordinates of the buffered blocks </summary> |
||
28 | private DataBlkInt dbi = new DataBlkInt(); |
||
29 | |||
30 | /// <summary>Temporary DataBlkInt object (needed when encoder uses floating-point |
||
31 | /// filters). This avoid allocating new DataBlk at each time |
||
32 | /// </summary> |
||
33 | private DataBlkInt intBlk; |
||
34 | |||
35 | private Image image; |
||
36 | |||
37 | public ImgReaderGDI(Image image) |
||
38 | { |
||
39 | if (image.PixelFormat != PixelFormat.Format24bppRgb) |
||
40 | throw new ArgumentException("Only 24bpp RGB images are currently supported"); |
||
41 | |||
42 | this.image = image; |
||
43 | |||
44 | w = image.Width; |
||
45 | h = image.Height; |
||
46 | |||
47 | nc = 3; |
||
48 | rb = 8; |
||
49 | } |
||
50 | |||
51 | /// <summary> Closes the underlying file from where the image data is being read. No |
||
52 | /// operations are possible after a call to this method. |
||
53 | /// |
||
54 | /// </summary> |
||
55 | /// <exception cref="IOException">If an I/O error occurs. |
||
56 | /// |
||
57 | /// </exception> |
||
58 | public override void close() |
||
59 | { |
||
60 | image.Dispose(); |
||
61 | image = null; |
||
62 | |||
63 | barr = null; |
||
64 | } |
||
65 | |||
66 | /// <summary> Returns the number of bits corresponding to the nominal range of the |
||
67 | /// data in the specified component. This is the value rb (range bits) that |
||
68 | /// was specified in the constructor, which normally is 8 for non bilevel |
||
69 | /// data, and 1 for bilevel data. |
||
70 | /// |
||
71 | /// <P>If this number is <i>b</b> then the nominal range is between |
||
72 | /// -2^(b-1) and 2^(b-1)-1, since unsigned data is level shifted to have a |
||
73 | /// nominal avergae of 0. |
||
74 | /// |
||
75 | /// </summary> |
||
76 | /// <param name="c">The index of the component. |
||
77 | /// |
||
78 | /// </param> |
||
79 | /// <returns> The number of bits corresponding to the nominal range of the |
||
80 | /// data. For floating-point data this value is not applicable and the |
||
81 | /// return value is undefined. |
||
82 | /// |
||
83 | /// </returns> |
||
84 | public override int getNomRangeBits(int c) |
||
85 | { |
||
86 | // Check component index |
||
87 | if (c < 0 || c > 2) |
||
88 | throw new System.ArgumentException(); |
||
89 | |||
90 | return rb; |
||
91 | } |
||
92 | |||
93 | /// <summary> Returns the position of the fixed point in the specified component |
||
94 | /// (i.e. the number of fractional bits), which is always 0 for this |
||
95 | /// ImgReader. |
||
96 | /// |
||
97 | /// </summary> |
||
98 | /// <param name="c">The index of the component. |
||
99 | /// |
||
100 | /// </param> |
||
101 | /// <returns> The position of the fixed-point (i.e. the number of fractional |
||
102 | /// bits). Always 0 for this ImgReader. |
||
103 | /// |
||
104 | /// </returns> |
||
105 | public override int getFixedPoint(int c) |
||
106 | { |
||
107 | // Check component index |
||
108 | if (c < 0 || c > 2) |
||
109 | throw new System.ArgumentException(); |
||
110 | return 0; |
||
111 | } |
||
112 | |||
113 | /// <summary> Returns, in the blk argument, the block of image data containing the |
||
114 | /// specifed rectangular area, in the specified component. The data is |
||
115 | /// returned, as a reference to the internal data, if any, instead of as a |
||
116 | /// copy, therefore the returned data should not be modified. |
||
117 | /// |
||
118 | /// <P> After being read the coefficients are level shifted by subtracting |
||
119 | /// 2^(nominal bit range - 1) |
||
120 | /// |
||
121 | /// <P>The rectangular area to return is specified by the 'ulx', 'uly', 'w' |
||
122 | /// and 'h' members of the 'blk' argument, relative to the current |
||
123 | /// tile. These members are not modified by this method. The 'offset' and |
||
124 | /// 'scanw' of the returned data can be arbitrary. See the 'DataBlk' class. |
||
125 | /// |
||
126 | /// <P>If the data array in <tt>blk</tt> is <tt>null</tt>, then a new one |
||
127 | /// is created if necessary. The implementation of this interface may |
||
128 | /// choose to return the same array or a new one, depending on what is more |
||
129 | /// efficient. Therefore, the data array in <tt>blk</tt> prior to the |
||
130 | /// method call should not be considered to contain the returned data, a |
||
131 | /// new array may have been created. Instead, get the array from |
||
132 | /// <tt>blk</tt> after the method has returned. |
||
133 | /// |
||
134 | /// <P>The returned data always has its 'progressive' attribute unset |
||
135 | /// (i.e. false). |
||
136 | /// |
||
137 | /// <P>When an I/O exception is encountered the JJ2KExceptionHandler is |
||
138 | /// used. The exception is passed to its handleException method. The action |
||
139 | /// that is taken depends on the action that has been registered in |
||
140 | /// JJ2KExceptionHandler. See JJ2KExceptionHandler for details. |
||
141 | /// |
||
142 | /// <P>This method implements buffering for the 3 components: When the |
||
143 | /// first one is asked, all the 3 components are read and stored until they |
||
144 | /// are needed. |
||
145 | /// |
||
146 | /// </summary> |
||
147 | /// <param name="blk">Its coordinates and dimensions specify the area to |
||
148 | /// return. Some fields in this object are modified to return the data. |
||
149 | /// |
||
150 | /// </param> |
||
151 | /// <param name="c">The index of the component from which to get the data. Only 0, |
||
152 | /// 1 and 3 are valid. |
||
153 | /// |
||
154 | /// </param> |
||
155 | /// <returns> The requested DataBlk |
||
156 | /// |
||
157 | /// </returns> |
||
158 | /// <seealso cref="getCompData"> |
||
159 | /// |
||
160 | /// </seealso> |
||
161 | /// <seealso cref="JJ2KExceptionHandler"> |
||
162 | /// |
||
163 | /// </seealso> |
||
164 | public override DataBlk getInternCompData(DataBlk blk, int c) |
||
165 | { |
||
166 | // Check component index |
||
167 | if (c < 0 || c > 2) |
||
168 | throw new System.ArgumentException(); |
||
169 | |||
170 | // Check type of block provided as an argument |
||
171 | if (blk.DataType != DataBlk.TYPE_INT) |
||
172 | { |
||
173 | if (intBlk == null) |
||
174 | intBlk = new DataBlkInt(blk.ulx, blk.uly, blk.w, blk.h); |
||
175 | else |
||
176 | { |
||
177 | intBlk.ulx = blk.ulx; |
||
178 | intBlk.uly = blk.uly; |
||
179 | intBlk.w = blk.w; |
||
180 | intBlk.h = blk.h; |
||
181 | } |
||
182 | blk = intBlk; |
||
183 | } |
||
184 | |||
185 | // If asking a component for the first time for this block, read all of the components |
||
186 | if ((barr == null) || (dbi.ulx > blk.ulx) || (dbi.uly > blk.uly) || (dbi.ulx + dbi.w < blk.ulx + blk.w) || (dbi.uly + dbi.h < blk.uly + blk.h)) |
||
187 | { |
||
188 | int i; |
||
189 | int[] red, green, blue, alpha; |
||
190 | int componentCount = (image.PixelFormat == PixelFormat.Format32bppArgb) ? 4 : 3; |
||
191 | |||
192 | barr = new int[componentCount][]; |
||
193 | |||
194 | // Reset data arrays if needed |
||
195 | if (barr[c] == null || barr[c].Length < blk.w * blk.h) |
||
196 | { |
||
197 | barr[c] = new int[blk.w * blk.h]; |
||
198 | } |
||
199 | blk.Data = barr[c]; |
||
200 | |||
201 | i = (c + 1) % 3; |
||
202 | if (barr[i] == null || barr[i].Length < blk.w * blk.h) |
||
203 | { |
||
204 | barr[i] = new int[blk.w * blk.h]; |
||
205 | } |
||
206 | i = (c + 2) % 3; |
||
207 | if (barr[i] == null || barr[i].Length < blk.w * blk.h) |
||
208 | { |
||
209 | barr[i] = new int[blk.w * blk.h]; |
||
210 | } |
||
211 | |||
212 | if (componentCount == 4) |
||
213 | { |
||
214 | if (barr[3] == null || barr[3].Length < blk.w * blk.h) |
||
215 | barr[3] = new int[blk.w * blk.h]; |
||
216 | } |
||
217 | |||
218 | // set attributes of the DataBlk used for buffering |
||
219 | dbi.ulx = blk.ulx; |
||
220 | dbi.uly = blk.uly; |
||
221 | dbi.w = blk.w; |
||
222 | dbi.h = blk.h; |
||
223 | |||
224 | red = barr[0]; |
||
225 | green = barr[1]; |
||
226 | blue = barr[2]; |
||
227 | alpha = (componentCount == 4) ? barr[3] : null; |
||
228 | |||
229 | Bitmap bitmap = (Bitmap)image; |
||
230 | BitmapData data = bitmap.LockBits(new Rectangle(blk.ulx, blk.uly, blk.w, blk.h), ImageLockMode.ReadOnly, |
||
231 | (componentCount == 3) ? PixelFormat.Format24bppRgb : PixelFormat.Format32bppArgb); |
||
232 | unsafe |
||
233 | { |
||
234 | byte* ptr = (byte*)data.Scan0.ToPointer(); |
||
235 | |||
236 | int k = 0; |
||
237 | for (int j = 0; j < blk.w * blk.h; j++) |
||
238 | { |
||
239 | blue[k] = ((byte)*(ptr + 0) & 0xFF) - 128; |
||
240 | green[k] = ((byte)*(ptr + 1) & 0xFF) - 128; |
||
241 | red[k] = ((byte)*(ptr + 2) & 0xFF) - 128; |
||
242 | if (componentCount == 4) |
||
243 | alpha[k] = ((byte)*(ptr + 3) & 0xFF) - 128; |
||
244 | |||
245 | ++k; |
||
246 | ptr += 3; |
||
247 | } |
||
248 | } |
||
249 | bitmap.UnlockBits(data); |
||
250 | |||
251 | barr[0] = red; |
||
252 | barr[1] = green; |
||
253 | barr[2] = blue; |
||
254 | if (componentCount == 4) |
||
255 | barr[3] = alpha; |
||
256 | |||
257 | // Set buffer attributes |
||
258 | blk.Data = barr[c]; |
||
259 | blk.offset = 0; |
||
260 | blk.scanw = blk.w; |
||
261 | } |
||
262 | else |
||
263 | { |
||
264 | //Asking for the 2nd or 3rd (or 4th) block component |
||
265 | blk.Data = barr[c]; |
||
266 | blk.offset = (blk.ulx - dbi.ulx) * dbi.w + blk.ulx - dbi.ulx; |
||
267 | blk.scanw = dbi.scanw; |
||
268 | } |
||
269 | |||
270 | // Turn off the progressive attribute |
||
271 | blk.progressive = false; |
||
272 | return blk; |
||
273 | } |
||
274 | |||
275 | /// <summary> Returns, in the blk argument, a block of image data containing the |
||
276 | /// specifed rectangular area, in the specified component. The data is |
||
277 | /// returned, as a copy of the internal data, therefore the returned data |
||
278 | /// can be modified "in place". |
||
279 | /// |
||
280 | /// <P> After being read the coefficients are level shifted by subtracting |
||
281 | /// 2^(nominal bit range - 1) |
||
282 | /// |
||
283 | /// <P>The rectangular area to return is specified by the 'ulx', 'uly', 'w' |
||
284 | /// and 'h' members of the 'blk' argument, relative to the current |
||
285 | /// tile. These members are not modified by this method. The 'offset' of |
||
286 | /// the returned data is 0, and the 'scanw' is the same as the block's |
||
287 | /// width. See the 'DataBlk' class. |
||
288 | /// |
||
289 | /// <P>If the data array in 'blk' is 'null', then a new one is created. If |
||
290 | /// the data array is not 'null' then it is reused, and it must be large |
||
291 | /// enough to contain the block's data. Otherwise an 'ArrayStoreException' |
||
292 | /// or an 'IndexOutOfBoundsException' is thrown by the Java system. |
||
293 | /// |
||
294 | /// <P>The returned data has its 'progressive' attribute unset |
||
295 | /// (i.e. false). |
||
296 | /// |
||
297 | /// <P>When an I/O exception is encountered the JJ2KExceptionHandler is |
||
298 | /// used. The exception is passed to its handleException method. The action |
||
299 | /// that is taken depends on the action that has been registered in |
||
300 | /// JJ2KExceptionHandler. See JJ2KExceptionHandler for details. |
||
301 | /// |
||
302 | /// </summary> |
||
303 | /// <param name="blk">Its coordinates and dimensions specify the area to |
||
304 | /// return. If it contains a non-null data array, then it must have the |
||
305 | /// correct dimensions. If it contains a null data array a new one is |
||
306 | /// created. The fields in this object are modified to return the data. |
||
307 | /// |
||
308 | /// </param> |
||
309 | /// <param name="c">The index of the component from which to get the data. Only |
||
310 | /// 0,1 and 2 are valid. |
||
311 | /// |
||
312 | /// </param> |
||
313 | /// <returns> The requested DataBlk |
||
314 | /// |
||
315 | /// </returns> |
||
316 | /// <seealso cref="getInternCompData"> |
||
317 | /// |
||
318 | /// </seealso> |
||
319 | /// <seealso cref="JJ2KExceptionHandler"> |
||
320 | /// |
||
321 | /// </seealso> |
||
322 | public override DataBlk getCompData(DataBlk blk, int c) |
||
323 | { |
||
324 | // NOTE: can not directly call getInterCompData since that returns |
||
325 | // internally buffered data. |
||
326 | int ulx, uly, w, h; |
||
327 | |||
328 | // Check type of block provided as an argument |
||
329 | if (blk.DataType != DataBlk.TYPE_INT) |
||
330 | { |
||
331 | DataBlkInt tmp = new DataBlkInt(blk.ulx, blk.uly, blk.w, blk.h); |
||
332 | blk = tmp; |
||
333 | } |
||
334 | |||
335 | int[] bakarr = (int[])blk.Data; |
||
336 | // Save requested block size |
||
337 | ulx = blk.ulx; |
||
338 | uly = blk.uly; |
||
339 | w = blk.w; |
||
340 | h = blk.h; |
||
341 | // Force internal data buffer to be different from external |
||
342 | blk.Data = null; |
||
343 | getInternCompData(blk, c); |
||
344 | // Copy the data |
||
345 | if (bakarr == null) |
||
346 | { |
||
347 | bakarr = new int[w * h]; |
||
348 | } |
||
349 | if (blk.offset == 0 && blk.scanw == w) |
||
350 | { |
||
351 | // Requested and returned block buffer are the same size |
||
352 | // CONVERSION PROBLEM? |
||
353 | Array.Copy((System.Array)blk.Data, 0, (System.Array)bakarr, 0, w * h); |
||
354 | } |
||
355 | else |
||
356 | { |
||
357 | // Requested and returned block are different |
||
358 | for (int i = h - 1; i >= 0; i--) |
||
359 | { |
||
360 | // copy line by line |
||
361 | // CONVERSION PROBLEM? |
||
362 | Array.Copy((System.Array)blk.Data, blk.offset + i * blk.scanw, (System.Array)bakarr, i * w, w); |
||
363 | } |
||
364 | } |
||
365 | blk.Data = bakarr; |
||
366 | blk.offset = 0; |
||
367 | blk.scanw = blk.w; |
||
368 | return blk; |
||
369 | } |
||
370 | |||
371 | /// <summary> Returns true if the data read was originally signed in the specified |
||
372 | /// component, false if not. This method always returns false since PPM |
||
373 | /// data is always unsigned. |
||
374 | /// |
||
375 | /// </summary> |
||
376 | /// <param name="c">The index of the component, from 0 to N-1. |
||
377 | /// |
||
378 | /// </param> |
||
379 | /// <returns> always false, since PPM data is always unsigned. |
||
380 | /// |
||
381 | /// </returns> |
||
382 | public override bool isOrigSigned(int c) |
||
383 | { |
||
384 | // Check component index |
||
385 | if (c < 0 || c > 2) |
||
386 | throw new System.ArgumentException(); |
||
387 | return false; |
||
388 | } |
||
389 | |||
390 | /// <summary> Returns a string of information about the object, more than 1 line |
||
391 | /// long. The information string includes information from the underlying |
||
392 | /// RandomAccessFile (its toString() method is called in turn). |
||
393 | /// |
||
394 | /// </summary> |
||
395 | /// <returns> A string of information about the object. |
||
396 | /// |
||
397 | /// </returns> |
||
398 | public override System.String ToString() |
||
399 | { |
||
400 | return "ImgReaderGDI: WxH = " + w + "x" + h + ", Component = 0,1,2"; |
||
401 | } |
||
402 | } |
||
403 | } |