corrade-vassal – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | vero | 1 | /* |
2 | * CVS identifier: |
||
3 | * |
||
4 | * $Id: ImgWriterPGM.java,v 1.14 2002/07/19 14:13:38 grosbois Exp $ |
||
5 | * |
||
6 | * Class: ImgWriterRawPGM |
||
7 | * |
||
8 | * Description: Image writer for unsigned 8 bit data in |
||
9 | * PGM file format. |
||
10 | * |
||
11 | * |
||
12 | * |
||
13 | * COPYRIGHT: |
||
14 | * |
||
15 | * This software module was originally developed by Raphaël Grosbois and |
||
16 | * Diego Santa Cruz (Swiss Federal Institute of Technology-EPFL); Joel |
||
17 | * Askelöf (Ericsson Radio Systems AB); and Bertrand Berthelot, David |
||
18 | * Bouchard, Félix Henry, Gerard Mozelle and Patrice Onno (Canon Research |
||
19 | * Centre France S.A) in the course of development of the JPEG2000 |
||
20 | * standard as specified by ISO/IEC 15444 (JPEG 2000 Standard). This |
||
21 | * software module is an implementation of a part of the JPEG 2000 |
||
22 | * Standard. Swiss Federal Institute of Technology-EPFL, Ericsson Radio |
||
23 | * Systems AB and Canon Research Centre France S.A (collectively JJ2000 |
||
24 | * Partners) agree not to assert against ISO/IEC and users of the JPEG |
||
25 | * 2000 Standard (Users) any of their rights under the copyright, not |
||
26 | * including other intellectual property rights, for this software module |
||
27 | * with respect to the usage by ISO/IEC and Users of this software module |
||
28 | * or modifications thereof for use in hardware or software products |
||
29 | * claiming conformance to the JPEG 2000 Standard. Those intending to use |
||
30 | * this software module in hardware or software products are advised that |
||
31 | * their use may infringe existing patents. The original developers of |
||
32 | * this software module, JJ2000 Partners and ISO/IEC assume no liability |
||
33 | * for use of this software module or modifications thereof. No license |
||
34 | * or right to this software module is granted for non JPEG 2000 Standard |
||
35 | * conforming products. JJ2000 Partners have full right to use this |
||
36 | * software module for his/her own purpose, assign or donate this |
||
37 | * software module to any third party and to inhibit third parties from |
||
38 | * using this software module for non JPEG 2000 Standard conforming |
||
39 | * products. This copyright notice must be included in all copies or |
||
40 | * derivative works of this software module. |
||
41 | * |
||
42 | * Copyright (c) 1999/2000 JJ2000 Partners. |
||
43 | * */ |
||
44 | using System; |
||
45 | using CSJ2K.j2k.image; |
||
46 | using CSJ2K.j2k.util; |
||
47 | namespace CSJ2K.j2k.image.output |
||
48 | { |
||
49 | |||
50 | /// <summary> This class writes a component from an image in 8 bit unsigned data to a |
||
51 | /// binary PGM file. The size of the image that is written to the file is the |
||
52 | /// size of the component from which to get the data, not the size of the |
||
53 | /// source image (they differ if there is some sub-sampling). |
||
54 | /// |
||
55 | /// <p>Before writing, all coefficients are inversly level shifted and then |
||
56 | /// "saturated" (they are limited to the nominal dynamic range).<br> <u>Ex:</u> |
||
57 | /// if the nominal range is 0-255, the following algorithm is applied:<br> |
||
58 | /// <tt>if coeff<0, output=0<br> if coeff>255, output=255<br> else |
||
59 | /// output=coeff</tt></p> |
||
60 | /// |
||
61 | /// <p>The write() methods of an object of this class may not be called |
||
62 | /// concurrently from different threads.</p> |
||
63 | /// |
||
64 | /// <p>NOTE: This class is not thread safe, for reasons of internal |
||
65 | /// buffering.</p> |
||
66 | /// |
||
67 | /// </summary> |
||
68 | public class ImgWriterPGM:ImgWriter |
||
69 | { |
||
70 | |||
71 | /// <summary>Value used to inverse level shift </summary> |
||
72 | private int levShift; |
||
73 | |||
74 | /// <summary>Where to write the data </summary> |
||
75 | //UPGRADE_TODO: Class 'java.io.RandomAccessFile' was converted to 'System.IO.FileStream' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javaioRandomAccessFile'" |
||
76 | private System.IO.FileStream out_Renamed; |
||
77 | |||
78 | /// <summary>The index of the component from where to get the data </summary> |
||
79 | private int c; |
||
80 | |||
81 | /// <summary>The number of fractional bits in the source data </summary> |
||
82 | private int fb; |
||
83 | |||
84 | /// <summary>A DataBlk, just used to avoid allocating a new one each time |
||
85 | /// it is needed |
||
86 | /// </summary> |
||
87 | private DataBlkInt db = new DataBlkInt(); |
||
88 | |||
89 | /// <summary>The offset of the raw pixel data in the PGM file </summary> |
||
90 | private int offset; |
||
91 | |||
92 | /// <summary>The line buffer. </summary> |
||
93 | // This makes the class not thrad safe |
||
94 | // (but it is not the only one making it so) |
||
95 | private byte[] buf; |
||
96 | |||
97 | /// <summary> Creates a new writer to the specified File object, to write data from |
||
98 | /// the specified component. |
||
99 | /// |
||
100 | /// <p>The size of the image that is written to the file is the size of the |
||
101 | /// component from which to get the data, specified by b, not the size of |
||
102 | /// the source image (they differ if there is some sub-sampling).</p> |
||
103 | /// |
||
104 | /// </summary> |
||
105 | /// <param name="out">The file where to write the data |
||
106 | /// |
||
107 | /// </param> |
||
108 | /// <param name="imgSrc">The source from where to get the image data to write. |
||
109 | /// |
||
110 | /// </param> |
||
111 | /// <param name="c">The index of the component from where to get the data. |
||
112 | /// |
||
113 | /// </param> |
||
114 | public ImgWriterPGM(System.IO.FileInfo out_Renamed, BlkImgDataSrc imgSrc, int c) |
||
115 | { |
||
116 | // Check that imgSrc is of the correct type |
||
117 | // Check that the component index is valid |
||
118 | if (c < 0 || c >= imgSrc.NumComps) |
||
119 | { |
||
120 | throw new System.ArgumentException("Invalid number of components"); |
||
121 | } |
||
122 | |||
123 | // Check that imgSrc is of the correct type |
||
124 | if (imgSrc.getNomRangeBits(c) > 8) |
||
125 | { |
||
126 | FacilityManager.getMsgLogger().println("Warning: Component " + c + " has nominal bitdepth " + imgSrc.getNomRangeBits(c) + ". Pixel values will be " + "down-shifted to fit bitdepth of 8 for PGM file", 8, 8); |
||
127 | } |
||
128 | |||
129 | // Initialize |
||
130 | bool tmpBool; |
||
131 | if (System.IO.File.Exists(out_Renamed.FullName)) |
||
132 | tmpBool = true; |
||
133 | else |
||
134 | tmpBool = System.IO.Directory.Exists(out_Renamed.FullName); |
||
135 | bool tmpBool2; |
||
136 | if (System.IO.File.Exists(out_Renamed.FullName)) |
||
137 | { |
||
138 | System.IO.File.Delete(out_Renamed.FullName); |
||
139 | tmpBool2 = true; |
||
140 | } |
||
141 | else if (System.IO.Directory.Exists(out_Renamed.FullName)) |
||
142 | { |
||
143 | System.IO.Directory.Delete(out_Renamed.FullName); |
||
144 | tmpBool2 = true; |
||
145 | } |
||
146 | else |
||
147 | tmpBool2 = false; |
||
148 | if (tmpBool && !tmpBool2) |
||
149 | { |
||
150 | throw new System.IO.IOException("Could not reset file"); |
||
151 | } |
||
152 | this.out_Renamed = SupportClass.RandomAccessFileSupport.CreateRandomAccessFile(out_Renamed, "rw"); |
||
153 | src = imgSrc; |
||
154 | this.c = c; |
||
155 | w = imgSrc.ImgWidth; |
||
156 | h = imgSrc.ImgHeight; |
||
157 | fb = imgSrc.getFixedPoint(c); |
||
158 | levShift = 1 << (imgSrc.getNomRangeBits(c) - 1); |
||
159 | |||
160 | writeHeaderInfo(); |
||
161 | } |
||
162 | |||
163 | /// <summary> Creates a new writer to the specified file, to write data from the |
||
164 | /// specified component. |
||
165 | /// |
||
166 | /// <P>The size of the image that is written to the file is the size of the |
||
167 | /// component from which to get the data, specified by b, not the size of |
||
168 | /// the source image (they differ if there is some sub-sampling). |
||
169 | /// |
||
170 | /// </summary> |
||
171 | /// <param name="fname">The name of the file where to write the data |
||
172 | /// |
||
173 | /// </param> |
||
174 | /// <param name="imgSrc">The source from where to get the image data to write. |
||
175 | /// |
||
176 | /// </param> |
||
177 | /// <param name="c">The index of the component from where to get the data. |
||
178 | /// |
||
179 | /// </param> |
||
180 | public ImgWriterPGM(System.String fname, BlkImgDataSrc imgSrc, int c):this(new System.IO.FileInfo(fname), imgSrc, c) |
||
181 | { |
||
182 | } |
||
183 | |||
184 | /// <summary> Closes the underlying file or netwrok connection to where the data is |
||
185 | /// written. Any call to other methods of the class become illegal after a |
||
186 | /// call to this one. |
||
187 | /// |
||
188 | /// </summary> |
||
189 | /// <exception cref="IOException">If an I/O error occurs. |
||
190 | /// |
||
191 | /// </exception> |
||
192 | public override void close() |
||
193 | { |
||
194 | int i; |
||
195 | // Finish writing the file, writing 0s at the end if the data at end |
||
196 | // has not been written. |
||
197 | if (out_Renamed.Length != w * h + offset) |
||
198 | { |
||
199 | // Goto end of file |
||
200 | out_Renamed.Seek(out_Renamed.Length, System.IO.SeekOrigin.Begin); |
||
201 | // Fill with 0s |
||
202 | for (i = offset + w * h - (int) out_Renamed.Length; i > 0; i--) |
||
203 | { |
||
204 | out_Renamed.WriteByte((System.Byte) 0); |
||
205 | } |
||
206 | } |
||
207 | out_Renamed.Close(); |
||
208 | src = null; |
||
209 | out_Renamed = null; |
||
210 | db = null; |
||
211 | } |
||
212 | |||
213 | /// <summary> Writes all buffered data to the file or resource. |
||
214 | /// |
||
215 | /// </summary> |
||
216 | /// <exception cref="IOException">If an I/O error occurs. |
||
217 | /// |
||
218 | /// </exception> |
||
219 | public override void flush() |
||
220 | { |
||
221 | // No flush needed here since we are using a RandomAccessFile Get rid |
||
222 | // of line buffer (is this a good choice?) |
||
223 | buf = null; |
||
224 | } |
||
225 | |||
226 | /// <summary> Writes the data of the specified area to the file, coordinates are |
||
227 | /// relative to the current tile of the source. Before writing, the |
||
228 | /// coefficients are limited to the nominal range. |
||
229 | /// |
||
230 | /// <p>This method may not be called concurrently from different |
||
231 | /// threads.</p> |
||
232 | /// |
||
233 | /// <p>If the data returned from the BlkImgDataSrc source is progressive, |
||
234 | /// then it is requested over and over until it is not progressive |
||
235 | /// anymore.</p> |
||
236 | /// |
||
237 | /// </summary> |
||
238 | /// <param name="ulx">The horizontal coordinate of the upper-left corner of the |
||
239 | /// area to write, relative to the current tile. |
||
240 | /// |
||
241 | /// </param> |
||
242 | /// <param name="uly">The vertical coordinate of the upper-left corner of the area |
||
243 | /// to write, relative to the current tile. |
||
244 | /// |
||
245 | /// </param> |
||
246 | /// <param name="width">The width of the area to write. |
||
247 | /// |
||
248 | /// </param> |
||
249 | /// <param name="height">The height of the area to write. |
||
250 | /// |
||
251 | /// </param> |
||
252 | /// <exception cref="IOException">If an I/O error occurs. |
||
253 | /// |
||
254 | /// </exception> |
||
255 | public override void write(int ulx, int uly, int w, int h) |
||
256 | { |
||
257 | int k, i, j; |
||
258 | int fracbits = fb; // In local variable for faster access |
||
259 | int tOffx, tOffy; // Active tile offset in the X and Y direction |
||
260 | |||
261 | // Initialize db |
||
262 | db.ulx = ulx; |
||
263 | db.uly = uly; |
||
264 | db.w = w; |
||
265 | db.h = h; |
||
266 | // Get the current active tile offset |
||
267 | //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" |
||
268 | tOffx = src.getCompULX(c) - (int) System.Math.Ceiling(src.ImgULX / (double) src.getCompSubsX(c)); |
||
269 | //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" |
||
270 | tOffy = src.getCompULY(c) - (int) System.Math.Ceiling(src.ImgULY / (double) src.getCompSubsY(c)); |
||
271 | // Check the array size |
||
272 | if (db.data_array != null && db.data_array.Length < w * h) |
||
273 | { |
||
274 | // A new one will be allocated by getInternCompData() |
||
275 | db.data_array = null; |
||
276 | } |
||
277 | // Request the data and make sure it is not |
||
278 | // progressive |
||
279 | do |
||
280 | { |
||
281 | db = (DataBlkInt) src.getInternCompData(db, c); |
||
282 | } |
||
283 | while (db.progressive); |
||
284 | |||
285 | // variables used during coeff saturation |
||
286 | int tmp, maxVal = (1 << src.getNomRangeBits(c)) - 1; |
||
287 | |||
288 | // If nominal bitdepth greater than 8, calculate down shift |
||
289 | int downShift = src.getNomRangeBits(c) - 8; |
||
290 | if (downShift < 0) |
||
291 | { |
||
292 | downShift = 0; |
||
293 | } |
||
294 | |||
295 | // Check line buffer |
||
296 | if (buf == null || buf.Length < w) |
||
297 | { |
||
298 | buf = new byte[w]; // Expand buffer |
||
299 | } |
||
300 | |||
301 | // Write line by line |
||
302 | for (i = 0; i < h; i++) |
||
303 | { |
||
304 | // Skip to beggining of line in file |
||
305 | out_Renamed.Seek(this.offset + this.w * (uly + tOffy + i) + ulx + tOffx, System.IO.SeekOrigin.Begin); |
||
306 | // Write all bytes in the line |
||
307 | if (fracbits == 0) |
||
308 | { |
||
309 | for (k = db.offset + i * db.scanw + w - 1, j = w - 1; j >= 0; j--, k--) |
||
310 | { |
||
311 | tmp = db.data_array[k] + levShift; |
||
312 | buf[j] = (byte) (((tmp < 0)?0:((tmp > maxVal)?maxVal:tmp)) >> downShift); |
||
313 | } |
||
314 | } |
||
315 | else |
||
316 | { |
||
317 | for (k = db.offset + i * db.scanw + w - 1, j = w - 1; j >= 0; j--, k--) |
||
318 | { |
||
319 | tmp = (db.data_array[k] >> fracbits) + levShift; |
||
320 | buf[j] = (byte) (((tmp < 0)?0:((tmp > maxVal)?maxVal:tmp)) >> downShift); |
||
321 | } |
||
322 | } |
||
323 | out_Renamed.Write(buf, 0, w); |
||
324 | } |
||
325 | } |
||
326 | |||
327 | /// <summary> Writes the source's current tile to the output. The requests of data |
||
328 | /// issued to the source BlkImgDataSrc object are done by strips, in order |
||
329 | /// to reduce memory usage. |
||
330 | /// |
||
331 | /// <p>If the data returned from the BlkImgDataSrc source is progressive, |
||
332 | /// then it is requested over and over until it is not progressive |
||
333 | /// anymore.</p> |
||
334 | /// |
||
335 | /// </summary> |
||
336 | /// <exception cref="IOException">If an I/O error occurs. |
||
337 | /// |
||
338 | /// </exception> |
||
339 | /// <seealso cref="DataBlk"> |
||
340 | /// |
||
341 | /// </seealso> |
||
342 | public override void write() |
||
343 | { |
||
344 | int i; |
||
345 | int tIdx = src.TileIdx; |
||
346 | int tw = src.getTileCompWidth(tIdx, c); // Tile width |
||
347 | int th = src.getTileCompHeight(tIdx, c); // Tile height |
||
348 | // Write in strips |
||
349 | for (i = 0; i < th; i += DEF_STRIP_HEIGHT) |
||
350 | { |
||
351 | write(0, i, tw, (th - i < DEF_STRIP_HEIGHT)?th - i:DEF_STRIP_HEIGHT); |
||
352 | } |
||
353 | } |
||
354 | |||
355 | /// <summary> Writes the header info of the PGM file : |
||
356 | /// |
||
357 | /// P5 |
||
358 | /// width height |
||
359 | /// 255 |
||
360 | /// |
||
361 | /// </summary> |
||
362 | /// <exception cref="IOException">If there is an IOException |
||
363 | /// |
||
364 | /// </exception> |
||
365 | private void writeHeaderInfo() |
||
366 | { |
||
367 | byte[] byteVals; |
||
368 | int i; |
||
369 | System.String val; |
||
370 | |||
371 | // write 'P5' to file |
||
372 | out_Renamed.WriteByte((System.Byte) 'P'); // 'P' |
||
373 | out_Renamed.WriteByte((System.Byte) '5'); // '5' |
||
374 | out_Renamed.WriteByte((System.Byte) '\n'); // newline |
||
375 | offset = 3; |
||
376 | // Write width in ASCII |
||
377 | val = System.Convert.ToString(w); |
||
378 | byteVals = System.Text.ASCIIEncoding.ASCII.GetBytes(val); |
||
379 | for (i = 0; i < byteVals.Length; i++) |
||
380 | { |
||
381 | out_Renamed.WriteByte((byte) byteVals[i]); |
||
382 | offset++; |
||
383 | } |
||
384 | out_Renamed.WriteByte((System.Byte) ' '); // blank |
||
385 | offset++; |
||
386 | // Write height in ASCII |
||
387 | val = System.Convert.ToString(h); |
||
388 | byteVals = System.Text.ASCIIEncoding.ASCII.GetBytes(val); |
||
389 | for (i = 0; i < byteVals.Length; i++) |
||
390 | { |
||
391 | out_Renamed.WriteByte((byte) byteVals[i]); |
||
392 | offset++; |
||
393 | } |
||
394 | // Write maxval |
||
395 | out_Renamed.WriteByte((System.Byte) '\n'); // newline |
||
396 | out_Renamed.WriteByte((System.Byte) '2'); // '2' |
||
397 | out_Renamed.WriteByte((System.Byte) '5'); // '5' |
||
398 | out_Renamed.WriteByte((System.Byte) '5'); // '5' |
||
399 | out_Renamed.WriteByte((System.Byte) '\n'); // newline |
||
400 | offset += 5; |
||
401 | } |
||
402 | |||
403 | /// <summary> Returns a string of information about the object, more than 1 line |
||
404 | /// long. The information string includes information from the underlying |
||
405 | /// RandomAccessFile (its toString() method is called in turn). |
||
406 | /// |
||
407 | /// </summary> |
||
408 | /// <returns> A string of information about the object. |
||
409 | /// |
||
410 | /// </returns> |
||
411 | public override System.String ToString() |
||
412 | { |
||
413 | //UPGRADE_TODO: The equivalent in .NET for method 'java.lang.Object.toString' may return a different value. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1043'" |
||
414 | return "ImgWriterPGM: WxH = " + w + "x" + h + ", Component=" + c + "\nUnderlying RandomAccessFile:\n" + out_Renamed.ToString(); |
||
415 | } |
||
416 | } |
||
417 | } |