1 | |
2 | //
|
3 | // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
4 | //
|
5 | // By downloading, copying, installing or using the software you agree to this license.
|
6 | // If you do not agree to this license, do not download, install,
|
7 | // copy or use the software.
|
8 | //
|
9 | //
|
10 | // License Agreement
|
11 | // For Open Source Computer Vision Library
|
12 | //
|
13 | // Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
|
14 | // Copyright (C) 2009, Willow Garage Inc., all rights reserved.
|
15 | // Third party copyrights are property of their respective owners.
|
16 | //
|
17 | // Redistribution and use in source and binary forms, with or without modification,
|
18 | // are permitted provided that the following conditions are met:
|
19 | //
|
20 | // * Redistribution's of source code must retain the above copyright notice,
|
21 | // this list of conditions and the following disclaimer.
|
22 | //
|
23 | // * Redistribution's in binary form must reproduce the above copyright notice,
|
24 | // this list of conditions and the following disclaimer in the documentation
|
25 | // and/or other materials provided with the distribution.
|
26 | //
|
27 | // * The name of the copyright holders may not be used to endorse or promote products
|
28 | // derived from this software without specific prior written permission.
|
29 | //
|
30 | // This software is provided by the copyright holders and contributors "as is" and
|
31 | // any express or implied warranties, including, but not limited to, the implied
|
32 | // warranties of merchantability and fitness for a particular purpose are disclaimed.
|
33 | // In no event shall the Intel Corporation or contributors be liable for any direct,
|
34 | // indirect, incidental, special, exemplary, or consequential damages
|
35 | // (including, but not limited to, procurement of substitute goods or services;
|
36 | // loss of use, data, or profits; or business interruption) however caused
|
37 | // and on any theory of liability, whether in contract, strict liability,
|
38 | // or tort (including negligence or otherwise) arising in any way out of
|
39 | // the use of this software, even if advised of the possibility of such damage.
|
40 | //
|
41 | //M*/
|
42 |
|
43 | |
44 | A part of the file implements TIFF reader on base of libtiff library
|
45 | (see otherlibs/_graphics/readme.txt for copyright notice)
|
46 | \****************************************************************************************/
|
47 |
|
48 | #include "precomp.hpp"
|
49 | #include "grfmt_tiff.hpp"
|
50 |
|
51 | namespace cv
|
52 | {
|
53 | static const char fmtSignTiffII[] = "II\x2a\x00";
|
54 | static const char fmtSignTiffMM[] = "MM\x00\x2a";
|
55 |
|
56 | #ifdef HAVE_TIFF
|
57 |
|
58 | #include "tiff.h"
|
59 | #include "tiffio.h"
|
60 |
|
61 | static int grfmt_tiff_err_handler_init = 0;
|
62 | static void GrFmtSilentTIFFErrorHandler( const char*, const char*, va_list ) {}
|
63 |
|
64 | TiffDecoder::TiffDecoder()
|
65 | {
|
66 | m_tif = 0;
|
67 | if( !grfmt_tiff_err_handler_init )
|
68 | {
|
69 | grfmt_tiff_err_handler_init = 1;
|
70 |
|
71 | TIFFSetErrorHandler( GrFmtSilentTIFFErrorHandler );
|
72 | TIFFSetWarningHandler( GrFmtSilentTIFFErrorHandler );
|
73 | }
|
74 | }
|
75 |
|
76 |
|
77 | void TiffDecoder::close()
|
78 | {
|
79 | if( m_tif )
|
80 | {
|
81 | TIFF* tif = (TIFF*)m_tif;
|
82 | TIFFClose( tif );
|
83 | m_tif = 0;
|
84 | }
|
85 | }
|
86 |
|
87 | TiffDecoder::~TiffDecoder()
|
88 | {
|
89 | close();
|
90 | }
|
91 |
|
92 | size_t TiffDecoder::signatureLength() const
|
93 | {
|
94 | return 4;
|
95 | }
|
96 |
|
97 | bool TiffDecoder::checkSignature( const string& signature ) const
|
98 | {
|
99 | return signature.size() >= 4 &&
|
100 | (memcmp(signature.c_str(), fmtSignTiffII, 4) == 0 ||
|
101 | memcmp(signature.c_str(), fmtSignTiffMM, 4) == 0);
|
102 | }
|
103 |
|
104 | ImageDecoder TiffDecoder::newDecoder() const
|
105 | {
|
106 | return new TiffDecoder;
|
107 | }
|
108 |
|
109 | bool TiffDecoder::readHeader()
|
110 | {
|
111 | bool result = false;
|
112 |
|
113 | close();
|
114 | TIFF* tif = TIFFOpen( m_filename.c_str(), "rb" );
|
115 |
|
116 | if( tif )
|
117 | {
|
118 | uint32 wdth = 0, hght = 0;
|
119 | uint16 photometric = 0;
|
120 | m_tif = tif;
|
121 |
|
122 | if( TIFFGetField( tif, TIFFTAG_IMAGEWIDTH, &wdth ) &&
|
123 | TIFFGetField( tif, TIFFTAG_IMAGELENGTH, &hght ) &&
|
124 | TIFFGetField( tif, TIFFTAG_PHOTOMETRIC, &photometric ))
|
125 | {
|
126 | uint16 bpp=8, ncn = photometric > 1 ? 3 : 1;
|
127 | TIFFGetField( tif, TIFFTAG_BITSPERSAMPLE, &bpp );
|
128 | TIFFGetField( tif, TIFFTAG_SAMPLESPERPIXEL, &ncn );
|
129 |
|
130 | m_width = wdth;
|
131 | m_height = hght;
|
132 | if( bpp > 8 &&
|
133 | ((photometric != 2 && photometric != 1) ||
|
134 | (ncn != 1 && ncn != 3 && ncn != 4)))
|
135 | bpp = 8;
|
136 |
|
137 | switch(bpp)
|
138 | {
|
139 | case 8:
|
140 | m_type = CV_MAKETYPE(CV_8U, photometric > 1 ? 3 : 1);
|
141 | break;
|
142 | case 16:
|
143 | m_type = CV_MAKETYPE(CV_16U, photometric > 1 ? 3 : 1);
|
144 | break;
|
145 |
|
146 | case 32:
|
147 | m_type = CV_MAKETYPE(CV_32F, photometric > 1 ? 3 : 1);
|
148 | break;
|
149 | case 64:
|
150 | m_type = CV_MAKETYPE(CV_64F, photometric > 1 ? 3 : 1);
|
151 | break;
|
152 |
|
153 | default:
|
154 | result = false;
|
155 | }
|
156 | result = true;
|
157 | }
|
158 | }
|
159 |
|
160 | if( !result )
|
161 | close();
|
162 |
|
163 | return result;
|
164 | }
|
165 |
|
166 |
|
167 | bool TiffDecoder::readData( Mat& img )
|
168 | {
|
169 | bool result = false;
|
170 | bool color = img.channels() > 1;
|
171 | uchar* data = img.data;
|
172 | int step = (int)img.step;
|
173 |
|
174 | if( img.depth() != CV_8U && img.depth() != CV_16U && img.depth() != CV_32F && img.depth() != CV_64F )
|
175 | return false;
|
176 |
|
177 | if( m_tif && m_width && m_height )
|
178 | {
|
179 | TIFF* tif = (TIFF*)m_tif;
|
180 | uint32 tile_width0 = m_width, tile_height0 = 0;
|
181 | int x, y, i;
|
182 | int is_tiled = TIFFIsTiled(tif);
|
183 | uint16 photometric;
|
184 | TIFFGetField( tif, TIFFTAG_PHOTOMETRIC, &photometric );
|
185 | uint16 bpp = 8, ncn = photometric > 1 ? 3 : 1;
|
186 | TIFFGetField( tif, TIFFTAG_BITSPERSAMPLE, &bpp );
|
187 | TIFFGetField( tif, TIFFTAG_SAMPLESPERPIXEL, &ncn );
|
188 | const int bitsPerByte = 8;
|
189 | int dst_bpp = (int)(img.elemSize1() * bitsPerByte);
|
190 |
|
191 | if(dst_bpp == 8)
|
192 | {
|
193 | char errmsg[1024];
|
194 | if(!TIFFRGBAImageOK( tif, errmsg ))
|
195 | {
|
196 | close();
|
197 | return false;
|
198 | }
|
199 | }
|
200 |
|
201 | if( (!is_tiled) ||
|
202 | (is_tiled &&
|
203 | TIFFGetField( tif, TIFFTAG_TILEWIDTH, &tile_width0 ) &&
|
204 | TIFFGetField( tif, TIFFTAG_TILELENGTH, &tile_height0 )))
|
205 | {
|
206 | if(!is_tiled)
|
207 | TIFFGetField( tif, TIFFTAG_ROWSPERSTRIP, &tile_height0 );
|
208 |
|
209 | if( tile_width0 <= 0 )
|
210 | tile_width0 = m_width;
|
211 |
|
212 | if( tile_height0 <= 0 )
|
213 | tile_height0 = m_height;
|
214 |
|
215 | AutoBuffer<uchar> _buffer(tile_height0*tile_width0*8);
|
216 | uchar* buffer = _buffer;
|
217 | ushort* buffer16 = (ushort*)buffer;
|
218 | float* buffer32 = (float*)buffer;
|
219 | double* buffer64 = (double*)buffer;
|
220 | int tileidx = 0;
|
221 |
|
222 | for( y = 0; y < m_height; y += tile_height0, data += step*tile_height0 )
|
223 | {
|
224 | int tile_height = tile_height0;
|
225 |
|
226 | if( y + tile_height > m_height )
|
227 | tile_height = m_height - y;
|
228 |
|
229 | for( x = 0; x < m_width; x += tile_width0, tileidx++ )
|
230 | {
|
231 | int tile_width = tile_width0, ok;
|
232 |
|
233 | if( x + tile_width > m_width )
|
234 | tile_width = m_width - x;
|
235 |
|
236 | switch(dst_bpp)
|
237 | {
|
238 | case 8:
|
239 | {
|
240 | if( !is_tiled )
|
241 | ok = TIFFReadRGBAStrip( tif, y, (uint32*)buffer );
|
242 | else
|
243 | ok = TIFFReadRGBATile( tif, x, y, (uint32*)buffer );
|
244 |
|
245 | if( !ok )
|
246 | {
|
247 | close();
|
248 | return false;
|
249 | }
|
250 |
|
251 | for( i = 0; i < tile_height; i++ )
|
252 | if( color )
|
253 | icvCvt_BGRA2BGR_8u_C4C3R( buffer + i*tile_width*4, 0,
|
254 | data + x*3 + step*(tile_height - i - 1), 0,
|
255 | cvSize(tile_width,1), 2 );
|
256 | else
|
257 | icvCvt_BGRA2Gray_8u_C4C1R( buffer + i*tile_width*4, 0,
|
258 | data + x + step*(tile_height - i - 1), 0,
|
259 | cvSize(tile_width,1), 2 );
|
260 | break;
|
261 | }
|
262 |
|
263 | case 16:
|
264 | {
|
265 | if( !is_tiled )
|
266 | ok = (int)TIFFReadEncodedStrip( tif, tileidx, (uint32*)buffer, (tsize_t)-1 ) >= 0;
|
267 | else
|
268 | ok = (int)TIFFReadEncodedTile( tif, tileidx, (uint32*)buffer, (tsize_t)-1 ) >= 0;
|
269 |
|
270 | if( !ok )
|
271 | {
|
272 | close();
|
273 | return false;
|
274 | }
|
275 |
|
276 | for( i = 0; i < tile_height; i++ )
|
277 | {
|
278 | if( color )
|
279 | {
|
280 | if( ncn == 1 )
|
281 | {
|
282 | icvCvt_Gray2BGR_16u_C1C3R(buffer16 + i*tile_width*ncn, 0,
|
283 | (ushort*)(data + step*i) + x*3, 0,
|
284 | cvSize(tile_width,1) );
|
285 | }
|
286 | else if( ncn == 3 )
|
287 | {
|
288 | icvCvt_RGB2BGR_16u_C3R(buffer16 + i*tile_width*ncn, 0,
|
289 | (ushort*)(data + step*i) + x*3, 0,
|
290 | cvSize(tile_width,1) );
|
291 | }
|
292 | else
|
293 | {
|
294 | icvCvt_BGRA2BGR_16u_C4C3R(buffer16 + i*tile_width*ncn, 0,
|
295 | (ushort*)(data + step*i) + x*3, 0,
|
296 | cvSize(tile_width,1), 2 );
|
297 | }
|
298 | }
|
299 | else
|
300 | {
|
301 | if( ncn == 1 )
|
302 | {
|
303 | memcpy((ushort*)(data + step*i)+x,
|
304 | buffer16 + i*tile_width*ncn,
|
305 | tile_width*sizeof(buffer16[0]));
|
306 | }
|
307 | else
|
308 | {
|
309 | icvCvt_BGRA2Gray_16u_CnC1R(buffer16 + i*tile_width*ncn, 0,
|
310 | (ushort*)(data + step*i) + x, 0,
|
311 | cvSize(tile_width,1), ncn, 2 );
|
312 | }
|
313 | }
|
314 | }
|
315 | break;
|
316 | }
|
317 |
|
318 | case 32:
|
319 | case 64:
|
320 | {
|
321 | if( !is_tiled )
|
322 | ok = (int)TIFFReadEncodedStrip( tif, tileidx, buffer, (tsize_t)-1 ) >= 0;
|
323 | else
|
324 | ok = (int)TIFFReadEncodedTile( tif, tileidx, buffer, (tsize_t)-1 ) >= 0;
|
325 |
|
326 | if( !ok || ncn != 1 )
|
327 | {
|
328 | close();
|
329 | return false;
|
330 | }
|
331 |
|
332 | for( i = 0; i < tile_height; i++ )
|
333 | {
|
334 | if(dst_bpp == 32)
|
335 | {
|
336 | memcpy((float*)(data + step*i)+x,
|
337 | buffer32 + i*tile_width*ncn,
|
338 | tile_width*sizeof(buffer32[0]));
|
339 | }
|
340 | else
|
341 | {
|
342 | memcpy((double*)(data + step*i)+x,
|
343 | buffer64 + i*tile_width*ncn,
|
344 | tile_width*sizeof(buffer64[0]));
|
345 | }
|
346 | }
|
347 |
|
348 | break;
|
349 | }
|
350 | default:
|
351 | {
|
352 | close();
|
353 | return false;
|
354 | }
|
355 | }
|
356 | }
|
357 | }
|
358 |
|
359 | result = true;
|
360 | }
|
361 | }
|
362 |
|
363 | close();
|
364 | return result;
|
365 | }
|
366 |
|
367 | #endif
|
368 |
|
369 |
|
370 |
|
371 | TiffEncoder::TiffEncoder()
|
372 | {
|
373 | m_description = "TIFF Files (*.tiff;*.tif)";
|
374 | #ifdef HAVE_TIFF
|
375 | m_buf_supported = false;
|
376 | #else
|
377 | m_buf_supported = true;
|
378 | #endif
|
379 | }
|
380 |
|
381 | TiffEncoder::~TiffEncoder()
|
382 | {
|
383 | }
|
384 |
|
385 | ImageEncoder TiffEncoder::newEncoder() const
|
386 | {
|
387 | return new TiffEncoder;
|
388 | }
|
389 |
|
390 | bool TiffEncoder::isFormatSupported( int depth ) const
|
391 | {
|
392 | return depth == CV_8U || depth == CV_16U;
|
393 | }
|
394 |
|
395 | void TiffEncoder::writeTag( WLByteStream& strm, TiffTag tag,
|
396 | TiffFieldType fieldType,
|
397 | int count, int value )
|
398 | {
|
399 | strm.putWord( tag );
|
400 | strm.putWord( fieldType );
|
401 | strm.putDWord( count );
|
402 | strm.putDWord( value );
|
403 | }
|
404 |
|
405 | #ifdef HAVE_TIFF
|
406 | bool TiffEncoder::writeLibTiff( const Mat& img, const vector<int>& )
|
407 | {
|
408 | int channels = img.channels();
|
409 | int width = img.cols, height = img.rows;
|
410 | int depth = img.depth();
|
411 |
|
412 | int bitsPerChannel = -1;
|
413 | switch (depth)
|
414 | {
|
415 | case CV_8U:
|
416 | {
|
417 | bitsPerChannel = 8;
|
418 | break;
|
419 | }
|
420 | case CV_16U:
|
421 | {
|
422 | bitsPerChannel = 16;
|
423 | break;
|
424 | }
|
425 | default:
|
426 | {
|
427 | return false;
|
428 | }
|
429 | }
|
430 |
|
431 | const int bitsPerByte = 8;
|
432 | size_t fileStep = (width * channels * bitsPerChannel) / bitsPerByte;
|
433 | int rowsPerStrip = (int)((1 << 13)/fileStep);
|
434 |
|
435 | if( rowsPerStrip < 1 )
|
436 | rowsPerStrip = 1;
|
437 |
|
438 | if( rowsPerStrip > height )
|
439 | rowsPerStrip = height;
|
440 |
|
441 |
|
442 |
|
443 |
|
444 | TIFF* pTiffHandle = TIFFOpen(m_filename.c_str(), "w");
|
445 | if (!pTiffHandle)
|
446 | {
|
447 | return false;
|
448 | }
|
449 |
|
450 |
|
451 | int compression = COMPRESSION_LZW;
|
452 | int predictor = PREDICTOR_HORIZONTAL;
|
453 |
|
454 | int colorspace = channels > 1 ? PHOTOMETRIC_RGB : PHOTOMETRIC_MINISBLACK;
|
455 |
|
456 | if ( !TIFFSetField(pTiffHandle, TIFFTAG_IMAGEWIDTH, width)
|
457 | || !TIFFSetField(pTiffHandle, TIFFTAG_IMAGELENGTH, height)
|
458 | || !TIFFSetField(pTiffHandle, TIFFTAG_BITSPERSAMPLE, bitsPerChannel)
|
459 | || !TIFFSetField(pTiffHandle, TIFFTAG_COMPRESSION, compression)
|
460 | || !TIFFSetField(pTiffHandle, TIFFTAG_PHOTOMETRIC, colorspace)
|
461 | || !TIFFSetField(pTiffHandle, TIFFTAG_SAMPLESPERPIXEL, channels)
|
462 | || !TIFFSetField(pTiffHandle, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG)
|
463 | || !TIFFSetField(pTiffHandle, TIFFTAG_ROWSPERSTRIP, rowsPerStrip)
|
464 | || !TIFFSetField(pTiffHandle, TIFFTAG_PREDICTOR, predictor)
|
465 | )
|
466 | {
|
467 | TIFFClose(pTiffHandle);
|
468 | return false;
|
469 | }
|
470 |
|
471 |
|
472 | size_t scanlineSize = TIFFScanlineSize(pTiffHandle);
|
473 | AutoBuffer<uchar,1024> _buffer(scanlineSize+32);
|
474 | uchar* buffer = _buffer;
|
475 | if (!buffer)
|
476 | {
|
477 | TIFFClose(pTiffHandle);
|
478 | return false;
|
479 | }
|
480 |
|
481 | for (int y = 0; y < height; ++y)
|
482 | {
|
483 | switch(channels)
|
484 | {
|
485 | case 1:
|
486 | {
|
487 | memcpy(buffer, img.data + img.step * y, scanlineSize);
|
488 | break;
|
489 | }
|
490 |
|
491 | case 3:
|
492 | {
|
493 | if (depth == CV_8U)
|
494 | icvCvt_BGR2RGB_8u_C3R( img.data + img.step*y, 0, buffer, 0, cvSize(width,1) );
|
495 | else
|
496 | icvCvt_BGR2RGB_16u_C3R( (const ushort*)(img.data + img.step*y), 0, (ushort*)buffer, 0, cvSize(width,1) );
|
497 | break;
|
498 | }
|
499 |
|
500 | case 4:
|
501 | {
|
502 | if (depth == CV_8U)
|
503 | icvCvt_BGRA2RGBA_8u_C4R( img.data + img.step*y, 0, buffer, 0, cvSize(width,1) );
|
504 | else
|
505 | icvCvt_BGRA2RGBA_16u_C4R( (const ushort*)(img.data + img.step*y), 0, (ushort*)buffer, 0, cvSize(width,1) );
|
506 | break;
|
507 | }
|
508 |
|
509 | default:
|
510 | {
|
511 | TIFFClose(pTiffHandle);
|
512 | return false;
|
513 | }
|
514 | }
|
515 |
|
516 | int writeResult = TIFFWriteScanline(pTiffHandle, buffer, y, 0);
|
517 | if (writeResult != 1)
|
518 | {
|
519 | TIFFClose(pTiffHandle);
|
520 | return false;
|
521 | }
|
522 | }
|
523 |
|
524 | TIFFClose(pTiffHandle);
|
525 | return true;
|
526 | }
|
527 |
|
528 | #endif
|
529 |
|
530 | #ifdef HAVE_TIFF
|
531 | bool TiffEncoder::write( const Mat& img, const vector<int>& params)
|
532 | #else
|
533 | bool TiffEncoder::write( const Mat& img, const vector<int>& )
|
534 | #endif
|
535 | {
|
536 | int channels = img.channels();
|
537 | int width = img.cols, height = img.rows;
|
538 | int depth = img.depth();
|
539 |
|
540 | if (depth != CV_8U && depth != CV_16U)
|
541 | return false;
|
542 |
|
543 | int bytesPerChannel = depth == CV_8U ? 1 : 2;
|
544 | int fileStep = width * channels * bytesPerChannel;
|
545 |
|
546 | WLByteStream strm;
|
547 |
|
548 | if( m_buf )
|
549 | {
|
550 | if( !strm.open(*m_buf) )
|
551 | return false;
|
552 | }
|
553 | else
|
554 | {
|
555 | #ifdef HAVE_TIFF
|
556 | return writeLibTiff(img, params);
|
557 | #else
|
558 | if( !strm.open(m_filename) )
|
559 | return false;
|
560 | #endif
|
561 | }
|
562 |
|
563 | int rowsPerStrip = (1 << 13)/fileStep;
|
564 |
|
565 | if( rowsPerStrip < 1 )
|
566 | rowsPerStrip = 1;
|
567 |
|
568 | if( rowsPerStrip > height )
|
569 | rowsPerStrip = height;
|
570 |
|
571 | int i, stripCount = (height + rowsPerStrip - 1) / rowsPerStrip;
|
572 |
|
573 | if( m_buf )
|
574 | m_buf->reserve( alignSize(stripCount*8 + fileStep*height + 256, 256) );
|
575 |
|
576 | |
577 | int uncompressedRowSize = rowsPerStrip * fileStep;
|
578 | #endif*/
|
579 | int directoryOffset = 0;
|
580 |
|
581 | AutoBuffer<int,1024> stripOffsets(stripCount);
|
582 | AutoBuffer<short,1024> stripCounts(stripCount);
|
583 | AutoBuffer<uchar,1024> _buffer(fileStep+32);
|
584 | uchar* buffer = _buffer;
|
585 | int stripOffsetsOffset = 0;
|
586 | int stripCountsOffset = 0;
|
587 | int bitsPerSample = 8 * bytesPerChannel;
|
588 | int y = 0;
|
589 |
|
590 | strm.putBytes( fmtSignTiffII, 4 );
|
591 | strm.putDWord( directoryOffset );
|
592 |
|
593 |
|
594 |
|
595 | for( i = 0; i < stripCount; i++ )
|
596 | {
|
597 | int limit = y + rowsPerStrip;
|
598 |
|
599 | if( limit > height )
|
600 | limit = height;
|
601 |
|
602 | stripOffsets[i] = strm.getPos();
|
603 |
|
604 | for( ; y < limit; y++ )
|
605 | {
|
606 | if( channels == 3 )
|
607 | {
|
608 | if (depth == CV_8U)
|
609 | icvCvt_BGR2RGB_8u_C3R( img.data + img.step*y, 0, buffer, 0, cvSize(width,1) );
|
610 | else
|
611 | icvCvt_BGR2RGB_16u_C3R( (const ushort*)(img.data + img.step*y), 0, (ushort*)buffer, 0, cvSize(width,1) );
|
612 | }
|
613 | else
|
614 | {
|
615 | if( channels == 4 )
|
616 | {
|
617 | if (depth == CV_8U)
|
618 | icvCvt_BGRA2RGBA_8u_C4R( img.data + img.step*y, 0, buffer, 0, cvSize(width,1) );
|
619 | else
|
620 | icvCvt_BGRA2RGBA_16u_C4R( (const ushort*)(img.data + img.step*y), 0, (ushort*)buffer, 0, cvSize(width,1) );
|
621 | }
|
622 | }
|
623 |
|
624 | strm.putBytes( channels > 1 ? buffer : img.data + img.step*y, fileStep );
|
625 | }
|
626 |
|
627 | stripCounts[i] = (short)(strm.getPos() - stripOffsets[i]);
|
628 | |
629 | stripCounts[i] < uncompressedRowSize &&
|
630 | i == stripCount - 1);*/
|
631 | }
|
632 |
|
633 | if( stripCount > 2 )
|
634 | {
|
635 | stripOffsetsOffset = strm.getPos();
|
636 | for( i = 0; i < stripCount; i++ )
|
637 | strm.putDWord( stripOffsets[i] );
|
638 |
|
639 | stripCountsOffset = strm.getPos();
|
640 | for( i = 0; i < stripCount; i++ )
|
641 | strm.putWord( stripCounts[i] );
|
642 | }
|
643 | else if(stripCount == 2)
|
644 | {
|
645 | stripOffsetsOffset = strm.getPos();
|
646 | for (i = 0; i < stripCount; i++)
|
647 | {
|
648 | strm.putDWord (stripOffsets [i]);
|
649 | }
|
650 | stripCountsOffset = stripCounts [0] + (stripCounts [1] << 16);
|
651 | }
|
652 | else
|
653 | {
|
654 | stripOffsetsOffset = stripOffsets[0];
|
655 | stripCountsOffset = stripCounts[0];
|
656 | }
|
657 |
|
658 | if( channels > 1 )
|
659 | {
|
660 | int bitsPerSamplePos = strm.getPos();
|
661 | strm.putWord(bitsPerSample);
|
662 | strm.putWord(bitsPerSample);
|
663 | strm.putWord(bitsPerSample);
|
664 | if( channels == 4 )
|
665 | strm.putWord(bitsPerSample);
|
666 | bitsPerSample = bitsPerSamplePos;
|
667 | }
|
668 |
|
669 | directoryOffset = strm.getPos();
|
670 |
|
671 |
|
672 | strm.putWord( 9 );
|
673 |
|
674 | |
675 | ascending order. This is a non-fatal error, but this cause
|
676 | warning with some tools. So, keep this in ascending order */
|
677 |
|
678 | writeTag( strm, TIFF_TAG_WIDTH, TIFF_TYPE_LONG, 1, width );
|
679 | writeTag( strm, TIFF_TAG_HEIGHT, TIFF_TYPE_LONG, 1, height );
|
680 | writeTag( strm, TIFF_TAG_BITS_PER_SAMPLE,
|
681 | TIFF_TYPE_SHORT, channels, bitsPerSample );
|
682 | writeTag( strm, TIFF_TAG_COMPRESSION, TIFF_TYPE_LONG, 1, TIFF_UNCOMP );
|
683 | writeTag( strm, TIFF_TAG_PHOTOMETRIC, TIFF_TYPE_SHORT, 1, channels > 1 ? 2 : 1 );
|
684 |
|
685 | writeTag( strm, TIFF_TAG_STRIP_OFFSETS, TIFF_TYPE_LONG,
|
686 | stripCount, stripOffsetsOffset );
|
687 |
|
688 | writeTag( strm, TIFF_TAG_SAMPLES_PER_PIXEL, TIFF_TYPE_SHORT, 1, channels );
|
689 | writeTag( strm, TIFF_TAG_ROWS_PER_STRIP, TIFF_TYPE_LONG, 1, rowsPerStrip );
|
690 |
|
691 | writeTag( strm, TIFF_TAG_STRIP_COUNTS,
|
692 | stripCount > 1 ? TIFF_TYPE_SHORT : TIFF_TYPE_LONG,
|
693 | stripCount, stripCountsOffset );
|
694 |
|
695 | strm.putDWord(0);
|
696 | strm.close();
|
697 |
|
698 | if( m_buf )
|
699 | {
|
700 | (*m_buf)[4] = (uchar)directoryOffset;
|
701 | (*m_buf)[5] = (uchar)(directoryOffset >> 8);
|
702 | (*m_buf)[6] = (uchar)(directoryOffset >> 16);
|
703 | (*m_buf)[7] = (uchar)(directoryOffset >> 24);
|
704 | }
|
705 | else
|
706 | {
|
707 |
|
708 | FILE* f = fopen( m_filename.c_str(), "r+b" );
|
709 | buffer[0] = (uchar)directoryOffset;
|
710 | buffer[1] = (uchar)(directoryOffset >> 8);
|
711 | buffer[2] = (uchar)(directoryOffset >> 16);
|
712 | buffer[3] = (uchar)(directoryOffset >> 24);
|
713 |
|
714 | fseek( f, 4, SEEK_SET );
|
715 | fwrite( buffer, 1, 4, f );
|
716 | fclose(f);
|
717 | }
|
718 |
|
719 | return true;
|
720 | }
|
721 |
|
722 | }
|