planning too far ahead
[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
92bda632
TC
23#include "imager.h"
24#include "imageri.h"
faa9b3e7 25
97ac0a96 26static int i_ppix_d16(i_img *im, int x, int y, const i_color *val);
faa9b3e7
TC
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);
97ac0a96
TC
29static int i_plin_d16(i_img *im, int l, int r, int y, const i_color *vals);
30static int i_ppixf_d16(i_img *im, int x, int y, const i_fcolor *val);
faa9b3e7
TC
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);
97ac0a96 33static int i_plinf_d16(i_img *im, int l, int r, int y, const i_fcolor *vals);
faa9b3e7 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/*
92bda632 139=item i_img_16_new_low(int x, int y, int ch)
faa9b3e7
TC
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) {
f0960b14 146 int bytes, line_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 162
f0960b14
TC
163 /* basic assumption: we can always allocate a buffer representing a
164 line from the image, otherwise we're going to have trouble
165 working with the image */
166 line_bytes = sizeof(i_fcolor) * x;
167 if (line_bytes / x != sizeof(i_fcolor)) {
168 i_push_error(0, "integer overflow calculating scanline allocation");
169 return NULL;
170 }
171
faa9b3e7
TC
172 *im = IIM_base_16bit_direct;
173 i_tags_new(&im->tags);
174 im->xsize = x;
175 im->ysize = y;
176 im->channels = ch;
653ea321 177 im->bytes = bytes;
faa9b3e7
TC
178 im->ext_data = NULL;
179 im->idata = mymalloc(im->bytes);
180 if (im->idata) {
181 memset(im->idata, 0, im->bytes);
182 }
183 else {
184 i_tags_destroy(&im->tags);
185 im = NULL;
186 }
187
188 return im;
189}
190
92bda632
TC
191/*
192=item i_img_16_new(x, y, ch)
193
9167a5c6
TC
194=category Image creation/destruction
195=synopsis i_img *img = i_img_16_new(width, height, channels);
92bda632
TC
196
197Create a new 16-bit/sample image.
198
199Returns the image on success, or NULL on failure.
200
201=cut
202*/
203
faa9b3e7
TC
204i_img *i_img_16_new(int x, int y, int ch) {
205 i_img *im;
1501d9b3
TC
206
207 i_clear_error();
faa9b3e7
TC
208
209 im = mymalloc(sizeof(i_img));
210 if (im) {
211 if (!i_img_16_new_low(im, x, y, ch)) {
212 myfree(im);
213 im = NULL;
214 }
215 }
216
217 mm_log((1, "(%p) <- i_img_16_new\n", im));
218
219 return im;
220}
221
167660cd
TC
222/*
223=item i_img_to_rgb16(im)
224
225=category Image creation
226
227Returns a 16-bit/sample version of the supplied image.
228
229Returns the image on success, or NULL on failure.
230
231=cut
232*/
233
234i_img *
235i_img_to_rgb16(i_img *im) {
236 i_img *targ;
237 i_fcolor *line;
238 int y;
239
240 targ = i_img_16_new(im->xsize, im->ysize, im->channels);
241 if (!targ)
242 return NULL;
243 line = mymalloc(sizeof(i_fcolor) * im->xsize);
244 for (y = 0; y < im->ysize; ++y) {
245 i_glinf(im, 0, im->xsize, y, line);
246 i_plinf(targ, 0, im->xsize, y, line);
247 }
248
249 myfree(line);
250
251 return targ;
252}
253
97ac0a96 254static int i_ppix_d16(i_img *im, int x, int y, const i_color *val) {
faa9b3e7
TC
255 int off, ch;
256
837a4b43 257 if (x < 0 || x >= im->xsize || y < 0 || y >= im->ysize)
faa9b3e7
TC
258 return -1;
259
260 off = (x + y * im->xsize) * im->channels;
9b8ce4f4
TC
261 if (I_ALL_CHANNELS_WRITABLE(im)) {
262 for (ch = 0; ch < im->channels; ++ch)
263 STORE8as16(im->idata, off+ch, val->channel[ch]);
264 }
265 else {
266 for (ch = 0; ch < im->channels; ++ch)
267 if (im->ch_mask & (1 << ch))
268 STORE8as16(im->idata, off+ch, val->channel[ch]);
269 }
faa9b3e7
TC
270
271 return 0;
272}
273
274static int i_gpix_d16(i_img *im, int x, int y, i_color *val) {
275 int off, ch;
276
837a4b43 277 if (x < 0 || x >= im->xsize || y < 0 || y >= im->ysize)
faa9b3e7
TC
278 return -1;
279
280 off = (x + y * im->xsize) * im->channels;
281 for (ch = 0; ch < im->channels; ++ch)
282 val->channel[ch] = GET16as8(im->idata, off+ch);
283
284 return 0;
285}
286
97ac0a96 287static int i_ppixf_d16(i_img *im, int x, int y, const i_fcolor *val) {
faa9b3e7
TC
288 int off, ch;
289
837a4b43 290 if (x < 0 || x >= im->xsize || y < 0 || y >= im->ysize)
faa9b3e7
TC
291 return -1;
292
293 off = (x + y * im->xsize) * im->channels;
9b8ce4f4
TC
294 if (I_ALL_CHANNELS_WRITABLE(im)) {
295 for (ch = 0; ch < im->channels; ++ch)
296 STORE16(im->idata, off+ch, SampleFTo16(val->channel[ch]));
297 }
298 else {
299 for (ch = 0; ch < im->channels; ++ch)
300 if (im->ch_mask & (1 << ch))
301 STORE16(im->idata, off+ch, SampleFTo16(val->channel[ch]));
302 }
faa9b3e7
TC
303
304 return 0;
305}
306
307static int i_gpixf_d16(i_img *im, int x, int y, i_fcolor *val) {
308 int off, ch;
309
837a4b43 310 if (x < 0 || x >= im->xsize || y < 0 || y >= im->ysize)
faa9b3e7
TC
311 return -1;
312
313 off = (x + y * im->xsize) * im->channels;
314 for (ch = 0; ch < im->channels; ++ch)
315 val->channel[ch] = Sample16ToF(GET16(im->idata, off+ch));
316
317 return 0;
318}
319
320static int i_glin_d16(i_img *im, int l, int r, int y, i_color *vals) {
321 int ch, count, i;
322 int off;
323 if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
324 if (r > im->xsize)
325 r = im->xsize;
326 off = (l+y*im->xsize) * im->channels;
327 count = r - l;
328 for (i = 0; i < count; ++i) {
329 for (ch = 0; ch < im->channels; ++ch) {
330 vals[i].channel[ch] = GET16as8(im->idata, off);
331 ++off;
332 }
333 }
334 return count;
335 }
336 else {
337 return 0;
338 }
339}
340
97ac0a96 341static int i_plin_d16(i_img *im, int l, int r, int y, const i_color *vals) {
faa9b3e7
TC
342 int ch, count, i;
343 int off;
344 if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
345 if (r > im->xsize)
346 r = im->xsize;
347 off = (l+y*im->xsize) * im->channels;
348 count = r - l;
9b8ce4f4
TC
349 if (I_ALL_CHANNELS_WRITABLE(im)) {
350 for (i = 0; i < count; ++i) {
351 for (ch = 0; ch < im->channels; ++ch) {
352 STORE8as16(im->idata, off, vals[i].channel[ch]);
353 ++off;
354 }
355 }
356 }
357 else {
358 for (i = 0; i < count; ++i) {
359 for (ch = 0; ch < im->channels; ++ch) {
360 if (im->ch_mask & (1 << ch))
361 STORE8as16(im->idata, off, vals[i].channel[ch]);
362 ++off;
363 }
faa9b3e7
TC
364 }
365 }
366 return count;
367 }
368 else {
369 return 0;
370 }
371}
372
373static int i_glinf_d16(i_img *im, int l, int r, int y, i_fcolor *vals) {
374 int ch, count, i;
375 int off;
376 if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
377 if (r > im->xsize)
378 r = im->xsize;
379 off = (l+y*im->xsize) * im->channels;
380 count = r - l;
381 for (i = 0; i < count; ++i) {
382 for (ch = 0; ch < im->channels; ++ch) {
383 vals[i].channel[ch] = Sample16ToF(GET16(im->idata, off));
384 ++off;
385 }
386 }
387 return count;
388 }
389 else {
390 return 0;
391 }
392}
393
97ac0a96 394static int i_plinf_d16(i_img *im, int l, int r, int y, const i_fcolor *vals) {
faa9b3e7
TC
395 int ch, count, i;
396 int off;
397 if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
398 if (r > im->xsize)
399 r = im->xsize;
400 off = (l+y*im->xsize) * im->channels;
401 count = r - l;
9b8ce4f4
TC
402 if (I_ALL_CHANNELS_WRITABLE(im)) {
403 for (i = 0; i < count; ++i) {
404 for (ch = 0; ch < im->channels; ++ch) {
405 STORE16(im->idata, off, SampleFTo16(vals[i].channel[ch]));
406 ++off;
407 }
408 }
409 }
410 else {
411 for (i = 0; i < count; ++i) {
412 for (ch = 0; ch < im->channels; ++ch) {
413 if (im->ch_mask & (1 << ch))
414 STORE16(im->idata, off, SampleFTo16(vals[i].channel[ch]));
415 ++off;
416 }
faa9b3e7
TC
417 }
418 }
419 return count;
420 }
421 else {
422 return 0;
423 }
424}
425
426static int i_gsamp_d16(i_img *im, int l, int r, int y, i_sample_t *samps,
18accb2a 427 int const *chans, int chan_count) {
faa9b3e7
TC
428 int ch, count, i, w;
429 int off;
430
431 if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
432 if (r > im->xsize)
433 r = im->xsize;
434 off = (l+y*im->xsize) * im->channels;
435 w = r - l;
436 count = 0;
437
438 if (chans) {
439 /* make sure we have good channel numbers */
440 for (ch = 0; ch < chan_count; ++ch) {
441 if (chans[ch] < 0 || chans[ch] >= im->channels) {
442 i_push_errorf(0, "No channel %d in this image", chans[ch]);
443 return 0;
444 }
445 }
446 for (i = 0; i < w; ++i) {
447 for (ch = 0; ch < chan_count; ++ch) {
448 *samps++ = GET16as8(im->idata, off+chans[ch]);
449 ++count;
450 }
451 off += im->channels;
452 }
453 }
454 else {
c7481ae1
TC
455 if (chan_count <= 0 || chan_count > im->channels) {
456 i_push_errorf(0, "chan_count %d out of range, must be >0, <= channels",
457 chan_count);
458 return 0;
459 }
faa9b3e7
TC
460 for (i = 0; i < w; ++i) {
461 for (ch = 0; ch < chan_count; ++ch) {
462 *samps++ = GET16as8(im->idata, off+ch);
463 ++count;
464 }
465 off += im->channels;
466 }
467 }
468
469 return count;
470 }
471 else {
472 return 0;
473 }
474}
475
476static int i_gsampf_d16(i_img *im, int l, int r, int y, i_fsample_t *samps,
18accb2a 477 int const *chans, int chan_count) {
faa9b3e7
TC
478 int ch, count, i, w;
479 int off;
480
481 if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
482 if (r > im->xsize)
483 r = im->xsize;
484 off = (l+y*im->xsize) * im->channels;
485 w = r - l;
486 count = 0;
487
488 if (chans) {
489 /* make sure we have good channel numbers */
490 for (ch = 0; ch < chan_count; ++ch) {
491 if (chans[ch] < 0 || chans[ch] >= im->channels) {
492 i_push_errorf(0, "No channel %d in this image", chans[ch]);
493 return 0;
494 }
495 }
496 for (i = 0; i < w; ++i) {
497 for (ch = 0; ch < chan_count; ++ch) {
498 *samps++ = Sample16ToF(GET16(im->idata, off+chans[ch]));
499 ++count;
500 }
501 off += im->channels;
502 }
503 }
504 else {
c7481ae1
TC
505 if (chan_count <= 0 || chan_count > im->channels) {
506 i_push_errorf(0, "chan_count %d out of range, must be >0, <= channels",
507 chan_count);
508 return 0;
509 }
faa9b3e7
TC
510 for (i = 0; i < w; ++i) {
511 for (ch = 0; ch < chan_count; ++ch) {
512 *samps++ = Sample16ToF(GET16(im->idata, off+ch));
513 ++count;
514 }
515 off += im->channels;
516 }
517 }
518
519 return count;
520 }
521 else {
522 return 0;
523 }
524}
525
b8c2033e
AMH
526/*
527=back
528
529=head1 AUTHOR
530
531Tony Cook <tony@develop-help.com>
532
533=head1 SEE ALSO
534
535Imager(3)
536
537=cut
538*/