corrade-vassal – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 vero 1 /*
2 * CVS identifier:
3 *
4 * $Id: ImgWriterPGX.java,v 1.14 2002/07/19 14:10:46 grosbois Exp $
5 *
6 * Class: ImgWriterPGX
7 *
8 * Description: Image Writer for PGX files (custom file format
9 * for VM3A)
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 extends the ImgWriter abstract class for writing PGX files. PGX
51 /// is a custom monochrome file format invented specifically to simplify the
52 /// use of VM3A with images of different bit-depths in the range 1 to 31 bits
53 /// per pixel.
54 ///
55 /// <p>The file consists of a one line text header followed by the data.</p>
56 ///
57 /// <p>
58 /// <u>Header:</u> "PG"+ <i>ws</i> +&lt;<i>endianess</i>&gt;+ <i>ws</i>
59 /// +[<i>sign</i>]+<i>ws</i> + &lt;<i>bit-depth</i>&gt;+"
60 /// "+&lt;<i>width</i>&gt;+" "+&lt;<i>height</i>&gt;+'\n'</p>
61 ///
62 /// <p>where:<br>
63 /// <ul>
64 /// <li><i>ws</i> (white-spaces) is any combination of characters ' ' and
65 /// '\t'.</li>
66 /// <li><i>endianess</i> equals "LM" or "ML"(resp. little-endian or
67 /// big-endian)</li>
68 /// <li><i>sign</i> equals "+" or "-" (resp. unsigned or signed). If omited,
69 /// values are supposed to be unsigned.</li>
70 /// <li><i>bit-depth</i> that can be any number between 1 and 31.</li>
71 /// <li><i>width</i> and <i>height</i> are the image dimensions (in
72 /// pixels).</li>
73 /// </ul>
74 ///
75 /// <u>Data:</u> The image binary values appear one after the other (in raster
76 /// order) immediately after the last header character ('\n') and are
77 /// byte-aligned (they are packed into 1,2 or 4 bytes per sample, depending
78 /// upon the bit-depth value).
79 /// </p>
80 ///
81 /// <p> If the data is unsigned, level shifting is applied adding 2^(bit depth
82 /// - 1)</p>
83 ///
84 /// <p><u>NOTE</u>: This class is not thread safe, for reasons of internal
85 /// buffering.</p>
86 ///
87 /// </summary>
88 /// <seealso cref="ImgWriter">
89 ///
90 /// </seealso>
91 /// <seealso cref="BlkImgDataSrc">
92 ///
93 /// </seealso>
94 public class ImgWriterPGX:ImgWriter
95 {
96  
97 /// <summary>Used during saturation (2^bitdepth-1 if unsigned, 2^(bitdepth-1)-1 if
98 /// signed)
99 /// </summary>
100 internal int maxVal;
101  
102 /// <summary>Used during saturation (0 if unsigned, -2^(bitdepth-1) if signed) </summary>
103 internal int minVal;
104  
105 /// <summary>Used with level-shiting </summary>
106 internal int levShift;
107  
108 /// <summary>Whether the data must be signed when writing or not. In the latter
109 /// case inverse level shifting must be applied
110 /// </summary>
111 internal bool isSigned;
112  
113 /// <summary>The bit-depth of the input file (must be between 1 and 31)</summary>
114 private int bitDepth;
115  
116 /// <summary>Where to write the data </summary>
117 //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'"
118 private System.IO.FileStream out_Renamed;
119  
120 /// <summary>The offset of the raw pixel data in the PGX file </summary>
121 private int offset;
122  
123 /// <summary>A DataBlk, just used to avoid allocating a new one each time it is
124 /// needed
125 /// </summary>
126 private DataBlkInt db = new DataBlkInt();
127  
128 /// <summary>The number of fractional bits in the source data </summary>
129 private int fb;
130  
131 /// <summary>The index of the component from where to get the data </summary>
132 private int c;
133  
134 /// <summary>The pack length of one sample (in bytes, according to the output
135 /// bit-depth
136 /// </summary>
137 private int packBytes;
138  
139 /// <summary>The line buffer. </summary>
140 // This makes the class not thrad safe
141 // (but it is not the only one making it so)
142 private byte[] buf;
143  
144 /// <summary> Creates a new writer to the specified File object, to write data from
145 /// the specified component.
146 ///
147 /// <p>The size of the image that is written to the file is the size of the
148 /// component from which to get the data, specified by b, not the size of
149 /// the source image (they differ if there is some sub-sampling).</p>
150 ///
151 /// <p>All the header informations are given by the BlkImgDataSrc source
152 /// (component width, component height, bit-depth) and sign flag, which are
153 /// provided to the constructor. The endianness is always big-endian (MSB
154 /// first).</p>
155 ///
156 /// </summary>
157 /// <param name="out">The file where to write the data
158 ///
159 /// </param>
160 /// <param name="imgSrc">The source from where to get the image data to write.
161 ///
162 /// </param>
163 /// <param name="c">The index of the component from where to get the data.
164 ///
165 /// </param>
166 /// <param name="isSigned">Whether the datas are signed or not (needed only when
167 /// writing header).
168 ///
169 /// </param>
170 /// <seealso cref="DataBlk">
171 ///
172 /// </seealso>
173 public ImgWriterPGX(System.IO.FileInfo out_Renamed, BlkImgDataSrc imgSrc, int c, bool isSigned)
174 {
175 //Initialize
176 this.c = c;
177 bool tmpBool;
178 if (System.IO.File.Exists(out_Renamed.FullName))
179 tmpBool = true;
180 else
181 tmpBool = System.IO.Directory.Exists(out_Renamed.FullName);
182 bool tmpBool2;
183 if (System.IO.File.Exists(out_Renamed.FullName))
184 {
185 System.IO.File.Delete(out_Renamed.FullName);
186 tmpBool2 = true;
187 }
188 else if (System.IO.Directory.Exists(out_Renamed.FullName))
189 {
190 System.IO.Directory.Delete(out_Renamed.FullName);
191 tmpBool2 = true;
192 }
193 else
194 tmpBool2 = false;
195 if (tmpBool && !tmpBool2)
196 {
197 throw new System.IO.IOException("Could not reset file");
198 }
199 this.out_Renamed = SupportClass.RandomAccessFileSupport.CreateRandomAccessFile(out_Renamed, "rw");
200 this.isSigned = isSigned;
201 src = imgSrc;
202 w = src.ImgWidth;
203 h = src.ImgHeight;
204 fb = imgSrc.getFixedPoint(c);
205  
206 bitDepth = src.getNomRangeBits(this.c);
207 if ((bitDepth <= 0) || (bitDepth > 31))
208 {
209 throw new System.IO.IOException("PGX supports only bit-depth between " + "1 and 31");
210 }
211 if (bitDepth <= 8)
212 {
213 packBytes = 1;
214 }
215 else if (bitDepth <= 16)
216 {
217 packBytes = 2;
218 }
219 else
220 {
221 // <= 31
222 packBytes = 4;
223 }
224  
225 // Writes PGX header
226 System.String tmpString = "PG " + "ML " + ((this.isSigned)?"- ":"+ ") + bitDepth + " " + w + " " + h + "\n"; // component height
227  
228 byte[] tmpByte = System.Text.ASCIIEncoding.ASCII.GetBytes(tmpString);
229 for (int i = 0; i < tmpByte.Length; i++)
230 {
231 this.out_Renamed.WriteByte((byte) tmpByte[i]);
232 }
233  
234 offset = tmpByte.Length;
235 maxVal = this.isSigned?((1 << (src.getNomRangeBits(c) - 1)) - 1):((1 << src.getNomRangeBits(c)) - 1);
236 minVal = this.isSigned?((- 1) * (1 << (src.getNomRangeBits(c) - 1))):0;
237  
238 levShift = (this.isSigned)?0:1 << (src.getNomRangeBits(c) - 1);
239 }
240  
241 /// <summary> Creates a new writer to the specified file, to write data from the
242 /// specified component.
243 ///
244 /// <p>The size of the image that is written to the file is the size of the
245 /// component from which to get the data, specified by b, not the size of
246 /// the source image (they differ if there is some sub-sampling).</p>
247 ///
248 /// <p>All header information is given by the BlkImgDataSrc source
249 /// (component width, component height, bit-depth) and sign flag, which are
250 /// provided to the constructor. The endianness is always big-endian (MSB
251 /// first).
252 ///
253 /// </summary>
254 /// <param name="fname">The name of the file where to write the data
255 ///
256 /// </param>
257 /// <param name="imgSrc">The source from where to get the image data to write.
258 ///
259 /// </param>
260 /// <param name="c">The index of the component from where to get the data.
261 ///
262 /// </param>
263 /// <param name="isSigned">Whether the datas are signed or not (needed only when
264 /// writing header).
265 ///
266 /// </param>
267 /// <seealso cref="DataBlk">
268 ///
269 /// </seealso>
270 public ImgWriterPGX(System.String fname, BlkImgDataSrc imgSrc, int c, bool isSigned):this(new System.IO.FileInfo(fname), imgSrc, c, isSigned)
271 {
272 }
273  
274 /// <summary> Closes the underlying file or netwrok connection to where the data is
275 /// written. Any call to other methods of the class become illegal after a
276 /// call to this one.
277 ///
278 /// </summary>
279 /// <exception cref="IOException">If an I/O error occurs.
280 ///
281 /// </exception>
282 public override void close()
283 {
284 int i;
285 // Finish writing the file, writing 0s at the end if the data at end
286 // has not been written.
287 if (out_Renamed.Length != w * h * packBytes + offset)
288 {
289 // Goto end of file
290 out_Renamed.Seek(out_Renamed.Length, System.IO.SeekOrigin.Begin);
291 // Fill with 0s
292 for (i = offset + w * h * packBytes - (int) out_Renamed.Length; i > 0; i--)
293 {
294 out_Renamed.WriteByte((System.Byte) 0);
295 }
296 }
297 out_Renamed.Close();
298 src = null;
299 out_Renamed = null;
300 db = null;
301 }
302  
303 /// <summary> Writes all buffered data to the file or resource.
304 ///
305 /// </summary>
306 /// <exception cref="IOException">If an I/O error occurs.
307 ///
308 /// </exception>
309 public override void flush()
310 {
311 // No flush is needed since we use RandomAccessFile
312 // Get rid of line buffer (is this a good choice?)
313 buf = null;
314 }
315  
316 /// <summary> Writes the data of the specified area to the file, coordinates are
317 /// relative to the current tile of the source. Before writing, the
318 /// coefficients are limited to the nominal range and packed into 1,2 or 4
319 /// bytes (according to the bit-depth).
320 ///
321 /// <p>If the data is unisigned, level shifting is applied adding 2^(bit
322 /// depth - 1)</p>
323 ///
324 /// <p>This method may not be called concurrently from different
325 /// threads.</p>
326 ///
327 /// <p>If the data returned from the BlkImgDataSrc source is progressive,
328 /// then it is requested over and over until it is not progressive
329 /// anymore.</p>
330 ///
331 /// </summary>
332 /// <param name="ulx">The horizontal coordinate of the upper-left corner of the
333 /// area to write, relative to the current tile.
334 ///
335 /// </param>
336 /// <param name="uly">The vertical coordinate of the upper-left corner of the area
337 /// to write, relative to the current tile.
338 ///
339 /// </param>
340 /// <param name="width">The width of the area to write.
341 ///
342 /// </param>
343 /// <param name="height">The height of the area to write.
344 ///
345 /// </param>
346 /// <exception cref="IOException">If an I/O error occurs.
347 ///
348 /// </exception>
349 public override void write(int ulx, int uly, int w, int h)
350 {
351 int k, i, j;
352 int fracbits = fb; // In local variable for faster access
353 int tOffx, tOffy; // Active tile offset in the X and Y direction
354  
355 // Initialize db
356 db.ulx = ulx;
357 db.uly = uly;
358 db.w = w;
359 db.h = h;
360 // Get the current active tile offset
361 //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'"
362 tOffx = src.getCompULX(c) - (int) System.Math.Ceiling(src.ImgULX / (double) src.getCompSubsX(c));
363 //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'"
364 tOffy = src.getCompULY(c) - (int) System.Math.Ceiling(src.ImgULY / (double) src.getCompSubsY(c));
365 // Check the array size
366 if (db.data_array != null && db.data_array.Length < w * h)
367 {
368 // A new one will be allocated by getInternCompData()
369 db.data_array = null;
370 }
371 // Request the data and make sure it is not
372 // progressive
373 do
374 {
375 db = (DataBlkInt) src.getInternCompData(db, c);
376 }
377 while (db.progressive);
378  
379 int tmp;
380  
381  
382 // Check line buffer
383 if (buf == null || buf.Length < packBytes * w)
384 {
385 buf = new byte[packBytes * w]; // Expand buffer
386 }
387  
388 switch (packBytes)
389 {
390  
391  
392 case 1: // Samples packed into 1 byte
393 // Write line by line
394 for (i = 0; i < h; i++)
395 {
396 // Skip to beggining of line in file
397 out_Renamed.Seek(offset + this.w * (uly + tOffy + i) + ulx + tOffx, System.IO.SeekOrigin.Begin);
398 // Write all bytes in the line
399 if (fracbits == 0)
400 {
401 for (k = db.offset + i * db.scanw + w - 1, j = w - 1; j >= 0; k--)
402 {
403 tmp = db.data_array[k] + levShift;
404 buf[j--] = (byte) ((tmp < minVal)?minVal:((tmp > maxVal)?maxVal:tmp));
405 }
406 }
407 else
408 {
409 for (k = db.offset + i * db.scanw + w - 1, j = w - 1; j >= 0; k--)
410 {
411 tmp = (SupportClass.URShift(db.data_array[k], fracbits)) + levShift;
412 buf[j--] = (byte) ((tmp < minVal)?minVal:((tmp > maxVal)?maxVal:tmp));
413 }
414 }
415 out_Renamed.Write(buf, 0, w);
416 }
417 break;
418  
419  
420 case 2: // Samples packed in to 2 bytes (short)
421 // Write line by line
422 for (i = 0; i < h; i++)
423 {
424  
425 // Skip to beggining of line in file
426 out_Renamed.Seek(offset + 2 * (this.w * (uly + tOffy + i) + ulx + tOffx), System.IO.SeekOrigin.Begin);
427 // Write all bytes in the line
428 if (fracbits == 0)
429 {
430 for (k = db.offset + i * db.scanw + w - 1, j = (w << 1) - 1; j >= 0; k--)
431 {
432 tmp = db.data_array[k] + levShift;
433 tmp = (tmp < minVal)?minVal:((tmp > maxVal)?maxVal:tmp);
434 buf[j--] = (byte) tmp; // no need for 0xFF mask since
435 // truncation will do it already
436 buf[j--] = (byte) (SupportClass.URShift(tmp, 8));
437 }
438 }
439 else
440 {
441 for (k = db.offset + i * db.scanw + w - 1, j = (w << 1) - 1; j >= 0; k--)
442 {
443 tmp = (SupportClass.URShift(db.data_array[k], fracbits)) + levShift;
444 tmp = (tmp < minVal)?minVal:((tmp > maxVal)?maxVal:tmp);
445 buf[j--] = (byte) tmp; // no need for 0xFF mask since
446 // truncation will do it already
447 buf[j--] = (byte) (SupportClass.URShift(tmp, 8));
448 }
449 }
450 out_Renamed.Write(buf, 0, w << 1);
451 }
452 break;
453  
454  
455 case 4:
456 // Write line by line
457 for (i = 0; i < h; i++)
458 {
459 // Skip to beggining of line in file
460 out_Renamed.Seek(offset + 4 * (this.w * (uly + tOffy + i) + ulx + tOffx), System.IO.SeekOrigin.Begin);
461 // Write all bytes in the line
462 if (fracbits == 0)
463 {
464 for (k = db.offset + i * db.scanw + w - 1, j = (w << 2) - 1; j >= 0; k--)
465 {
466 tmp = db.data_array[k] + levShift;
467 tmp = (tmp < minVal)?minVal:((tmp > maxVal)?maxVal:tmp);
468 buf[j--] = (byte) tmp; // No need to use 0xFF
469 buf[j--] = (byte) (SupportClass.URShift(tmp, 8)); // masks since truncation
470 buf[j--] = (byte) (SupportClass.URShift(tmp, 16)); // will have already the
471 buf[j--] = (byte) (SupportClass.URShift(tmp, 24)); // same effect
472 }
473 }
474 else
475 {
476 for (k = db.offset + i * db.scanw + w - 1, j = (w << 2) - 1; j >= 0; k--)
477 {
478 tmp = (SupportClass.URShift(db.data_array[k], fracbits)) + levShift;
479 tmp = (tmp < minVal)?minVal:((tmp > maxVal)?maxVal:tmp);
480 buf[j--] = (byte) tmp; // No need to use 0xFF
481 buf[j--] = (byte) (SupportClass.URShift(tmp, 8)); // masks since truncation
482 buf[j--] = (byte) (SupportClass.URShift(tmp, 16)); // will have already the
483 buf[j--] = (byte) (SupportClass.URShift(tmp, 24)); // same effect
484 }
485 }
486 out_Renamed.Write(buf, 0, w << 2);
487 }
488 break;
489  
490  
491 default:
492 throw new System.IO.IOException("PGX supports only bit-depth between " + "1 and 31");
493  
494 }
495 }
496  
497 /// <summary> Writes the source's current tile to the output. The requests of data
498 /// issued to the source BlkImgDataSrc object are done by strips, in order
499 /// to reduce memory usage.
500 ///
501 /// <p>If the data returned from the BlkImgDataSrc source is progressive,
502 /// then it is requested over and over until it is not progressive
503 /// anymore.</p>
504 ///
505 /// </summary>
506 /// <exception cref="IOException">If an I/O error occurs.
507 ///
508 /// </exception>
509 /// <seealso cref="DataBlk">
510 ///
511 /// </seealso>
512 public override void write()
513 {
514 int i;
515 int tIdx = src.TileIdx;
516 int tw = src.getTileCompWidth(tIdx, c); // Tile width
517 int th = src.getTileCompHeight(tIdx, c); // Tile height
518 // Write in strips
519 for (i = 0; i < th; i += DEF_STRIP_HEIGHT)
520 {
521 write(0, i, tw, (th - i < DEF_STRIP_HEIGHT)?th - i:DEF_STRIP_HEIGHT);
522 }
523 }
524  
525 /// <summary> Returns a string of information about the object, more than 1 line
526 /// long. The information string includes information from the underlying
527 /// RandomAccessFile (its toString() method is called in turn).
528 ///
529 /// </summary>
530 /// <returns> A string of information about the object.
531 ///
532 /// </returns>
533 public override System.String ToString()
534 {
535 //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'"
536 return "ImgWriterPGX: WxH = " + w + "x" + h + ", Component = " + c + ", Bit-depth = " + bitDepth + ", signed = " + isSigned + "\nUnderlying RandomAccessFile:\n" + out_Renamed.ToString();
537 }
538 }
539 }