1
|
#include <Draw/Draw.h>
|
2
|
#include "tif.h"
|
3
|
|
4
|
#ifdef PLATFORM_WIN32
|
5
|
#define tif_int32 long
|
6
|
#define tif_uint32 unsigned long
|
7
|
#else
|
8
|
#define tif_int32 int
|
9
|
#define tif_uint32 unsigned int
|
10
|
#endif
|
11
|
|
12
|
#define LLOG(x)
|
13
|
|
14
|
|
15
|
|
16
|
NAMESPACE_UPP
|
17
|
|
18
|
#if DBGALLOC
|
19
|
double total_allocated = 0, total_freed = 0;
|
20
|
unsigned alloc_calls = 0, free_calls = 0, realloc_calls = 0;
|
21
|
Index<tsize_t> size_index;
|
22
|
Vector<int> size_alloc_calls, size_free_calls;
|
23
|
int op_id;
|
24
|
|
25
|
void dbgAddAlloc(void *p, tsize_t s)
|
26
|
{
|
27
|
++op_id;
|
28
|
total_allocated += s;
|
29
|
int i = size_index.Find(s);
|
30
|
if(i >= 0)
|
31
|
size_alloc_calls[i]++;
|
32
|
else
|
33
|
{
|
34
|
size_index.Add(s);
|
35
|
size_alloc_calls.Add(1);
|
36
|
size_free_calls.Add(0);
|
37
|
}
|
38
|
LLOG(op_id << " tAlloc(" << s << ") = " << p << ": blks: " << alloc_calls - free_calls << ", alloc = " << total_allocated << ", free = " << total_freed << ", diff = " << (total_allocated - total_freed));
|
39
|
}
|
40
|
|
41
|
void dbgAddFree(void *p, tsize_t s)
|
42
|
{
|
43
|
++op_id;
|
44
|
total_freed += s;
|
45
|
int i = size_index.Find(s);
|
46
|
if(i >= 0)
|
47
|
size_free_calls[i]++;
|
48
|
else
|
49
|
{
|
50
|
size_index.Add(s);
|
51
|
size_alloc_calls.Add(0);
|
52
|
size_free_calls.Add(1);
|
53
|
}
|
54
|
LLOG(op_id << " tFree(" << p << ") = " << s << ": blks: " << alloc_calls - free_calls << ", alloc = " << total_allocated << ", free = " << total_freed << ", diff = " << (total_allocated - total_freed));
|
55
|
}
|
56
|
|
57
|
void TiffAllocStat()
|
58
|
{
|
59
|
for(int i = 0; i < size_index.GetCount(); i++)
|
60
|
if(size_alloc_calls[i] != size_free_calls[i])
|
61
|
LOG("Alloc/free mismatch: size = " << size_index[i]
|
62
|
<< ", alloc = " << size_alloc_calls[i] << ", frees = " << size_free_calls[i]);
|
63
|
}
|
64
|
#endif
|
65
|
|
66
|
extern "C" tdata_t _TIFFmalloc(tsize_t s)
|
67
|
{
|
68
|
byte *p = new byte[s + 4];
|
69
|
Poke32le(p, s);
|
70
|
#if DBGALLOC
|
71
|
alloc_calls++;
|
72
|
dbgAddAlloc(p, s);
|
73
|
#endif
|
74
|
return (tdata_t)(p + 4);
|
75
|
}
|
76
|
|
77
|
extern "C" void _TIFFfree(tdata_t p)
|
78
|
{
|
79
|
if(p) {
|
80
|
byte *rawp = (byte *)p - 4;
|
81
|
#if DBGALLOC
|
82
|
free_calls++;
|
83
|
dbgAddFree(p, Peek32le(rawp));
|
84
|
#endif
|
85
|
delete[] (rawp);
|
86
|
}
|
87
|
}
|
88
|
|
89
|
extern "C" tdata_t _TIFFrealloc(tdata_t p, tsize_t s)
|
90
|
{
|
91
|
int oldsize = (p ? Peek32le((const byte *)p - 4) : 0);
|
92
|
if(s <= oldsize) {
|
93
|
Poke32le((byte *)p - 4, s);
|
94
|
return p;
|
95
|
}
|
96
|
byte *newptr = new byte[s + 4];
|
97
|
#if DBGALLOC
|
98
|
alloc_calls++;
|
99
|
dbgAddAlloc(newptr, s);
|
100
|
#endif
|
101
|
if(oldsize) {
|
102
|
memcpy(newptr + 4, p, min<int>(oldsize, s));
|
103
|
#if DBGALLOC
|
104
|
free_calls++;
|
105
|
dbgAddFree(newptr, oldsize);
|
106
|
#endif
|
107
|
delete[] ((byte *)p - 4);
|
108
|
}
|
109
|
Poke32le(newptr, s);
|
110
|
return (tdata_t)(newptr + 4);
|
111
|
}
|
112
|
|
113
|
extern "C" void _TIFFmemset(void* p, int v, tsize_t c) { memset(p, v, c); }
|
114
|
extern "C" void _TIFFmemcpy(void* d, const tdata_t s, tsize_t c) { memcpy(d, s, c); }
|
115
|
extern "C" int _TIFFmemcmp(const tdata_t p1, const tdata_t p2, tsize_t c) { return memcmp(p1, p2, c); }
|
116
|
|
117
|
static void Blt2to4(byte *dest, const byte *src, unsigned count)
|
118
|
{
|
119
|
byte b;
|
120
|
|
121
|
#define BLT2_4_4(o) \
|
122
|
b = src[(o)]; \
|
123
|
dest[2 * (o) + 0] = ((b >> 2) & 0x30) | ((b >> 4) & 0x03); \
|
124
|
dest[2 * (o) + 1] = ((b << 2) & 0x30) | (b & 0x03);
|
125
|
|
126
|
for(unsigned rep = count >> 5; rep; rep--) {
|
127
|
BLT2_4_4(0) BLT2_4_4(1) BLT2_4_4(2) BLT2_4_4(3)
|
128
|
BLT2_4_4(4) BLT2_4_4(5) BLT2_4_4(6) BLT2_4_4(7)
|
129
|
dest += 8 * 2;
|
130
|
src += 8;
|
131
|
}
|
132
|
if(count & 16) {
|
133
|
BLT2_4_4(0) BLT2_4_4(1) BLT2_4_4(2) BLT2_4_4(3)
|
134
|
dest += 4 * 2;
|
135
|
src += 4;
|
136
|
}
|
137
|
if(count & 8) {
|
138
|
BLT2_4_4(0) BLT2_4_4(1)
|
139
|
dest += 2 * 2;
|
140
|
src += 2;
|
141
|
}
|
142
|
if(count & 4) {
|
143
|
BLT2_4_4(0)
|
144
|
dest += 2;
|
145
|
src++;
|
146
|
}
|
147
|
switch(count & 3) {
|
148
|
case 0:
|
149
|
break;
|
150
|
|
151
|
case 1:
|
152
|
*dest = ((*src >> 2) & 0x30);
|
153
|
break;
|
154
|
|
155
|
case 2:
|
156
|
*dest = ((*src >> 2) & 0x30) | ((*src >> 4) & 0x03);
|
157
|
break;
|
158
|
|
159
|
case 3:
|
160
|
*dest++ = ((*src >> 2) & 0x30) | ((*src >> 4) & 0x03);
|
161
|
*dest = (*src << 2) & 0x30;
|
162
|
break;
|
163
|
}
|
164
|
}
|
165
|
|
166
|
static void BltPack11(byte *dest, const byte *src, byte bit_shift, unsigned count)
|
167
|
{
|
168
|
if(bit_shift == 0)
|
169
|
{
|
170
|
#if defined(CPU_IA32)
|
171
|
#define BLT_PACK_11_4(o) *(unsigned *)(dest + (o)) = *(const unsigned *)(src + (o));
|
172
|
#else
|
173
|
#define BLT_PACK_11_4(o) dest[(o) + 0] = src[(o) + 0]; dest[(o) + 1] = src[(o) + 1]; \
|
174
|
dest[(o) + 2] = src[(o) + 2]; dest[(o) + 3] = src[(o) + 3];
|
175
|
#endif
|
176
|
for(unsigned rep = count >> 7; rep; rep--)
|
177
|
{
|
178
|
BLT_PACK_11_4(0) BLT_PACK_11_4(4) BLT_PACK_11_4(8) BLT_PACK_11_4(12)
|
179
|
dest += 16;
|
180
|
src += 16;
|
181
|
}
|
182
|
if(count & 0x40)
|
183
|
{
|
184
|
BLT_PACK_11_4(0) BLT_PACK_11_4(4)
|
185
|
dest += 8;
|
186
|
src += 8;
|
187
|
}
|
188
|
if(count & 0x20)
|
189
|
{
|
190
|
BLT_PACK_11_4(0)
|
191
|
dest += 4;
|
192
|
src += 4;
|
193
|
}
|
194
|
if(count & 0x10)
|
195
|
{
|
196
|
dest[0] = src[0]; dest[1] = src[1];
|
197
|
dest += 2;
|
198
|
src += 2;
|
199
|
}
|
200
|
if(count & 8)
|
201
|
*dest++ = *src++;
|
202
|
switch(count & 7)
|
203
|
{
|
204
|
case 0: break;
|
205
|
case 1: *dest = (*src & 0x80) | (*dest | 0x7f); break;
|
206
|
case 2: *dest = (*src & 0xc0) | (*dest | 0x3f); break;
|
207
|
case 3: *dest = (*src & 0xe0) | (*dest | 0x1f); break;
|
208
|
case 4: *dest = (*src & 0xf0) | (*dest | 0x0f); break;
|
209
|
case 5: *dest = (*src & 0xf8) | (*dest | 0x07); break;
|
210
|
case 6: *dest = (*src & 0xfc) | (*dest | 0x03); break;
|
211
|
case 7: *dest = (*src & 0xfe) | (*dest | 0x01); break;
|
212
|
}
|
213
|
}
|
214
|
else
|
215
|
{
|
216
|
const byte shift1 = bit_shift, shift2 = 8 - bit_shift;
|
217
|
byte mask;
|
218
|
if(count + shift1 <= 8)
|
219
|
{
|
220
|
mask = ((1 << count) - 1) << (8 - count - shift1);
|
221
|
*dest = (*dest & ~mask) | ((*src >> shift1) & mask);
|
222
|
return;
|
223
|
}
|
224
|
mask = 0xff00 >> shift1;
|
225
|
*dest = (*dest & ~mask) | ((*src >> shift1) & mask);
|
226
|
dest++;
|
227
|
count -= shift2;
|
228
|
#define BLT_SHIFT_11_1(o) dest[(o)] = (src[(o)] << shift2) | (src[(o) + 1] >> shift1);
|
229
|
#define BLT_SHIFT_11_4(o) BLT_SHIFT_11_1((o)) BLT_SHIFT_11_1((o) + 1) BLT_SHIFT_11_1((o) + 2) BLT_SHIFT_11_1((o) + 3)
|
230
|
for(unsigned rep = count >> 6; rep; rep--)
|
231
|
{
|
232
|
BLT_SHIFT_11_4(0) BLT_SHIFT_11_4(4)
|
233
|
dest += 8;
|
234
|
src += 8;
|
235
|
}
|
236
|
if(count & 0x20)
|
237
|
{
|
238
|
BLT_SHIFT_11_4(0)
|
239
|
dest += 4;
|
240
|
src += 4;
|
241
|
}
|
242
|
if(count & 0x10)
|
243
|
{
|
244
|
BLT_SHIFT_11_1(0) BLT_SHIFT_11_1(1)
|
245
|
dest += 2;
|
246
|
src += 2;
|
247
|
}
|
248
|
if(count & 8)
|
249
|
{
|
250
|
BLT_SHIFT_11_1(0)
|
251
|
dest++;
|
252
|
src++;
|
253
|
}
|
254
|
if(count &= 7)
|
255
|
{
|
256
|
byte data = (count <= shift1 ? src[1] << shift2 : (src[1] << shift2) | (src[2] >> shift1));
|
257
|
mask = 0xff00 >> count;
|
258
|
*dest = (*dest & ~mask) | (data & mask);
|
259
|
}
|
260
|
}
|
261
|
}
|
262
|
|
263
|
|
264
|
|
265
|
|
266
|
static void BltPack22(byte *dest, const byte *src, byte bit_shift, unsigned count)
|
267
|
{
|
268
|
unsigned c2 = count >> 2;
|
269
|
count &= 0x03;
|
270
|
byte shift1, shift2;
|
271
|
byte sMask1, sMask2;
|
272
|
byte dMask1, dMask2;
|
273
|
|
274
|
if(!bit_shift)
|
275
|
{
|
276
|
if(c2)
|
277
|
{
|
278
|
memcpy(dest, src, c2);
|
279
|
dest += c2;
|
280
|
src += c2;
|
281
|
}
|
282
|
switch(count)
|
283
|
{
|
284
|
default:
|
285
|
case 0:
|
286
|
break;
|
287
|
|
288
|
case 1:
|
289
|
*dest = (*dest & 0x3f) | (*src & 0x3f);
|
290
|
break;
|
291
|
|
292
|
case 2:
|
293
|
*dest = (*dest & 0x0f) | (*src & 0x0f);
|
294
|
break;
|
295
|
|
296
|
case 3:
|
297
|
*dest = (*dest & 0x03) | (*src & 0x03);
|
298
|
break;
|
299
|
}
|
300
|
}
|
301
|
else
|
302
|
{
|
303
|
bit_shift <<= 1;
|
304
|
shift1 = bit_shift;
|
305
|
shift2 = (8 - bit_shift);
|
306
|
sMask1 = 0xff << shift1;
|
307
|
dMask1 = 0xff << shift2;
|
308
|
sMask2 = 0xff >> shift2;
|
309
|
dMask2 = 0xff >> shift1;
|
310
|
while(c2--)
|
311
|
{
|
312
|
*dest = (*dest & dMask1) | ((*src & sMask1) >> shift1);
|
313
|
dest++;
|
314
|
*dest = (*dest & dMask2) | ((*src & sMask2) << shift2);
|
315
|
src++;
|
316
|
}
|
317
|
switch(count)
|
318
|
{
|
319
|
case 0:
|
320
|
default:
|
321
|
break;
|
322
|
|
323
|
case 1:
|
324
|
*dest = (*dest & ~(0xc0 >> bit_shift)) | ((*src & 0xc0) >> bit_shift);
|
325
|
break;
|
326
|
|
327
|
case 2:
|
328
|
if(bit_shift <= 4)
|
329
|
{
|
330
|
*dest = (*dest & ~(0xf0 >> bit_shift)) | ((*src & 0xf0) >> bit_shift);
|
331
|
}
|
332
|
else
|
333
|
{
|
334
|
*dest = (*dest & ~(0xc0 >> bit_shift)) | ((*src & 0xc0) >> bit_shift);
|
335
|
dest++;
|
336
|
*dest = (*dest & 0x3f) | ((*src & 0x30) << 2);
|
337
|
}
|
338
|
break;
|
339
|
|
340
|
case 3:
|
341
|
if(bit_shift <= 2)
|
342
|
{
|
343
|
*dest = (*dest & ~(0xfc >> bit_shift)) | ((*src & 0xfc) >> bit_shift);
|
344
|
}
|
345
|
else if(bit_shift <= 4)
|
346
|
{
|
347
|
*dest = (*dest & ~(0xf0 >> bit_shift)) | ((*src & 0xf0) >> bit_shift);
|
348
|
dest++;
|
349
|
*dest = (*dest & 0x3f) | ((*src & 0x0c) << 4);
|
350
|
}
|
351
|
else
|
352
|
{
|
353
|
*dest = (*dest & 0xfc) | ((*src & 0xc0) >> 6);
|
354
|
dest++;
|
355
|
*dest = (*dest & 0x0f) | ((*src & 0x3c) << 2);
|
356
|
}
|
357
|
break;
|
358
|
}
|
359
|
}
|
360
|
|
361
|
}
|
362
|
|
363
|
static void BltPack44(byte *dest, const byte *src, bool shift, unsigned count)
|
364
|
{
|
365
|
|
366
|
ASSERT(count > 0);
|
367
|
if(shift)
|
368
|
{
|
369
|
byte c = *src++, d;
|
370
|
*dest = (*dest & 0xF0) | (c >> 4);
|
371
|
dest++;
|
372
|
count--;
|
373
|
while(count >= 8)
|
374
|
{
|
375
|
d = src[0]; dest[0] = (c << 4) | (d >> 4);
|
376
|
c = src[1]; dest[1] = (d << 4) | (c >> 4);
|
377
|
d = src[2]; dest[2] = (c << 4) | (d >> 4);
|
378
|
c = src[3]; dest[3] = (d << 4) | (c >> 4);
|
379
|
src += 4;
|
380
|
dest += 4;
|
381
|
count -= 8;
|
382
|
}
|
383
|
if(count & 4)
|
384
|
{
|
385
|
d = src[0]; dest[0] = (c << 4) | (d >> 4);
|
386
|
c = src[1]; dest[1] = (d << 4) | (c >> 4);
|
387
|
src += 2;
|
388
|
dest += 2;
|
389
|
}
|
390
|
if(count & 2)
|
391
|
{
|
392
|
d = src[0]; dest[0] = (c << 4) | (d >> 4);
|
393
|
c = d;
|
394
|
src++;
|
395
|
dest++;
|
396
|
}
|
397
|
if(count & 1)
|
398
|
dest[0] = (dest[0] & 15) | (c << 4);
|
399
|
}
|
400
|
else
|
401
|
{
|
402
|
unsigned c2 = count >> 1;
|
403
|
if(c2)
|
404
|
memcpy(dest, src, c2);
|
405
|
if(count & 1)
|
406
|
dest[c2] = (dest[c2] & 15) | (src[c2] & 0xF0);
|
407
|
}
|
408
|
}
|
409
|
|
410
|
static void BltPack4(byte *dest, const byte *src, unsigned count)
|
411
|
{
|
412
|
#define BLT_PACK_4_4(o) dest[(o)] = src[4 * (o)]; dest[(o) + 1] = src[4 * (o) + 4]; \
|
413
|
dest[(o) + 2] = src[4 * (o) + 8]; dest[(o) + 3] = src[4 * (o) + 12];
|
414
|
for(unsigned rep = count >> 4; rep; rep--)
|
415
|
{
|
416
|
BLT_PACK_4_4(0) BLT_PACK_4_4(4) BLT_PACK_4_4(8) BLT_PACK_4_4(12)
|
417
|
dest += 16;
|
418
|
src += 4 * 16;
|
419
|
}
|
420
|
if(count & 8)
|
421
|
{
|
422
|
BLT_PACK_4_4(0) BLT_PACK_4_4(4)
|
423
|
dest += 8;
|
424
|
src += 4 * 8;
|
425
|
}
|
426
|
if(count & 4)
|
427
|
{
|
428
|
BLT_PACK_4_4(0)
|
429
|
dest += 4;
|
430
|
src += 4 * 4;
|
431
|
}
|
432
|
if(count & 2)
|
433
|
{
|
434
|
dest[0] = src[0]; dest[1] = src[4];
|
435
|
dest += 2;
|
436
|
src += 4 * 2;
|
437
|
}
|
438
|
if(count & 1)
|
439
|
dest[0] = src[0];
|
440
|
}
|
441
|
|
442
|
static tsize_t ReadStream(thandle_t fd, tdata_t buf, tsize_t size)
|
443
|
{
|
444
|
Stream *stream = reinterpret_cast<Stream *>(fd);
|
445
|
if(!stream->IsOpen())
|
446
|
return 0;
|
447
|
|
448
|
|
449
|
return stream->Get(buf, size);
|
450
|
}
|
451
|
|
452
|
static tsize_t WriteStream(thandle_t fd, tdata_t buf, tsize_t size)
|
453
|
{
|
454
|
Stream *stream = reinterpret_cast<Stream *>(fd);
|
455
|
ASSERT(stream->IsOpen());
|
456
|
stream->Put(buf, size);
|
457
|
return stream->IsError() ? 0 : size;
|
458
|
}
|
459
|
|
460
|
static toff_t SeekStream(thandle_t fd, toff_t off, int whence)
|
461
|
{
|
462
|
Stream *stream = reinterpret_cast<Stream *>(fd);
|
463
|
ASSERT(stream->IsOpen());
|
464
|
toff_t size = (toff_t)stream->GetSize();
|
465
|
toff_t destpos = (toff_t)(off + (whence == 1 ? stream->GetPos() : whence == 2 ? size : 0));
|
466
|
stream->Seek(destpos);
|
467
|
|
468
|
return (toff_t)stream->GetPos();
|
469
|
}
|
470
|
|
471
|
static int CloseStream(thandle_t fd)
|
472
|
{
|
473
|
return 0;
|
474
|
}
|
475
|
|
476
|
static int CloseOwnedStream(thandle_t fd)
|
477
|
{
|
478
|
delete reinterpret_cast<Stream *>(fd);
|
479
|
return 0;
|
480
|
}
|
481
|
|
482
|
static toff_t SizeStream(thandle_t fd)
|
483
|
{
|
484
|
Stream *stream = reinterpret_cast<Stream *>(fd);
|
485
|
ASSERT(stream->IsOpen());
|
486
|
|
487
|
return (toff_t)stream->GetSize();
|
488
|
}
|
489
|
|
490
|
static int MapStream(thandle_t fd, tdata_t *pbase, toff_t *psize)
|
491
|
{
|
492
|
return 0;
|
493
|
}
|
494
|
|
495
|
static void UnmapStream(thandle_t fd, tdata_t base, toff_t size)
|
496
|
{
|
497
|
}
|
498
|
|
499
|
struct ::tiff *TIFFFileStreamOpen(const char *filename, const char *mode)
|
500
|
{
|
501
|
One<FileStream> fs = new FileStream;
|
502
|
int m = _TIFFgetMode(mode, "TIFFOpen");
|
503
|
dword fmode = FileStream::READ;
|
504
|
|
505
|
switch(m) {
|
506
|
case O_RDONLY: {
|
507
|
fmode = FileStream::READ;
|
508
|
break;
|
509
|
}
|
510
|
case O_RDWR: {
|
511
|
fmode = FileStream::READWRITE;
|
512
|
break;
|
513
|
}
|
514
|
case O_RDWR|O_CREAT:
|
515
|
case O_RDWR|O_TRUNC:
|
516
|
case O_RDWR|O_CREAT|O_TRUNC: {
|
517
|
fmode = FileStream::CREATE;
|
518
|
break;
|
519
|
}
|
520
|
}
|
521
|
if(!fs->Open(filename, fmode))
|
522
|
return NULL;
|
523
|
return TIFFStreamOpen(filename, mode, -fs, true);
|
524
|
}
|
525
|
|
526
|
|
527
|
|
528
|
|
529
|
|
530
|
|
531
|
|
532
|
|
533
|
|
534
|
|
535
|
|
536
|
|
537
|
struct ::tiff *TIFFStreamOpen(const char *filename, const char *mode, Stream *stream, bool destruct)
|
538
|
{
|
539
|
return TIFFClientOpen(filename, mode, reinterpret_cast<thandle_t>(stream),
|
540
|
&ReadStream, &WriteStream,
|
541
|
&SeekStream,
|
542
|
destruct ? &CloseOwnedStream : &CloseStream,
|
543
|
&SizeStream,
|
544
|
&MapStream, &UnmapStream);
|
545
|
}
|
546
|
|
547
|
|
548
|
struct TIFRaster::Data : public TIFFRGBAImage {
|
549
|
Data(Stream& stream);
|
550
|
~Data();
|
551
|
|
552
|
bool Create();
|
553
|
Raster::Info GetInfo();
|
554
|
Raster::Line GetLine(int i, Raster *owner);
|
555
|
bool SeekPage(int page);
|
556
|
bool FetchPage();
|
557
|
void CloseTmpFile();
|
558
|
|
559
|
static void Warning(const char* module, const char* fmt, va_list ap);
|
560
|
static void Error(const char* module, const char* fmt, va_list ap);
|
561
|
|
562
|
RasterFormat format;
|
563
|
|
564
|
Stream& stream;
|
565
|
TIFF *tiff;
|
566
|
|
567
|
struct Page {
|
568
|
uint32 width, height;
|
569
|
uint16 bits_per_sample;
|
570
|
uint16 samples_per_pixel;
|
571
|
uint16 photometric;
|
572
|
Size dot_size;
|
573
|
bool alpha;
|
574
|
};
|
575
|
Array<Page> pages;
|
576
|
int page_index;
|
577
|
|
578
|
byte *MapDown(int x, int y, int count, bool read);
|
579
|
byte *MapUp(int x, int y, int count, bool read);
|
580
|
void Flush();
|
581
|
void Flush(int y);
|
582
|
|
583
|
Size size;
|
584
|
int bpp;
|
585
|
int row_bytes;
|
586
|
int cache_size;
|
587
|
bool alpha;
|
588
|
bool page_open;
|
589
|
bool page_fetched;
|
590
|
bool page_error;
|
591
|
Vector<byte> imagebuf;
|
592
|
String tmpfile;
|
593
|
FileStream filebuffer;
|
594
|
struct Row {
|
595
|
Row() : x(0), size(0) {}
|
596
|
|
597
|
Buffer<byte> mapping;
|
598
|
int x, size;
|
599
|
};
|
600
|
enum { MAX_CACHE_SIZE = 50000000 };
|
601
|
RGBA palette[256];
|
602
|
int palette_count;
|
603
|
Buffer<Row> rows;
|
604
|
int64 mapping_offset;
|
605
|
int mapping_size;
|
606
|
Vector<uint32> buffer;
|
607
|
tileContigRoutine contig;
|
608
|
tileSeparateRoutine separate;
|
609
|
int skewfac;
|
610
|
|
611
|
|
612
|
|
613
|
};
|
614
|
|
615
|
extern "C" {
|
616
|
|
617
|
TIFFErrorHandler _TIFFwarningHandler = TIFRaster::Data::Warning;
|
618
|
TIFFErrorHandler _TIFFerrorHandler = TIFRaster::Data::Error;
|
619
|
|
620
|
};
|
621
|
static void packTileRGB(TIFRaster::Data *helper, uint32 x, uint32 y, uint32 w, uint32 h)
|
622
|
{
|
623
|
if(helper->alpha) {
|
624
|
int x4 = 4 * x, w4 = 4 * w;
|
625
|
|
626
|
const byte *src = (const byte *)helper->buffer.Begin();
|
627
|
|
628
|
for(; h; h--, y++) {
|
629
|
for(byte *dest = helper->MapUp(x4, y, w4, false), *end = dest + w4; dest < end; dest += 4, src += 4) {
|
630
|
dest[0] = src[2];
|
631
|
dest[1] = src[1];
|
632
|
dest[2] = src[0];
|
633
|
dest[3] = src[3];
|
634
|
}
|
635
|
}
|
636
|
}
|
637
|
else {
|
638
|
int x3 = 3 * x, w3 = 3 * w;
|
639
|
|
640
|
const byte *src = (const byte *)helper->buffer.Begin();
|
641
|
|
642
|
for(; h; h--, y++) {
|
643
|
for(byte *dest = helper->MapUp(x3, y, w3, false), *end = dest + w3; dest < end; dest += 3, src += 4) {
|
644
|
dest[0] = src[2];
|
645
|
dest[1] = src[1];
|
646
|
dest[2] = src[0];
|
647
|
}
|
648
|
}
|
649
|
}
|
650
|
}
|
651
|
|
652
|
static void putContig1(TIFFRGBAImage *img, tif_uint32 *cp,
|
653
|
tif_uint32 x, tif_uint32 y, tif_uint32 w, tif_uint32 h,
|
654
|
tif_int32 fromskew, tif_int32 toskew, byte *pp)
|
655
|
{
|
656
|
TIFRaster::Data *helper = (TIFRaster::Data *)img;
|
657
|
Size size = helper->size;
|
658
|
int iw = toskew + w;
|
659
|
bool keep_y = (iw >= 0);
|
660
|
int x8 = x >> 3;
|
661
|
int w8 = ((x + w + 7) >> 3) - x8;
|
662
|
bool read = !!((x | w) & 7) && (int)w < helper->size.cx;
|
663
|
|
664
|
|
665
|
int drow = keep_y ? 1 : -1;
|
666
|
const byte *src = pp;
|
667
|
int srow = (fromskew + w - 1) / helper->skewfac + 1;
|
668
|
for(; h; h--, y += drow , src += srow)
|
669
|
BltPack11(helper->MapUp(x8, y, w8, read), src, (byte)(x & 7), w);
|
670
|
}
|
671
|
|
672
|
static void putContig2(TIFFRGBAImage *img, tif_uint32 *cp,
|
673
|
tif_uint32 x, tif_uint32 y, tif_uint32 w, tif_uint32 h,
|
674
|
tif_int32 fromskew, tif_int32 toskew, byte *pp)
|
675
|
{
|
676
|
TIFRaster::Data *helper = (TIFRaster::Data *)img;
|
677
|
Size size = helper->size;
|
678
|
int iw = toskew + w;
|
679
|
bool keep_y = (iw >= 0);
|
680
|
int x4 = x >> 2;
|
681
|
int w4 = ((x + w + 3) >> 2) - x4;
|
682
|
bool read = !!((x | w) & 3) && (int)w < helper->size.cx;
|
683
|
|
684
|
|
685
|
int drow = keep_y ? 1 : -1;
|
686
|
const byte *src = pp;
|
687
|
int srow = (fromskew + w - 1) / helper->skewfac + 1;
|
688
|
for(; h; h--, y += drow , src += srow)
|
689
|
BltPack22(helper->MapUp(x4, y, w4, read), src, (byte)(x & 3), w);
|
690
|
}
|
691
|
|
692
|
static void putContig4(TIFFRGBAImage *img, tif_uint32 *cp,
|
693
|
tif_uint32 x, tif_uint32 y, tif_uint32 w, tif_uint32 h,
|
694
|
tif_int32 fromskew, tif_int32 toskew, byte *pp)
|
695
|
{
|
696
|
TIFRaster::Data *helper = (TIFRaster::Data *)img;
|
697
|
Size size = helper->size;
|
698
|
int iw = toskew + w;
|
699
|
bool keep_y = (iw >= 0);
|
700
|
int x2 = x >> 1;
|
701
|
int w2 = ((x + w + 1) >> 1) - x2;
|
702
|
bool read = !!((x | w) & 1) && (int)w < helper->size.cx;
|
703
|
|
704
|
bool shift = (x & 1);
|
705
|
|
706
|
int drow = (keep_y ? 1 : -1);
|
707
|
const byte *src = pp;
|
708
|
int srow = (fromskew + w - 1) / helper->skewfac + 1;
|
709
|
for(; h; h--, y += drow, src += srow)
|
710
|
BltPack44(helper->MapUp(x2, y, w2, read), src, shift, w);
|
711
|
}
|
712
|
|
713
|
static void putContig8(TIFFRGBAImage *img, tif_uint32 *cp,
|
714
|
tif_uint32 x, tif_uint32 y, tif_uint32 w, tif_uint32 h,
|
715
|
tif_int32 fromskew, tif_int32 toskew, byte *pp)
|
716
|
{
|
717
|
TIFRaster::Data *helper = (TIFRaster::Data *)img;
|
718
|
Size size = helper->size;
|
719
|
int iw = toskew + w;
|
720
|
bool keep_y = (iw >= 0);
|
721
|
|
722
|
|
723
|
int drow = (keep_y ? 1 : -1);
|
724
|
const byte *src = pp;
|
725
|
int srow = (fromskew + w - 1) / helper->skewfac + 1;
|
726
|
for(; h; h--, y += drow, src += srow)
|
727
|
memcpy(helper->MapUp(x, y, w, false), src, w);
|
728
|
}
|
729
|
|
730
|
static void putContigRGB(TIFFRGBAImage *img, tif_uint32 *cp, tif_uint32 x, tif_uint32 y, tif_uint32 w, tif_uint32 h,
|
731
|
tif_int32 fromskew, tif_int32 toskew, byte *pp)
|
732
|
{
|
733
|
TIFRaster::Data *helper = (TIFRaster::Data *)img;
|
734
|
Size size = helper->size;
|
735
|
int iw = toskew + w;
|
736
|
int wh = w * h;
|
737
|
if(wh > helper->buffer.GetCount())
|
738
|
helper->buffer.SetCount(wh);
|
739
|
bool keep_y = (iw >= 0);
|
740
|
helper->contig(img, (tif_uint32 *)(keep_y ? &helper->buffer[0] : &helper->buffer[0] + w * (h - 1)),
|
741
|
0, 0, w, h, fromskew, keep_y ? 0 : -2 * (int)w, pp);
|
742
|
packTileRGB(helper, x, keep_y ? y : y - h + 1, w, h);
|
743
|
}
|
744
|
|
745
|
static void putSeparate(TIFFRGBAImage *img, tif_uint32 *cp,
|
746
|
tif_uint32 x, tif_uint32 y, tif_uint32 w, tif_uint32 h,
|
747
|
tif_int32 fromskew, tif_int32 toskew, byte *r, byte *g, byte *b, byte *a)
|
748
|
{
|
749
|
TIFRaster::Data *helper = (TIFRaster::Data *)img;
|
750
|
Size size = helper->size;
|
751
|
int wh = w * h;
|
752
|
if(wh > helper->buffer.GetCount())
|
753
|
helper->buffer.SetCount(wh);
|
754
|
int iw = toskew + w;
|
755
|
bool keep_y = (iw >= 0);
|
756
|
helper->separate(img, (tif_uint32 *)(keep_y ? &helper->buffer[0] : &helper->buffer[0] + w * (h - 1)),
|
757
|
0, 0, w, h, fromskew, keep_y ? 0 : -2 * (int)w, r, g, b, a);
|
758
|
packTileRGB(helper, x, keep_y ? y : y - h + 1, w, h);
|
759
|
}
|
760
|
|
761
|
byte *TIFRaster::Data::MapUp(int x, int y, int count, bool read)
|
762
|
{
|
763
|
return MapDown(x, size.cy - 1 - y, count, read);
|
764
|
}
|
765
|
|
766
|
byte *TIFRaster::Data::MapDown(int x, int y, int count, bool read)
|
767
|
{
|
768
|
if(!imagebuf.IsEmpty())
|
769
|
return &imagebuf[row_bytes * y] + x;
|
770
|
else {
|
771
|
ASSERT(filebuffer.IsOpen());
|
772
|
Row& row = rows[y];
|
773
|
if(row.size >= count && row.x <= x && row.x + row.size >= x + count)
|
774
|
return &row.mapping[x - row.x];
|
775
|
if(cache_size + count >= MAX_CACHE_SIZE)
|
776
|
Flush();
|
777
|
row.mapping.Alloc(count);
|
778
|
row.x = x;
|
779
|
row.size = count;
|
780
|
cache_size += count;
|
781
|
if(read) {
|
782
|
filebuffer.Seek(row_bytes * y + x);
|
783
|
filebuffer.GetAll(row.mapping, count);
|
784
|
}
|
785
|
return row.mapping;
|
786
|
}
|
787
|
}
|
788
|
|
789
|
void TIFRaster::Data::Flush()
|
790
|
{
|
791
|
LLOG("Flush, cache size = " << cache_size);
|
792
|
for(int y = 0; y < size.cy; y++)
|
793
|
Flush(y);
|
794
|
ASSERT(cache_size == 0);
|
795
|
}
|
796
|
|
797
|
void TIFRaster::Data::Flush(int y)
|
798
|
{
|
799
|
Row& row = rows[y];
|
800
|
if(filebuffer.IsOpen() && row.size > 0) {
|
801
|
int64 fpos = row_bytes * y + row.x;
|
802
|
|
803
|
filebuffer.Seek(fpos);
|
804
|
filebuffer.Put(row.mapping, row.size);
|
805
|
cache_size -= row.size;
|
806
|
row.size = 0;
|
807
|
row.mapping.Clear();
|
808
|
}
|
809
|
}
|
810
|
|
811
|
void TIFRaster::Data::Warning(const char *fn, const char *fmt, va_list ap)
|
812
|
{
|
813
|
if(!memcmp(fn, "tiff@", 5) && IsDigit(fn[5])) {
|
814
|
int addr = stou(fn + 5);
|
815
|
if(addr != -1 && addr != 0) {
|
816
|
TIFRaster::Data& wrapper = *reinterpret_cast<TIFRaster::Data *>(addr);
|
817
|
LLOG("TIF warning: " << VFormat(fmt, ap));
|
818
|
|
819
|
}
|
820
|
}
|
821
|
}
|
822
|
|
823
|
void TIFRaster::Data::Error(const char *fn, const char *fmt, va_list ap)
|
824
|
{
|
825
|
if(!memcmp(fn, "tiff@", 5) && IsDigit(fn[5])) {
|
826
|
int addr = stou(fn + 5);
|
827
|
if(addr != -1 && addr != 0) {
|
828
|
Data& wrapper = *reinterpret_cast<Data *>(addr);
|
829
|
LLOG("TIF error: " << VFormat(fmt, ap));
|
830
|
|
831
|
}
|
832
|
}
|
833
|
}
|
834
|
|
835
|
TIFRaster::Data::Data(Stream& stream)
|
836
|
: stream(stream)
|
837
|
{
|
838
|
tiff = NULL;
|
839
|
page_index = 0;
|
840
|
cache_size = 0;
|
841
|
page_open = false;
|
842
|
page_fetched = false;
|
843
|
page_error = false;
|
844
|
}
|
845
|
|
846
|
TIFRaster::Data::~Data()
|
847
|
{
|
848
|
if(tiff) {
|
849
|
if(page_open)
|
850
|
TIFFRGBAImageEnd(this);
|
851
|
CloseTmpFile();
|
852
|
TIFFClose(tiff);
|
853
|
}
|
854
|
}
|
855
|
|
856
|
bool TIFRaster::Data::Create()
|
857
|
{
|
858
|
tiff = TIFFStreamOpen("tiff@" + Format64((intptr_t)this), "r", &stream);
|
859
|
if(!tiff)
|
860
|
return false;
|
861
|
|
862
|
int count = TIFFNumberOfDirectories(tiff);
|
863
|
if(count <= 0)
|
864
|
return false;
|
865
|
for(int i = 0; i < count; i++) {
|
866
|
Page& page = pages.Add();
|
867
|
TIFFSetDirectory(tiff, i);
|
868
|
TIFFGetField(tiff, TIFFTAG_IMAGEWIDTH, &page.width);
|
869
|
TIFFGetField(tiff, TIFFTAG_IMAGELENGTH, &page.height);
|
870
|
float xres, yres;
|
871
|
TIFFGetFieldDefaulted(tiff, TIFFTAG_XRESOLUTION, &xres);
|
872
|
TIFFGetFieldDefaulted(tiff, TIFFTAG_YRESOLUTION, &yres);
|
873
|
uint16 resunit;
|
874
|
TIFFGetFieldDefaulted(tiff, TIFFTAG_RESOLUTIONUNIT, &resunit);
|
875
|
TIFFGetFieldDefaulted(tiff, TIFFTAG_BITSPERSAMPLE, &page.bits_per_sample);
|
876
|
TIFFGetFieldDefaulted(tiff, TIFFTAG_SAMPLESPERPIXEL, &page.samples_per_pixel);
|
877
|
TIFFGetFieldDefaulted(tiff, TIFFTAG_PHOTOMETRIC, &page.photometric);
|
878
|
double dots_per_unit = (resunit == RESUNIT_INCH ? 600.0 : resunit == RESUNIT_CENTIMETER
|
879
|
? 600.0 / 2.54 : 0);
|
880
|
page.dot_size.cx = (xres ? fround(page.width * dots_per_unit / xres) : 0);
|
881
|
page.dot_size.cy = (yres ? fround(page.height * dots_per_unit / yres) : 0);
|
882
|
page.alpha = false;
|
883
|
uint16 extrasamples, *sampletypes;
|
884
|
TIFFGetFieldDefaulted(tiff, TIFFTAG_EXTRASAMPLES, &extrasamples, &sampletypes);
|
885
|
for(int e = 0; e < extrasamples; e++)
|
886
|
if(sampletypes[e] == EXTRASAMPLE_ASSOCALPHA) {
|
887
|
page.alpha = true;
|
888
|
break;
|
889
|
}
|
890
|
}
|
891
|
return SeekPage(0);
|
892
|
}
|
893
|
|
894
|
bool TIFRaster::Data::SeekPage(int pgx)
|
895
|
{
|
896
|
if(page_open) {
|
897
|
TIFFRGBAImageEnd(this);
|
898
|
page_open = false;
|
899
|
}
|
900
|
|
901
|
ASSERT(pgx >= 0 && pgx < pages.GetCount());
|
902
|
page_index = pgx;
|
903
|
page_error = false;
|
904
|
TIFFSetDirectory(tiff, page_index);
|
905
|
CloseTmpFile();
|
906
|
|
907
|
char emsg[1024];
|
908
|
if(!TIFFRGBAImageBegin(this, tiff, 0, emsg)) {
|
909
|
TIFFError(TIFFFileName(tiff), "%s", emsg);
|
910
|
page_error = true;
|
911
|
return false;
|
912
|
}
|
913
|
|
914
|
page_open = true;
|
915
|
const Page& page = pages[page_index];
|
916
|
|
917
|
size = Size(page.width, page.height);
|
918
|
if(isContig) {
|
919
|
contig = put.contig;
|
920
|
put.contig = putContigRGB;
|
921
|
}
|
922
|
else {
|
923
|
separate = put.separate;
|
924
|
put.separate = putSeparate;
|
925
|
}
|
926
|
if(alpha = pages[page_index].alpha) {
|
927
|
format.Set32le(0xFF << 16, 0xFF << 8, 0xFF, 0xFF << 24);
|
928
|
bpp = 32;
|
929
|
}
|
930
|
else {
|
931
|
format.Set24le(0xFF << 16, 0xFF << 8, 0xFF);
|
932
|
bpp = 24;
|
933
|
}
|
934
|
palette_count = 0;
|
935
|
if(isContig && (photometric == PHOTOMETRIC_PALETTE
|
936
|
|| photometric == PHOTOMETRIC_MINISWHITE || photometric == PHOTOMETRIC_MINISBLACK)
|
937
|
&& (bitspersample == 1 || bitspersample == 2 || bitspersample == 4 || bitspersample == 8)) {
|
938
|
bpp = 8;
|
939
|
tif_uint32 **ppal = (photometric == PHOTOMETRIC_PALETTE ? PALmap : BWmap);
|
940
|
ASSERT(ppal);
|
941
|
|
942
|
palette_count = 1 << min<int>(bitspersample, 8);
|
943
|
byte mask = (1 << bitspersample) - 1;
|
944
|
int part_last = 8 / bitspersample - 1;
|
945
|
int i;
|
946
|
for(i = 0; i <= mask; i++) {
|
947
|
uint32 rgba = ppal[i][part_last];
|
948
|
palette[i].r = (byte)TIFFGetR(rgba);
|
949
|
palette[i].g = (byte)TIFFGetG(rgba);
|
950
|
palette[i].b = (byte)TIFFGetB(rgba);
|
951
|
palette[i].a = 255;
|
952
|
}
|
953
|
put.contig = putContig8;
|
954
|
switch(bitspersample) {
|
955
|
case 1: bpp = 1; put.contig = putContig1; format.Set1mf(); break;
|
956
|
case 2: bpp = 2; put.contig = putContig2; format.Set2mf(); break;
|
957
|
case 4: bpp = 4; put.contig = putContig4; format.Set4mf(); break;
|
958
|
case 8: format.Set8(); break;
|
959
|
default: NEVER();
|
960
|
}
|
961
|
skewfac = 8 / bitspersample;
|
962
|
}
|
963
|
row_bytes = (bpp * width + 31) >> 5 << 2;
|
964
|
|
965
|
page_fetched = false;
|
966
|
return true;
|
967
|
}
|
968
|
|
969
|
void TIFRaster::Data::CloseTmpFile()
|
970
|
{
|
971
|
if(filebuffer.IsOpen()) {
|
972
|
filebuffer.Close();
|
973
|
FileDelete(tmpfile);
|
974
|
}
|
975
|
tmpfile = Null;
|
976
|
}
|
977
|
|
978
|
bool TIFRaster::Data::FetchPage()
|
979
|
{
|
980
|
if(page_error)
|
981
|
return false;
|
982
|
if(page_fetched)
|
983
|
return true;
|
984
|
|
985
|
cache_size = 0;
|
986
|
rows.Clear();
|
987
|
int64 bytes = row_bytes * (int64)height;
|
988
|
if(bytes >= 1 << 28) {
|
989
|
tmpfile = GetTempFileName();
|
990
|
if(!filebuffer.Open(tmpfile, FileStream::CREATE)) {
|
991
|
page_error = true;
|
992
|
return false;
|
993
|
}
|
994
|
filebuffer.SetSize(bytes);
|
995
|
if(filebuffer.IsError()) {
|
996
|
filebuffer.Close();
|
997
|
FileDelete(tmpfile);
|
998
|
page_error = true;
|
999
|
return false;
|
1000
|
}
|
1001
|
rows.Alloc(size.cy);
|
1002
|
}
|
1003
|
else
|
1004
|
imagebuf.SetCount(size.cy * row_bytes, 0);
|
1005
|
|
1006
|
|
1007
|
|
1008
|
bool res = TIFFRGBAImageGet(this, 0, width, height);
|
1009
|
TIFFRGBAImageEnd(this);
|
1010
|
page_open = false;
|
1011
|
|
1012
|
if(filebuffer.IsOpen()) {
|
1013
|
Flush();
|
1014
|
if(filebuffer.IsError() || !res) {
|
1015
|
filebuffer.Close();
|
1016
|
FileDelete(tmpfile);
|
1017
|
page_error = true;
|
1018
|
return false;
|
1019
|
}
|
1020
|
|
1021
|
|
1022
|
|
1023
|
|
1024
|
|
1025
|
}
|
1026
|
|
1027
|
|
1028
|
|
1029
|
|
1030
|
page_fetched = true;
|
1031
|
return true;
|
1032
|
}
|
1033
|
|
1034
|
Raster::Info TIFRaster::Data::GetInfo()
|
1035
|
{
|
1036
|
const Page& page = pages[page_index];
|
1037
|
Raster::Info out;
|
1038
|
out.kind = (page.alpha ? IMAGE_ALPHA : IMAGE_OPAQUE);
|
1039
|
out.bpp = bpp;
|
1040
|
out.colors = 0;
|
1041
|
out.dots = page.dot_size;
|
1042
|
out.hotspot = Null;
|
1043
|
return out;
|
1044
|
}
|
1045
|
|
1046
|
Raster::Line TIFRaster::Data::GetLine(int line, Raster *raster)
|
1047
|
{
|
1048
|
if(!page_error && !page_fetched)
|
1049
|
FetchPage();
|
1050
|
if(page_error) {
|
1051
|
byte *tmp = new byte[row_bytes];
|
1052
|
memset(tmp, 0, row_bytes);
|
1053
|
return Raster::Line(tmp, raster, true);
|
1054
|
}
|
1055
|
if(!imagebuf.IsEmpty())
|
1056
|
return Raster::Line(&imagebuf[row_bytes * line], raster, false);
|
1057
|
const byte *data = MapDown(0, line, row_bytes, raster);
|
1058
|
byte *tmp = new byte[row_bytes];
|
1059
|
memcpy(tmp, data, row_bytes);
|
1060
|
return Raster::Line(tmp, raster, true);
|
1061
|
}
|
1062
|
|
1063
|
TIFRaster::TIFRaster()
|
1064
|
{
|
1065
|
}
|
1066
|
|
1067
|
TIFRaster::~TIFRaster()
|
1068
|
{
|
1069
|
}
|
1070
|
|
1071
|
bool TIFRaster::Create()
|
1072
|
{
|
1073
|
data = new Data(GetStream());
|
1074
|
return data->Create();
|
1075
|
}
|
1076
|
|
1077
|
Size TIFRaster::GetSize()
|
1078
|
{
|
1079
|
return data->size;
|
1080
|
}
|
1081
|
|
1082
|
Raster::Info TIFRaster::GetInfo()
|
1083
|
{
|
1084
|
return data->GetInfo();
|
1085
|
}
|
1086
|
|
1087
|
Raster::Line TIFRaster::GetLine(int line)
|
1088
|
{
|
1089
|
return data->GetLine(line, this);
|
1090
|
}
|
1091
|
|
1092
|
int TIFRaster::GetPaletteCount()
|
1093
|
{
|
1094
|
return data->palette_count;
|
1095
|
}
|
1096
|
|
1097
|
const RGBA *TIFRaster::GetPalette()
|
1098
|
{
|
1099
|
return data->palette;
|
1100
|
}
|
1101
|
|
1102
|
const RasterFormat *TIFRaster::GetFormat()
|
1103
|
{
|
1104
|
return &data->format;
|
1105
|
}
|
1106
|
|
1107
|
int TIFRaster::GetPageCount()
|
1108
|
{
|
1109
|
return data->pages.GetCount();
|
1110
|
}
|
1111
|
|
1112
|
int TIFRaster::GetActivePage() const
|
1113
|
{
|
1114
|
return data->page_index;
|
1115
|
}
|
1116
|
|
1117
|
void TIFRaster::SeekPage(int n)
|
1118
|
{
|
1119
|
data->SeekPage(n);
|
1120
|
}
|
1121
|
|
1122
|
class TIFEncoder::Data {
|
1123
|
public:
|
1124
|
Data(Stream& stream, RasterFormat& format);
|
1125
|
~Data();
|
1126
|
|
1127
|
void Start(Size size, Size dots, int bpp, const RGBA *palette);
|
1128
|
void WriteLineRaw(const byte *line);
|
1129
|
|
1130
|
private:
|
1131
|
Stream& stream;
|
1132
|
TIFF *tiff;
|
1133
|
Size size;
|
1134
|
int bpp;
|
1135
|
const RGBA *palette;
|
1136
|
Vector<byte> rowbuf;
|
1137
|
int linebytes;
|
1138
|
RasterFormat& format;
|
1139
|
int line;
|
1140
|
|
1141
|
static tsize_t ReadStream(thandle_t fd, tdata_t buf, tsize_t size);
|
1142
|
static tsize_t WriteStream(thandle_t fd, tdata_t buf, tsize_t size);
|
1143
|
static toff_t SeekStream(thandle_t fd, toff_t off, int whence);
|
1144
|
static int CloseStream(thandle_t fd);
|
1145
|
static toff_t SizeStream(thandle_t fd);
|
1146
|
static int MapStream(thandle_t fd, tdata_t *pbase, toff_t *psize);
|
1147
|
static void UnmapStream(thandle_t fd, tdata_t base, toff_t size);
|
1148
|
};
|
1149
|
|
1150
|
TIFEncoder::Data::Data(Stream& stream, RasterFormat& format)
|
1151
|
: stream(stream), format(format)
|
1152
|
{
|
1153
|
tiff = NULL;
|
1154
|
}
|
1155
|
|
1156
|
TIFEncoder::Data::~Data()
|
1157
|
{
|
1158
|
if(tiff) TIFFClose(tiff);
|
1159
|
}
|
1160
|
|
1161
|
tsize_t TIFEncoder::Data::ReadStream(thandle_t fd, tdata_t buf, tsize_t size)
|
1162
|
{
|
1163
|
Data& wrapper = *reinterpret_cast<Data *>(fd);
|
1164
|
ASSERT(wrapper.stream.IsOpen());
|
1165
|
|
1166
|
|
1167
|
return wrapper.stream.Get(buf, size);
|
1168
|
return 0;
|
1169
|
}
|
1170
|
|
1171
|
tsize_t TIFEncoder::Data::WriteStream(thandle_t fd, tdata_t buf, tsize_t size)
|
1172
|
{
|
1173
|
Data& wrapper = *reinterpret_cast<Data *>(fd);
|
1174
|
ASSERT(wrapper.stream.IsOpen());
|
1175
|
|
1176
|
|
1177
|
wrapper.stream.Put(buf, size);
|
1178
|
return size;
|
1179
|
}
|
1180
|
|
1181
|
toff_t TIFEncoder::Data::SeekStream(thandle_t fd, toff_t off, int whence)
|
1182
|
{
|
1183
|
Data& wrapper = *reinterpret_cast<Data *>(fd);
|
1184
|
ASSERT(wrapper.stream.IsOpen());
|
1185
|
toff_t size = (toff_t)wrapper.stream.GetSize();
|
1186
|
toff_t destpos = (toff_t)(off + (whence == 1 ? wrapper.stream.GetPos() : whence == 2 ? size : 0));
|
1187
|
if(destpos > size) {
|
1188
|
wrapper.stream.Seek(size);
|
1189
|
wrapper.stream.Put((int)0, (int)(destpos - size));
|
1190
|
}
|
1191
|
else
|
1192
|
wrapper.stream.Seek(destpos);
|
1193
|
|
1194
|
return (toff_t)wrapper.stream.GetPos();
|
1195
|
}
|
1196
|
|
1197
|
int TIFEncoder::Data::CloseStream(thandle_t fd)
|
1198
|
{
|
1199
|
return 0;
|
1200
|
}
|
1201
|
|
1202
|
toff_t TIFEncoder::Data::SizeStream(thandle_t fd)
|
1203
|
{
|
1204
|
Data& wrapper = *reinterpret_cast<Data *>(fd);
|
1205
|
ASSERT(wrapper.stream.IsOpen());
|
1206
|
|
1207
|
return (toff_t)wrapper.stream.GetSize();
|
1208
|
}
|
1209
|
|
1210
|
int TIFEncoder::Data::MapStream(thandle_t fd, tdata_t *pbase, toff_t *psize)
|
1211
|
{
|
1212
|
return 0;
|
1213
|
}
|
1214
|
|
1215
|
void TIFEncoder::Data::UnmapStream(thandle_t fd, tdata_t base, toff_t size)
|
1216
|
{
|
1217
|
}
|
1218
|
|
1219
|
void TIFEncoder::Data::Start(Size sz, Size dots, int bpp_, const RGBA *palette)
|
1220
|
{
|
1221
|
size = sz;
|
1222
|
bpp = bpp_;
|
1223
|
line = 0;
|
1224
|
|
1225
|
tiff = TIFFClientOpen("tiff@" + Format64((intptr_t)this), "w", reinterpret_cast<thandle_t>(this),
|
1226
|
ReadStream, WriteStream, SeekStream, CloseStream, SizeStream, MapStream, UnmapStream);
|
1227
|
|
1228
|
TIFFSetField(tiff, TIFFTAG_IMAGEWIDTH, size.cx);
|
1229
|
TIFFSetField(tiff, TIFFTAG_IMAGELENGTH, size.cy);
|
1230
|
TIFFSetField(tiff, TIFFTAG_BITSPERSAMPLE, min<int>(bpp, 8));
|
1231
|
TIFFSetField(tiff, TIFFTAG_COMPRESSION, COMPRESSION_LZW);
|
1232
|
TIFFSetField(tiff, TIFFTAG_PHOTOMETRIC, bpp <= 8 ? PHOTOMETRIC_PALETTE : PHOTOMETRIC_RGB);
|
1233
|
TIFFSetField(tiff, TIFFTAG_SAMPLESPERPIXEL, bpp <= 8 ? 1 : bpp != 32 ? 3 : 4);
|
1234
|
TIFFSetField(tiff, TIFFTAG_ROWSPERSTRIP, 1);
|
1235
|
TIFFSetField(tiff, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
|
1236
|
if(bpp == 32) {
|
1237
|
uint16 es = EXTRASAMPLE_ASSOCALPHA;
|
1238
|
TIFFSetField(tiff, TIFFTAG_EXTRASAMPLES, 1, &es);
|
1239
|
}
|
1240
|
|
1241
|
|
1242
|
if (dots.cx && dots.cy) {
|
1243
|
TIFFSetField(tiff, TIFFTAG_RESOLUTIONUNIT, (uint16)RESUNIT_INCH);
|
1244
|
float xres = float(sz.cx * 600.0 / dots.cx);
|
1245
|
TIFFSetField(tiff, TIFFTAG_XRESOLUTION, xres);
|
1246
|
float yres = float(sz.cy * 600.0 / dots.cy);
|
1247
|
TIFFSetField(tiff, TIFFTAG_YRESOLUTION, yres);
|
1248
|
}
|
1249
|
switch(bpp) {
|
1250
|
case 1: format.Set1mf(); break;
|
1251
|
case 2: format.Set2mf(); break;
|
1252
|
case 4: format.Set4mf(); break;
|
1253
|
case 8: format.Set8(); break;
|
1254
|
default: NEVER();
|
1255
|
case 24: format.Set24le(0xFF, 0xFF << 8, 0xFF << 16); break;
|
1256
|
case 32: format.Set32le(0xFF, 0xFF << 8, 0xFF << 16, 0xFF << 24); break;
|
1257
|
}
|
1258
|
if(bpp <= 8) {
|
1259
|
uint16 rpal[256], gpal[256], bpal[256];
|
1260
|
int c = 1 << bpp;
|
1261
|
memset(rpal, 0, sizeof(uint16) * c);
|
1262
|
memset(gpal, 0, sizeof(uint16) * c);
|
1263
|
memset(bpal, 0, sizeof(uint16) * c);
|
1264
|
for(int i = 0; i < c; i++) {
|
1265
|
rpal[i] = palette[i].r << 8;
|
1266
|
gpal[i] = palette[i].g << 8;
|
1267
|
bpal[i] = palette[i].b << 8;
|
1268
|
}
|
1269
|
TIFFSetField(tiff, TIFFTAG_COLORMAP, rpal, gpal, bpal);
|
1270
|
}
|
1271
|
int rowbytes = (bpp * size.cx + 31) >> 5 << 2;
|
1272
|
rowbuf.SetCount(rowbytes);
|
1273
|
linebytes = format.GetByteCount(size.cx);
|
1274
|
}
|
1275
|
|
1276
|
void TIFEncoder::Data::WriteLineRaw(const byte *s)
|
1277
|
{
|
1278
|
memcpy(rowbuf.Begin(), s, linebytes);
|
1279
|
TIFFWriteScanline(tiff, rowbuf.Begin(), line, 0);
|
1280
|
if(++line >= size.cy) {
|
1281
|
TIFFClose(tiff);
|
1282
|
tiff = NULL;
|
1283
|
}
|
1284
|
}
|
1285
|
|
1286
|
TIFEncoder::TIFEncoder(int bpp)
|
1287
|
: bpp(bpp)
|
1288
|
{
|
1289
|
}
|
1290
|
|
1291
|
TIFEncoder::~TIFEncoder()
|
1292
|
{
|
1293
|
}
|
1294
|
|
1295
|
int TIFEncoder::GetPaletteCount()
|
1296
|
{
|
1297
|
return (bpp > 8 ? 0 : 1 << bpp);
|
1298
|
}
|
1299
|
|
1300
|
void TIFEncoder::Start(Size sz)
|
1301
|
{
|
1302
|
data = new Data(GetStream(), format);
|
1303
|
data->Start(sz, GetDots(), bpp, bpp <= 8 ? GetPalette() : NULL);
|
1304
|
}
|
1305
|
|
1306
|
void TIFEncoder::WriteLineRaw(const byte *s)
|
1307
|
{
|
1308
|
data->WriteLineRaw(s);
|
1309
|
}
|
1310
|
|
1311
|
END_UPP_NAMESPACE
|