summaryrefslogtreecommitdiff
path: root/tiff.c
blob: 65ec6e0eb0b99b2f04db2a841c7dc14a58a4847b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
/* tiff.c
 * TIFF image decoding
 * (c) 2002 Petr 'Brain' Kulhavy
 * This file is a part of the Links program, released under GPL.
 *
 * Compiles in graphics mode only and only when HAVE_TIFF.
 */
#include "cfg.h"

#ifdef G
#include "links.h"

#ifdef HAVE_TIFF
#include <tiffio.h>
#include "bits.h"

void tiff_start(struct cached_image *cimg)
{
	struct tiff_decoder * deco;

	deco=mem_alloc(sizeof(struct tiff_decoder));

	cimg->decoder=deco;
	deco->tiff_size=0;
	deco->tiff_data=NULL;
	deco->tiff_open=0;
	deco->tiff_pos=0;
}


void tiff_restart(struct cached_image *cimg, unsigned char *data, int length)
{
	struct tiff_decoder * deco=(struct tiff_decoder*)cimg->decoder;
	unsigned char *p;

	if (!deco->tiff_data) {
		if ((unsigned)length > MAXINT) overalloc();
		p=mem_alloc(length);
	} else {
		if ((unsigned)length + (unsigned)deco->tiff_size > MAXINT) overalloc();
		if ((unsigned)length + (unsigned)deco->tiff_size < (unsigned)length) overalloc();
		p=mem_realloc(deco->tiff_data,deco->tiff_size+length);
	}
	deco->tiff_data=p;
	memcpy(deco->tiff_data+deco->tiff_size,data,length);
	deco->tiff_size+=length;
}

static toff_t tiff_size(thandle_t data)
{
	struct cached_image *cimg=(struct cached_image *)data;
	struct tiff_decoder *deco=(struct tiff_decoder*)cimg->decoder;

	if (!deco->tiff_open)internal("BUG IN LIBTIFF: sizeproc called on closed file. Contact the libtiff authors.\n");

	return deco->tiff_size;
}


static tsize_t tiff_read(thandle_t data, tdata_t dest, tsize_t count)
{
	struct cached_image *cimg=(struct cached_image *)data;
	struct tiff_decoder *deco=(struct tiff_decoder*)cimg->decoder;

	if (!deco->tiff_open)internal("BUG IN LIBTIFF: readproc called on closed file. Contact the libtiff authors.\n");

	if (count < 0)
		return 0;

	if (count > deco->tiff_size-deco->tiff_pos)
		count = deco->tiff_size-deco->tiff_pos;
	memcpy(dest,deco->tiff_data+deco->tiff_pos,count);
	deco->tiff_pos+=count;
	return count;
}


static tsize_t tiff_write(thandle_t data, tdata_t dest, tsize_t count)
{
	internal("BUG IN LIBTIFF: writeproc called on read-only file. Contact the libtiff authors.\n");
	return 0;
}


static toff_t tiff_seek(thandle_t data, toff_t offset, int whence)
{
	struct cached_image *cimg=(struct cached_image *)data;
	struct tiff_decoder *deco=(struct tiff_decoder*)cimg->decoder;
	long pos;

	if (!deco->tiff_open)internal("BUG IN LIBTIFF: seekproc called on closed file. Contact the libtiff authors.\n");

	switch(whence)
	{
		case SEEK_SET:
			pos = offset;
			break;
		case SEEK_CUR:
			pos = (unsigned long)deco->tiff_pos + offset;
			break;
		case SEEK_END:
			pos = (unsigned long)deco->tiff_size + offset;
			break;
		default:
			pos = deco->tiff_pos;
			break;
	}
	if (pos > deco->tiff_size) pos = deco->tiff_size;
	if (pos < 0) pos = 0;
	deco->tiff_pos = pos;
	return deco->tiff_pos;
}


static int tiff_close(void *data)
{
	struct cached_image *cimg=(struct cached_image *)data;
	struct tiff_decoder *deco=(struct tiff_decoder*)cimg->decoder;

	if (!deco->tiff_open)internal("BUG IN LIBTIFF: closeproc called on closed file. Contact the libtiff authors.\n");
	if (deco->tiff_data)mem_free(deco->tiff_data),deco->tiff_data=NULL;
	deco->tiff_open=0;
	return 0;
}


static int tiff_mmap(thandle_t data, tdata_t *dest, toff_t *len)
{
	struct cached_image *cimg=(struct cached_image *)data;
	struct tiff_decoder *deco=(struct tiff_decoder*)cimg->decoder;

	if (!deco->tiff_open)internal("BUG IN LIBTIFF: mapproc called on closed file. Contact the libtiff authors.\n");
	*dest=deco->tiff_data;
	*len=deco->tiff_size;
	return 0;
}


static void tiff_munmap(thandle_t data, tdata_t dest, toff_t len)
{
	struct cached_image *cimg=(struct cached_image *)data;
	struct tiff_decoder *deco=(struct tiff_decoder*)cimg->decoder;

	if (!deco->tiff_open)internal("BUG IN LIBTIFF: unmapproc called on closed file. Contact the libtiff authors.\n");
}


static void tiff_error_handler(const char* module, const char* fmt, va_list ap)
{
}

static void flip_buffer(void *buf,int width,int height)
{
	if (htonl(0x12345678L)!=0x12345678L)	/* little endian --- ja to chci na intelu rychly!!! */
	{
#ifdef t4c
		t4c* buffer=(t4c*)buf;
		register t4c a,b;
		t4c *p,*q;
		int i,l;

		for (l=0,p=buffer,q=buffer+width*(height-1);l<(height>>1);l++,q-=(width<<1))
			for (i=0;i<width;a=*p,b=*q,*p++=b,*q++=a,i++)
				;
#else
		unsigned char* buffer=(unsigned char*)buf;
		unsigned char *p,*q;
		int l;
		unsigned char *tmp;
		int w=4*width;

		if ((unsigned)w > MAXINT) overalloc();
		tmp=mem_alloc(w*sizeof(unsigned char));

		/* tohle je pomalejsi, protoze se kopiruje pamet->pamet, pamet->pamet */
		/* kdyz mame 4B typek, tak se kopiruje pamet->reg, reg->pamet */
		for (l=0,p=buffer,q=buffer+w*(height-1);l<(height>>1);l++,q-=w,p+=w)
			memcpy(tmp,p,w),memcpy(p,q,w),memcpy(q,tmp,w);
		mem_free(tmp);
#endif
	}
	else	/* big endian */
	{
		unsigned char zakazany_uvolneni[4];
		unsigned char* buffer=(unsigned char*)buf;
		int w=width<<2; /* 4 bytes per pixel */
		unsigned char *p,*q;
		int i,l;

		for (l=0,p=buffer,q=buffer+w*(height-1);l<(height>>1);l++,q-=(w<<1))
			for (i=0;i<width;i++,p+=4,q+=4)
			{
				memcpy(zakazany_uvolneni,p,4);
				p[0]=q[3];
				p[1]=q[2];
				p[2]=q[1];
				p[3]=q[0];
				q[0]=zakazany_uvolneni[3];
				q[1]=zakazany_uvolneni[2];
				q[2]=zakazany_uvolneni[1];
				q[3]=zakazany_uvolneni[0];
			}
		if (height&1) /* flip endianity of line in the middle (if the height is odd) */
			for (i=0;i<width;i++,p+=4)
			{
				memcpy(zakazany_uvolneni,p,4);
				p[0]=zakazany_uvolneni[3];
				p[1]=zakazany_uvolneni[2];
				p[2]=zakazany_uvolneni[1];
				p[3]=zakazany_uvolneni[0];
			}
	}
}

void tiff_finish(struct cached_image *cimg)
{
	struct tiff_decoder *deco=(struct tiff_decoder*)cimg->decoder;
	int bla;
	TIFF *t;

	if (!deco->tiff_size){img_end(cimg);return;}
	deco->tiff_open=1;
	TIFFSetErrorHandler(tiff_error_handler);
	TIFFSetWarningHandler(tiff_error_handler);
	t=TIFFClientOpen(
			"Prave si rek' svy posledni slova. A vybral sis k tomu prihodny misto.",
			"r",
			cimg,
			(TIFFReadWriteProc)tiff_read,
			(TIFFReadWriteProc)tiff_write,
			(TIFFSeekProc)tiff_seek,
			(TIFFCloseProc)tiff_close,
			(TIFFSizeProc)tiff_size,
			(TIFFMapFileProc)tiff_mmap,
			(TIFFUnmapFileProc)tiff_munmap
		);
	if (!t){img_end(cimg);return;}
	bla=TIFFGetField(t, TIFFTAG_IMAGEWIDTH, &(cimg->width));
	if (!bla){TIFFClose(t);img_end(cimg);return;}
	bla=TIFFGetField(t, TIFFTAG_IMAGELENGTH, &(cimg->height));
	if (!bla){TIFFClose(t);img_end(cimg);return;}
	cimg->buffer_bytes_per_pixel=4;
	cimg->red_gamma=cimg->green_gamma=cimg->blue_gamma=sRGB_gamma;
	cimg->strip_optimized=0;
	if (header_dimensions_known(cimg)){TIFFClose(t);img_end(cimg);return;}
/* int TIFFReadRGBAImage(TIFF* tif, u_long width, u_long height, u_long* raster, int stopOnError) from man page */
	/*TIFFReadRGBAImage(t,cimg->width,cimg->height,(unsigned long*)(cimg->buffer),1);*/ /* 231: warning: passing arg 4 of `TIFFReadRGBAImage' from incompatible pointer type */
	TIFFReadRGBAImage(t,cimg->width,cimg->height,(void*)(cimg->buffer),1);
	TIFFClose(t);

	/* For some reason the TIFFReadRGBAImage() function chooses the lower
	 * left corner as the origin.  Vertically mirror scanlines. 
	 */
	flip_buffer((void*)(cimg->buffer),cimg->width,cimg->height);

	img_end(cimg);
}

void add_tiff_version(unsigned char **s, int *l)
{
	unsigned char *p, *pp;
	int pl;
	add_to_str(s, l, "TIFF (");
	p = (unsigned char *)TIFFGetVersion();
	pp = strstr(p, "LIBTIFF, ");
	if (pp) p = pp + 9;
	pp = strstr(p, "Version ");
	if (pp) p = pp + 8;
	pl = strcspn(p, " \n");
	add_bytes_to_str(s, l, p, pl);
	add_to_str(s, l, ")");
}

#endif /* #ifdef HAVE_TIFF */

#endif /* #ifdef G */