- add smoke test for nearest_color filter
[imager.git] / img16.c
CommitLineData
faa9b3e7
TC
1/*
2=head1 NAME
3
4img16.c - implements 16-bit images
5
6=head1 SYNOPSIS
7
8 i_img *im = i_img_16_new(int x, int y, int channels);
9 # use like a normal image
10
11=head1 DESCRIPTION
12
13Implements 16-bit/sample images.
14
15This basic implementation is required so that we have some larger
16sample image type to work with.
17
18=over
19
20=cut
21*/
22
23#include "image.h"
24#include "imagei.h"
25
26static int i_ppix_d16(i_img *im, int x, int y, i_color *val);
27static int i_gpix_d16(i_img *im, int x, int y, i_color *val);
28static int i_glin_d16(i_img *im, int l, int r, int y, i_color *vals);
29static int i_plin_d16(i_img *im, int l, int r, int y, i_color *vals);
30static int i_ppixf_d16(i_img *im, int x, int y, i_fcolor *val);
31static int i_gpixf_d16(i_img *im, int x, int y, i_fcolor *val);
32static int i_glinf_d16(i_img *im, int l, int r, int y, i_fcolor *vals);
33static int i_plinf_d16(i_img *im, int l, int r, int y, i_fcolor *vals);
34static int i_gsamp_d16(i_img *im, int l, int r, int y, i_sample_t *samps,
18accb2a 35 int const *chans, int chan_count);
faa9b3e7 36static int i_gsampf_d16(i_img *im, int l, int r, int y, i_fsample_t *samps,
18accb2a 37 int const *chans, int chan_count);
faa9b3e7
TC
38
39/*
40=item IIM_base_16bit_direct
41
42Base structure used to initialize a 16-bit/sample image.
43
44Internal.
45
46=cut
47*/
48static i_img IIM_base_16bit_direct =
49{
50 0, /* channels set */
51 0, 0, 0, /* xsize, ysize, bytes */
9a88a5e6 52 ~0U, /* ch_mask */
faa9b3e7
TC
53 i_16_bits, /* bits */
54 i_direct_type, /* type */
55 0, /* virtual */
56 NULL, /* idata */
57 { 0, 0, NULL }, /* tags */
58 NULL, /* ext_data */
59
60 i_ppix_d16, /* i_f_ppix */
61 i_ppixf_d16, /* i_f_ppixf */
62 i_plin_d16, /* i_f_plin */
63 i_plinf_d16, /* i_f_plinf */
64 i_gpix_d16, /* i_f_gpix */
65 i_gpixf_d16, /* i_f_gpixf */
66 i_glin_d16, /* i_f_glin */
67 i_glinf_d16, /* i_f_glinf */
68 i_gsamp_d16, /* i_f_gsamp */
69 i_gsampf_d16, /* i_f_gsampf */
70
71 NULL, /* i_f_gpal */
72 NULL, /* i_f_ppal */
73 NULL, /* i_f_addcolor */
74 NULL, /* i_f_getcolor */
75 NULL, /* i_f_colorcount */
76 NULL, /* i_f_findcolor */
77
78 NULL, /* i_f_destroy */
79};
80
81/* it's possible some platforms won't have a 16-bit integer type,
82 so we check for one otherwise we work by bytes directly
83
84 We do assume 8-bit char
26fd367b
TC
85
86 "Compaq C V6.4-009 on Compaq Tru64 UNIX V5.1A (Rev. 1885)" says it
87 supports C99, but doesn't supply stdint.h, which is required for
88 both hosted and freestanding implementations. So guard against it.
faa9b3e7 89*/
26fd367b 90#if __STDC_VERSION__ >= 199901L && !defined(OS_dec_osf)
faa9b3e7
TC
91/* C99 should define something useful */
92#include <stdint.h>
93#ifdef UINT16_MAX
94typedef uint16_t i_sample16_t;
95#define GOT16
96#endif
97#endif
98
99/* check out unsigned short */
100#ifndef GOT16
101#include <limits.h>
102#if USHRT_MAX == 65535
103typedef unsigned short i_sample16_t;
104#define GOT16
105#endif
106#endif
107
108#ifdef GOT16
109
110/* we have a real 16-bit unsigned integer */
111#define STORE16(bytes, offset, word) \
112 (((i_sample16_t *)(bytes))[offset] = (word))
113#define STORE8as16(bytes, offset, byte) \
114 (((i_sample16_t *)(bytes))[offset] = (byte) * 256)
115#define GET16(bytes, offset) \
116 (((i_sample16_t *)(bytes))[offset])
117#define GET16as8(bytes, offset) \
118 (((i_sample16_t *)(bytes))[offset] / 256)
119
120#else
121
122/* we have to do this the hard way */
123#define STORE16(bytes, offset, word) \
124 ((((unsigned char *)(bytes))[(offset)*2] = (word) >> 8), \
125 (((unsigned char *)(bytes))[(offset)*2+1] = (word) & 0xFF))
126#define STORE8as16(bytes, offset, byte) \
127 ((((unsigned char *)(bytes))[(offset)*2] = (byte)), \
128 (((unsigned char *)(bytes))[(offset)*2+1] = 0))
129
130#define GET16(bytes, offset) \
131 (((unsigned char *)(bytes))[(offset)*2] * 256 \
132 + ((unsigned char *)(bytes))[(offset)*2+1])
133#define GET16as8(bytes, offset) \
134 (((unsigned char *)(bytes))[(offset)*2] << 8)
135
136#endif
137
138/*
139=item i_img_16_new(int x, int y, int ch)
140
141Creates a new 16-bit per sample image.
365ea842
TC
142
143=cut
faa9b3e7
TC
144*/
145i_img *i_img_16_new_low(i_img *im, int x, int y, int ch) {
653ea321 146 int bytes;
faa9b3e7 147 mm_log((1,"i_img_16_new(x %d, y %d, ch %d)\n", x, y, ch));
1501d9b3
TC
148
149 if (x < 1 || y < 1) {
150 i_push_error(0, "Image sizes must be positive");
151 return NULL;
152 }
153 if (ch < 1 || ch > MAXCHANNELS) {
154 i_push_errorf(0, "channels must be between 1 and %d", MAXCHANNELS);
155 return NULL;
156 }
653ea321
TC
157 bytes = x * y * ch * 2;
158 if (bytes / y / ch / 2 != x) {
159 i_push_errorf(0, "integer overflow calculating image allocation");
160 return NULL;
161 }
faa9b3e7
TC
162
163 *im = IIM_base_16bit_direct;
164 i_tags_new(&im->tags);
165 im->xsize = x;
166 im->ysize = y;
167 im->channels = ch;
653ea321 168 im->bytes = bytes;
faa9b3e7
TC
169 im->ext_data = NULL;
170 im->idata = mymalloc(im->bytes);
171 if (im->idata) {
172 memset(im->idata, 0, im->bytes);
173 }
174 else {
175 i_tags_destroy(&im->tags);
176 im = NULL;
177 }
178
179 return im;
180}
181
182i_img *i_img_16_new(int x, int y, int ch) {
183 i_img *im;
1501d9b3
TC
184
185 i_clear_error();
faa9b3e7
TC
186
187 im = mymalloc(sizeof(i_img));
188 if (im) {
189 if (!i_img_16_new_low(im, x, y, ch)) {
190 myfree(im);
191 im = NULL;
192 }
193 }
194
195 mm_log((1, "(%p) <- i_img_16_new\n", im));
196
197 return im;
198}
199
200static int i_ppix_d16(i_img *im, int x, int y, i_color *val) {
201 int off, ch;
202
203 if (x < 0 || x >= im->xsize || y < 0 || y > im->ysize)
204 return -1;
205
206 off = (x + y * im->xsize) * im->channels;
9b8ce4f4
TC
207 if (I_ALL_CHANNELS_WRITABLE(im)) {
208 for (ch = 0; ch < im->channels; ++ch)
209 STORE8as16(im->idata, off+ch, val->channel[ch]);
210 }
211 else {
212 for (ch = 0; ch < im->channels; ++ch)
213 if (im->ch_mask & (1 << ch))
214 STORE8as16(im->idata, off+ch, val->channel[ch]);
215 }
faa9b3e7
TC
216
217 return 0;
218}
219
220static int i_gpix_d16(i_img *im, int x, int y, i_color *val) {
221 int off, ch;
222
223 if (x < 0 || x >= im->xsize || y < 0 || y > im->ysize)
224 return -1;
225
226 off = (x + y * im->xsize) * im->channels;
227 for (ch = 0; ch < im->channels; ++ch)
228 val->channel[ch] = GET16as8(im->idata, off+ch);
229
230 return 0;
231}
232
233static int i_ppixf_d16(i_img *im, int x, int y, i_fcolor *val) {
234 int off, ch;
235
236 if (x < 0 || x >= im->xsize || y < 0 || y > im->ysize)
237 return -1;
238
239 off = (x + y * im->xsize) * im->channels;
9b8ce4f4
TC
240 if (I_ALL_CHANNELS_WRITABLE(im)) {
241 for (ch = 0; ch < im->channels; ++ch)
242 STORE16(im->idata, off+ch, SampleFTo16(val->channel[ch]));
243 }
244 else {
245 for (ch = 0; ch < im->channels; ++ch)
246 if (im->ch_mask & (1 << ch))
247 STORE16(im->idata, off+ch, SampleFTo16(val->channel[ch]));
248 }
faa9b3e7
TC
249
250 return 0;
251}
252
253static int i_gpixf_d16(i_img *im, int x, int y, i_fcolor *val) {
254 int off, ch;
255
256 if (x < 0 || x >= im->xsize || y < 0 || y > im->ysize)
257 return -1;
258
259 off = (x + y * im->xsize) * im->channels;
260 for (ch = 0; ch < im->channels; ++ch)
261 val->channel[ch] = Sample16ToF(GET16(im->idata, off+ch));
262
263 return 0;
264}
265
266static int i_glin_d16(i_img *im, int l, int r, int y, i_color *vals) {
267 int ch, count, i;
268 int off;
269 if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
270 if (r > im->xsize)
271 r = im->xsize;
272 off = (l+y*im->xsize) * im->channels;
273 count = r - l;
274 for (i = 0; i < count; ++i) {
275 for (ch = 0; ch < im->channels; ++ch) {
276 vals[i].channel[ch] = GET16as8(im->idata, off);
277 ++off;
278 }
279 }
280 return count;
281 }
282 else {
283 return 0;
284 }
285}
286
287static int i_plin_d16(i_img *im, int l, int r, int y, i_color *vals) {
288 int ch, count, i;
289 int off;
290 if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
291 if (r > im->xsize)
292 r = im->xsize;
293 off = (l+y*im->xsize) * im->channels;
294 count = r - l;
9b8ce4f4
TC
295 if (I_ALL_CHANNELS_WRITABLE(im)) {
296 for (i = 0; i < count; ++i) {
297 for (ch = 0; ch < im->channels; ++ch) {
298 STORE8as16(im->idata, off, vals[i].channel[ch]);
299 ++off;
300 }
301 }
302 }
303 else {
304 for (i = 0; i < count; ++i) {
305 for (ch = 0; ch < im->channels; ++ch) {
306 if (im->ch_mask & (1 << ch))
307 STORE8as16(im->idata, off, vals[i].channel[ch]);
308 ++off;
309 }
faa9b3e7
TC
310 }
311 }
312 return count;
313 }
314 else {
315 return 0;
316 }
317}
318
319static int i_glinf_d16(i_img *im, int l, int r, int y, i_fcolor *vals) {
320 int ch, count, i;
321 int off;
322 if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
323 if (r > im->xsize)
324 r = im->xsize;
325 off = (l+y*im->xsize) * im->channels;
326 count = r - l;
327 for (i = 0; i < count; ++i) {
328 for (ch = 0; ch < im->channels; ++ch) {
329 vals[i].channel[ch] = Sample16ToF(GET16(im->idata, off));
330 ++off;
331 }
332 }
333 return count;
334 }
335 else {
336 return 0;
337 }
338}
339
340static int i_plinf_d16(i_img *im, int l, int r, int y, i_fcolor *vals) {
341 int ch, count, i;
342 int off;
343 if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
344 if (r > im->xsize)
345 r = im->xsize;
346 off = (l+y*im->xsize) * im->channels;
347 count = r - l;
9b8ce4f4
TC
348 if (I_ALL_CHANNELS_WRITABLE(im)) {
349 for (i = 0; i < count; ++i) {
350 for (ch = 0; ch < im->channels; ++ch) {
351 STORE16(im->idata, off, SampleFTo16(vals[i].channel[ch]));
352 ++off;
353 }
354 }
355 }
356 else {
357 for (i = 0; i < count; ++i) {
358 for (ch = 0; ch < im->channels; ++ch) {
359 if (im->ch_mask & (1 << ch))
360 STORE16(im->idata, off, SampleFTo16(vals[i].channel[ch]));
361 ++off;
362 }
faa9b3e7
TC
363 }
364 }
365 return count;
366 }
367 else {
368 return 0;
369 }
370}
371
372static int i_gsamp_d16(i_img *im, int l, int r, int y, i_sample_t *samps,
18accb2a 373 int const *chans, int chan_count) {
faa9b3e7
TC
374 int ch, count, i, w;
375 int off;
376
377 if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
378 if (r > im->xsize)
379 r = im->xsize;
380 off = (l+y*im->xsize) * im->channels;
381 w = r - l;
382 count = 0;
383
384 if (chans) {
385 /* make sure we have good channel numbers */
386 for (ch = 0; ch < chan_count; ++ch) {
387 if (chans[ch] < 0 || chans[ch] >= im->channels) {
388 i_push_errorf(0, "No channel %d in this image", chans[ch]);
389 return 0;
390 }
391 }
392 for (i = 0; i < w; ++i) {
393 for (ch = 0; ch < chan_count; ++ch) {
394 *samps++ = GET16as8(im->idata, off+chans[ch]);
395 ++count;
396 }
397 off += im->channels;
398 }
399 }
400 else {
401 for (i = 0; i < w; ++i) {
402 for (ch = 0; ch < chan_count; ++ch) {
403 *samps++ = GET16as8(im->idata, off+ch);
404 ++count;
405 }
406 off += im->channels;
407 }
408 }
409
410 return count;
411 }
412 else {
413 return 0;
414 }
415}
416
417static int i_gsampf_d16(i_img *im, int l, int r, int y, i_fsample_t *samps,
18accb2a 418 int const *chans, int chan_count) {
faa9b3e7
TC
419 int ch, count, i, w;
420 int off;
421
422 if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
423 if (r > im->xsize)
424 r = im->xsize;
425 off = (l+y*im->xsize) * im->channels;
426 w = r - l;
427 count = 0;
428
429 if (chans) {
430 /* make sure we have good channel numbers */
431 for (ch = 0; ch < chan_count; ++ch) {
432 if (chans[ch] < 0 || chans[ch] >= im->channels) {
433 i_push_errorf(0, "No channel %d in this image", chans[ch]);
434 return 0;
435 }
436 }
437 for (i = 0; i < w; ++i) {
438 for (ch = 0; ch < chan_count; ++ch) {
439 *samps++ = Sample16ToF(GET16(im->idata, off+chans[ch]));
440 ++count;
441 }
442 off += im->channels;
443 }
444 }
445 else {
446 for (i = 0; i < w; ++i) {
447 for (ch = 0; ch < chan_count; ++ch) {
448 *samps++ = Sample16ToF(GET16(im->idata, off+ch));
449 ++count;
450 }
451 off += im->channels;
452 }
453 }
454
455 return count;
456 }
457 else {
458 return 0;
459 }
460}
461
b8c2033e
AMH
462/*
463=back
464
465=head1 AUTHOR
466
467Tony Cook <tony@develop-help.com>
468
469=head1 SEE ALSO
470
471Imager(3)
472
473=cut
474*/