add to_rgb16 method
[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
194=category Image creation
195
196Create a new 16-bit/sample image.
197
198Returns the image on success, or NULL on failure.
199
200=cut
201*/
202
faa9b3e7
TC
203i_img *i_img_16_new(int x, int y, int ch) {
204 i_img *im;
1501d9b3
TC
205
206 i_clear_error();
faa9b3e7
TC
207
208 im = mymalloc(sizeof(i_img));
209 if (im) {
210 if (!i_img_16_new_low(im, x, y, ch)) {
211 myfree(im);
212 im = NULL;
213 }
214 }
215
216 mm_log((1, "(%p) <- i_img_16_new\n", im));
217
218 return im;
219}
220
167660cd
TC
221/*
222=item i_img_to_rgb16(im)
223
224=category Image creation
225
226Returns a 16-bit/sample version of the supplied image.
227
228Returns the image on success, or NULL on failure.
229
230=cut
231*/
232
233i_img *
234i_img_to_rgb16(i_img *im) {
235 i_img *targ;
236 i_fcolor *line;
237 int y;
238
239 targ = i_img_16_new(im->xsize, im->ysize, im->channels);
240 if (!targ)
241 return NULL;
242 line = mymalloc(sizeof(i_fcolor) * im->xsize);
243 for (y = 0; y < im->ysize; ++y) {
244 i_glinf(im, 0, im->xsize, y, line);
245 i_plinf(targ, 0, im->xsize, y, line);
246 }
247
248 myfree(line);
249
250 return targ;
251}
252
97ac0a96 253static int i_ppix_d16(i_img *im, int x, int y, const i_color *val) {
faa9b3e7
TC
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;
9b8ce4f4
TC
260 if (I_ALL_CHANNELS_WRITABLE(im)) {
261 for (ch = 0; ch < im->channels; ++ch)
262 STORE8as16(im->idata, off+ch, val->channel[ch]);
263 }
264 else {
265 for (ch = 0; ch < im->channels; ++ch)
266 if (im->ch_mask & (1 << ch))
267 STORE8as16(im->idata, off+ch, val->channel[ch]);
268 }
faa9b3e7
TC
269
270 return 0;
271}
272
273static int i_gpix_d16(i_img *im, int x, int y, i_color *val) {
274 int off, ch;
275
276 if (x < 0 || x >= im->xsize || y < 0 || y > im->ysize)
277 return -1;
278
279 off = (x + y * im->xsize) * im->channels;
280 for (ch = 0; ch < im->channels; ++ch)
281 val->channel[ch] = GET16as8(im->idata, off+ch);
282
283 return 0;
284}
285
97ac0a96 286static int i_ppixf_d16(i_img *im, int x, int y, const i_fcolor *val) {
faa9b3e7
TC
287 int off, ch;
288
289 if (x < 0 || x >= im->xsize || y < 0 || y > im->ysize)
290 return -1;
291
292 off = (x + y * im->xsize) * im->channels;
9b8ce4f4
TC
293 if (I_ALL_CHANNELS_WRITABLE(im)) {
294 for (ch = 0; ch < im->channels; ++ch)
295 STORE16(im->idata, off+ch, SampleFTo16(val->channel[ch]));
296 }
297 else {
298 for (ch = 0; ch < im->channels; ++ch)
299 if (im->ch_mask & (1 << ch))
300 STORE16(im->idata, off+ch, SampleFTo16(val->channel[ch]));
301 }
faa9b3e7
TC
302
303 return 0;
304}
305
306static int i_gpixf_d16(i_img *im, int x, int y, i_fcolor *val) {
307 int off, ch;
308
309 if (x < 0 || x >= im->xsize || y < 0 || y > im->ysize)
310 return -1;
311
312 off = (x + y * im->xsize) * im->channels;
313 for (ch = 0; ch < im->channels; ++ch)
314 val->channel[ch] = Sample16ToF(GET16(im->idata, off+ch));
315
316 return 0;
317}
318
319static int i_glin_d16(i_img *im, int l, int r, int y, i_color *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] = GET16as8(im->idata, off);
330 ++off;
331 }
332 }
333 return count;
334 }
335 else {
336 return 0;
337 }
338}
339
97ac0a96 340static int i_plin_d16(i_img *im, int l, int r, int y, const i_color *vals) {
faa9b3e7
TC
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 STORE8as16(im->idata, off, 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 STORE8as16(im->idata, off, 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_glinf_d16(i_img *im, int l, int r, int y, i_fcolor *vals) {
373 int ch, count, i;
374 int off;
375 if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
376 if (r > im->xsize)
377 r = im->xsize;
378 off = (l+y*im->xsize) * im->channels;
379 count = r - l;
380 for (i = 0; i < count; ++i) {
381 for (ch = 0; ch < im->channels; ++ch) {
382 vals[i].channel[ch] = Sample16ToF(GET16(im->idata, off));
383 ++off;
384 }
385 }
386 return count;
387 }
388 else {
389 return 0;
390 }
391}
392
97ac0a96 393static int i_plinf_d16(i_img *im, int l, int r, int y, const i_fcolor *vals) {
faa9b3e7
TC
394 int ch, count, i;
395 int off;
396 if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
397 if (r > im->xsize)
398 r = im->xsize;
399 off = (l+y*im->xsize) * im->channels;
400 count = r - l;
9b8ce4f4
TC
401 if (I_ALL_CHANNELS_WRITABLE(im)) {
402 for (i = 0; i < count; ++i) {
403 for (ch = 0; ch < im->channels; ++ch) {
404 STORE16(im->idata, off, SampleFTo16(vals[i].channel[ch]));
405 ++off;
406 }
407 }
408 }
409 else {
410 for (i = 0; i < count; ++i) {
411 for (ch = 0; ch < im->channels; ++ch) {
412 if (im->ch_mask & (1 << ch))
413 STORE16(im->idata, off, SampleFTo16(vals[i].channel[ch]));
414 ++off;
415 }
faa9b3e7
TC
416 }
417 }
418 return count;
419 }
420 else {
421 return 0;
422 }
423}
424
425static int i_gsamp_d16(i_img *im, int l, int r, int y, i_sample_t *samps,
18accb2a 426 int const *chans, int chan_count) {
faa9b3e7
TC
427 int ch, count, i, w;
428 int off;
429
430 if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
431 if (r > im->xsize)
432 r = im->xsize;
433 off = (l+y*im->xsize) * im->channels;
434 w = r - l;
435 count = 0;
436
437 if (chans) {
438 /* make sure we have good channel numbers */
439 for (ch = 0; ch < chan_count; ++ch) {
440 if (chans[ch] < 0 || chans[ch] >= im->channels) {
441 i_push_errorf(0, "No channel %d in this image", chans[ch]);
442 return 0;
443 }
444 }
445 for (i = 0; i < w; ++i) {
446 for (ch = 0; ch < chan_count; ++ch) {
447 *samps++ = GET16as8(im->idata, off+chans[ch]);
448 ++count;
449 }
450 off += im->channels;
451 }
452 }
453 else {
454 for (i = 0; i < w; ++i) {
455 for (ch = 0; ch < chan_count; ++ch) {
456 *samps++ = GET16as8(im->idata, off+ch);
457 ++count;
458 }
459 off += im->channels;
460 }
461 }
462
463 return count;
464 }
465 else {
466 return 0;
467 }
468}
469
470static int i_gsampf_d16(i_img *im, int l, int r, int y, i_fsample_t *samps,
18accb2a 471 int const *chans, int chan_count) {
faa9b3e7
TC
472 int ch, count, i, w;
473 int off;
474
475 if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
476 if (r > im->xsize)
477 r = im->xsize;
478 off = (l+y*im->xsize) * im->channels;
479 w = r - l;
480 count = 0;
481
482 if (chans) {
483 /* make sure we have good channel numbers */
484 for (ch = 0; ch < chan_count; ++ch) {
485 if (chans[ch] < 0 || chans[ch] >= im->channels) {
486 i_push_errorf(0, "No channel %d in this image", chans[ch]);
487 return 0;
488 }
489 }
490 for (i = 0; i < w; ++i) {
491 for (ch = 0; ch < chan_count; ++ch) {
492 *samps++ = Sample16ToF(GET16(im->idata, off+chans[ch]));
493 ++count;
494 }
495 off += im->channels;
496 }
497 }
498 else {
499 for (i = 0; i < w; ++i) {
500 for (ch = 0; ch < chan_count; ++ch) {
501 *samps++ = Sample16ToF(GET16(im->idata, off+ch));
502 ++count;
503 }
504 off += im->channels;
505 }
506 }
507
508 return count;
509 }
510 else {
511 return 0;
512 }
513}
514
b8c2033e
AMH
515/*
516=back
517
518=head1 AUTHOR
519
520Tony Cook <tony@develop-help.com>
521
522=head1 SEE ALSO
523
524Imager(3)
525
526=cut
527*/