]> git.imager.perl.org - imager.git/blame - img16.c
Test::More is now a pre-requisite for Imager, so remove it from the
[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
97ac0a96 221static int i_ppix_d16(i_img *im, int x, int y, const i_color *val) {
faa9b3e7
TC
222 int off, ch;
223
224 if (x < 0 || x >= im->xsize || y < 0 || y > im->ysize)
225 return -1;
226
227 off = (x + y * im->xsize) * im->channels;
9b8ce4f4
TC
228 if (I_ALL_CHANNELS_WRITABLE(im)) {
229 for (ch = 0; ch < im->channels; ++ch)
230 STORE8as16(im->idata, off+ch, val->channel[ch]);
231 }
232 else {
233 for (ch = 0; ch < im->channels; ++ch)
234 if (im->ch_mask & (1 << ch))
235 STORE8as16(im->idata, off+ch, val->channel[ch]);
236 }
faa9b3e7
TC
237
238 return 0;
239}
240
241static int i_gpix_d16(i_img *im, int x, int y, i_color *val) {
242 int off, ch;
243
244 if (x < 0 || x >= im->xsize || y < 0 || y > im->ysize)
245 return -1;
246
247 off = (x + y * im->xsize) * im->channels;
248 for (ch = 0; ch < im->channels; ++ch)
249 val->channel[ch] = GET16as8(im->idata, off+ch);
250
251 return 0;
252}
253
97ac0a96 254static int i_ppixf_d16(i_img *im, int x, int y, const i_fcolor *val) {
faa9b3e7
TC
255 int off, ch;
256
257 if (x < 0 || x >= im->xsize || y < 0 || y > im->ysize)
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 STORE16(im->idata, off+ch, SampleFTo16(val->channel[ch]));
264 }
265 else {
266 for (ch = 0; ch < im->channels; ++ch)
267 if (im->ch_mask & (1 << ch))
268 STORE16(im->idata, off+ch, SampleFTo16(val->channel[ch]));
269 }
faa9b3e7
TC
270
271 return 0;
272}
273
274static int i_gpixf_d16(i_img *im, int x, int y, i_fcolor *val) {
275 int off, ch;
276
277 if (x < 0 || x >= im->xsize || y < 0 || y > im->ysize)
278 return -1;
279
280 off = (x + y * im->xsize) * im->channels;
281 for (ch = 0; ch < im->channels; ++ch)
282 val->channel[ch] = Sample16ToF(GET16(im->idata, off+ch));
283
284 return 0;
285}
286
287static int i_glin_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;
295 for (i = 0; i < count; ++i) {
296 for (ch = 0; ch < im->channels; ++ch) {
297 vals[i].channel[ch] = GET16as8(im->idata, off);
298 ++off;
299 }
300 }
301 return count;
302 }
303 else {
304 return 0;
305 }
306}
307
97ac0a96 308static int i_plin_d16(i_img *im, int l, int r, int y, const i_color *vals) {
faa9b3e7
TC
309 int ch, count, i;
310 int off;
311 if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
312 if (r > im->xsize)
313 r = im->xsize;
314 off = (l+y*im->xsize) * im->channels;
315 count = r - l;
9b8ce4f4
TC
316 if (I_ALL_CHANNELS_WRITABLE(im)) {
317 for (i = 0; i < count; ++i) {
318 for (ch = 0; ch < im->channels; ++ch) {
319 STORE8as16(im->idata, off, vals[i].channel[ch]);
320 ++off;
321 }
322 }
323 }
324 else {
325 for (i = 0; i < count; ++i) {
326 for (ch = 0; ch < im->channels; ++ch) {
327 if (im->ch_mask & (1 << ch))
328 STORE8as16(im->idata, off, vals[i].channel[ch]);
329 ++off;
330 }
faa9b3e7
TC
331 }
332 }
333 return count;
334 }
335 else {
336 return 0;
337 }
338}
339
340static int i_glinf_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;
348 for (i = 0; i < count; ++i) {
349 for (ch = 0; ch < im->channels; ++ch) {
350 vals[i].channel[ch] = Sample16ToF(GET16(im->idata, off));
351 ++off;
352 }
353 }
354 return count;
355 }
356 else {
357 return 0;
358 }
359}
360
97ac0a96 361static int i_plinf_d16(i_img *im, int l, int r, int y, const i_fcolor *vals) {
faa9b3e7
TC
362 int ch, count, i;
363 int off;
364 if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
365 if (r > im->xsize)
366 r = im->xsize;
367 off = (l+y*im->xsize) * im->channels;
368 count = r - l;
9b8ce4f4
TC
369 if (I_ALL_CHANNELS_WRITABLE(im)) {
370 for (i = 0; i < count; ++i) {
371 for (ch = 0; ch < im->channels; ++ch) {
372 STORE16(im->idata, off, SampleFTo16(vals[i].channel[ch]));
373 ++off;
374 }
375 }
376 }
377 else {
378 for (i = 0; i < count; ++i) {
379 for (ch = 0; ch < im->channels; ++ch) {
380 if (im->ch_mask & (1 << ch))
381 STORE16(im->idata, off, SampleFTo16(vals[i].channel[ch]));
382 ++off;
383 }
faa9b3e7
TC
384 }
385 }
386 return count;
387 }
388 else {
389 return 0;
390 }
391}
392
393static int i_gsamp_d16(i_img *im, int l, int r, int y, i_sample_t *samps,
18accb2a 394 int const *chans, int chan_count) {
faa9b3e7
TC
395 int ch, count, i, w;
396 int off;
397
398 if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
399 if (r > im->xsize)
400 r = im->xsize;
401 off = (l+y*im->xsize) * im->channels;
402 w = r - l;
403 count = 0;
404
405 if (chans) {
406 /* make sure we have good channel numbers */
407 for (ch = 0; ch < chan_count; ++ch) {
408 if (chans[ch] < 0 || chans[ch] >= im->channels) {
409 i_push_errorf(0, "No channel %d in this image", chans[ch]);
410 return 0;
411 }
412 }
413 for (i = 0; i < w; ++i) {
414 for (ch = 0; ch < chan_count; ++ch) {
415 *samps++ = GET16as8(im->idata, off+chans[ch]);
416 ++count;
417 }
418 off += im->channels;
419 }
420 }
421 else {
422 for (i = 0; i < w; ++i) {
423 for (ch = 0; ch < chan_count; ++ch) {
424 *samps++ = GET16as8(im->idata, off+ch);
425 ++count;
426 }
427 off += im->channels;
428 }
429 }
430
431 return count;
432 }
433 else {
434 return 0;
435 }
436}
437
438static int i_gsampf_d16(i_img *im, int l, int r, int y, i_fsample_t *samps,
18accb2a 439 int const *chans, int chan_count) {
faa9b3e7
TC
440 int ch, count, i, w;
441 int off;
442
443 if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
444 if (r > im->xsize)
445 r = im->xsize;
446 off = (l+y*im->xsize) * im->channels;
447 w = r - l;
448 count = 0;
449
450 if (chans) {
451 /* make sure we have good channel numbers */
452 for (ch = 0; ch < chan_count; ++ch) {
453 if (chans[ch] < 0 || chans[ch] >= im->channels) {
454 i_push_errorf(0, "No channel %d in this image", chans[ch]);
455 return 0;
456 }
457 }
458 for (i = 0; i < w; ++i) {
459 for (ch = 0; ch < chan_count; ++ch) {
460 *samps++ = Sample16ToF(GET16(im->idata, off+chans[ch]));
461 ++count;
462 }
463 off += im->channels;
464 }
465 }
466 else {
467 for (i = 0; i < w; ++i) {
468 for (ch = 0; ch < chan_count; ++ch) {
469 *samps++ = Sample16ToF(GET16(im->idata, off+ch));
470 ++count;
471 }
472 off += im->channels;
473 }
474 }
475
476 return count;
477 }
478 else {
479 return 0;
480 }
481}
482
b8c2033e
AMH
483/*
484=back
485
486=head1 AUTHOR
487
488Tony Cook <tony@develop-help.com>
489
490=head1 SEE ALSO
491
492Imager(3)
493
494=cut
495*/