- extra concept index entries
[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) {
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
191i_img *i_img_16_new(int x, int y, int ch) {
192 i_img *im;
1501d9b3
TC
193
194 i_clear_error();
faa9b3e7
TC
195
196 im = mymalloc(sizeof(i_img));
197 if (im) {
198 if (!i_img_16_new_low(im, x, y, ch)) {
199 myfree(im);
200 im = NULL;
201 }
202 }
203
204 mm_log((1, "(%p) <- i_img_16_new\n", im));
205
206 return im;
207}
208
209static int i_ppix_d16(i_img *im, int x, int y, i_color *val) {
210 int off, ch;
211
212 if (x < 0 || x >= im->xsize || y < 0 || y > im->ysize)
213 return -1;
214
215 off = (x + y * im->xsize) * im->channels;
9b8ce4f4
TC
216 if (I_ALL_CHANNELS_WRITABLE(im)) {
217 for (ch = 0; ch < im->channels; ++ch)
218 STORE8as16(im->idata, off+ch, val->channel[ch]);
219 }
220 else {
221 for (ch = 0; ch < im->channels; ++ch)
222 if (im->ch_mask & (1 << ch))
223 STORE8as16(im->idata, off+ch, val->channel[ch]);
224 }
faa9b3e7
TC
225
226 return 0;
227}
228
229static int i_gpix_d16(i_img *im, int x, int y, i_color *val) {
230 int off, ch;
231
232 if (x < 0 || x >= im->xsize || y < 0 || y > im->ysize)
233 return -1;
234
235 off = (x + y * im->xsize) * im->channels;
236 for (ch = 0; ch < im->channels; ++ch)
237 val->channel[ch] = GET16as8(im->idata, off+ch);
238
239 return 0;
240}
241
242static int i_ppixf_d16(i_img *im, int x, int y, i_fcolor *val) {
243 int off, ch;
244
245 if (x < 0 || x >= im->xsize || y < 0 || y > im->ysize)
246 return -1;
247
248 off = (x + y * im->xsize) * im->channels;
9b8ce4f4
TC
249 if (I_ALL_CHANNELS_WRITABLE(im)) {
250 for (ch = 0; ch < im->channels; ++ch)
251 STORE16(im->idata, off+ch, SampleFTo16(val->channel[ch]));
252 }
253 else {
254 for (ch = 0; ch < im->channels; ++ch)
255 if (im->ch_mask & (1 << ch))
256 STORE16(im->idata, off+ch, SampleFTo16(val->channel[ch]));
257 }
faa9b3e7
TC
258
259 return 0;
260}
261
262static int i_gpixf_d16(i_img *im, int x, int y, i_fcolor *val) {
263 int off, ch;
264
265 if (x < 0 || x >= im->xsize || y < 0 || y > im->ysize)
266 return -1;
267
268 off = (x + y * im->xsize) * im->channels;
269 for (ch = 0; ch < im->channels; ++ch)
270 val->channel[ch] = Sample16ToF(GET16(im->idata, off+ch));
271
272 return 0;
273}
274
275static int i_glin_d16(i_img *im, int l, int r, int y, i_color *vals) {
276 int ch, count, i;
277 int off;
278 if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
279 if (r > im->xsize)
280 r = im->xsize;
281 off = (l+y*im->xsize) * im->channels;
282 count = r - l;
283 for (i = 0; i < count; ++i) {
284 for (ch = 0; ch < im->channels; ++ch) {
285 vals[i].channel[ch] = GET16as8(im->idata, off);
286 ++off;
287 }
288 }
289 return count;
290 }
291 else {
292 return 0;
293 }
294}
295
296static int i_plin_d16(i_img *im, int l, int r, int y, i_color *vals) {
297 int ch, count, i;
298 int off;
299 if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
300 if (r > im->xsize)
301 r = im->xsize;
302 off = (l+y*im->xsize) * im->channels;
303 count = r - l;
9b8ce4f4
TC
304 if (I_ALL_CHANNELS_WRITABLE(im)) {
305 for (i = 0; i < count; ++i) {
306 for (ch = 0; ch < im->channels; ++ch) {
307 STORE8as16(im->idata, off, vals[i].channel[ch]);
308 ++off;
309 }
310 }
311 }
312 else {
313 for (i = 0; i < count; ++i) {
314 for (ch = 0; ch < im->channels; ++ch) {
315 if (im->ch_mask & (1 << ch))
316 STORE8as16(im->idata, off, vals[i].channel[ch]);
317 ++off;
318 }
faa9b3e7
TC
319 }
320 }
321 return count;
322 }
323 else {
324 return 0;
325 }
326}
327
328static int i_glinf_d16(i_img *im, int l, int r, int y, i_fcolor *vals) {
329 int ch, count, i;
330 int off;
331 if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
332 if (r > im->xsize)
333 r = im->xsize;
334 off = (l+y*im->xsize) * im->channels;
335 count = r - l;
336 for (i = 0; i < count; ++i) {
337 for (ch = 0; ch < im->channels; ++ch) {
338 vals[i].channel[ch] = Sample16ToF(GET16(im->idata, off));
339 ++off;
340 }
341 }
342 return count;
343 }
344 else {
345 return 0;
346 }
347}
348
349static int i_plinf_d16(i_img *im, int l, int r, int y, i_fcolor *vals) {
350 int ch, count, i;
351 int off;
352 if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
353 if (r > im->xsize)
354 r = im->xsize;
355 off = (l+y*im->xsize) * im->channels;
356 count = r - l;
9b8ce4f4
TC
357 if (I_ALL_CHANNELS_WRITABLE(im)) {
358 for (i = 0; i < count; ++i) {
359 for (ch = 0; ch < im->channels; ++ch) {
360 STORE16(im->idata, off, SampleFTo16(vals[i].channel[ch]));
361 ++off;
362 }
363 }
364 }
365 else {
366 for (i = 0; i < count; ++i) {
367 for (ch = 0; ch < im->channels; ++ch) {
368 if (im->ch_mask & (1 << ch))
369 STORE16(im->idata, off, SampleFTo16(vals[i].channel[ch]));
370 ++off;
371 }
faa9b3e7
TC
372 }
373 }
374 return count;
375 }
376 else {
377 return 0;
378 }
379}
380
381static int i_gsamp_d16(i_img *im, int l, int r, int y, i_sample_t *samps,
18accb2a 382 int const *chans, int chan_count) {
faa9b3e7
TC
383 int ch, count, i, w;
384 int off;
385
386 if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
387 if (r > im->xsize)
388 r = im->xsize;
389 off = (l+y*im->xsize) * im->channels;
390 w = r - l;
391 count = 0;
392
393 if (chans) {
394 /* make sure we have good channel numbers */
395 for (ch = 0; ch < chan_count; ++ch) {
396 if (chans[ch] < 0 || chans[ch] >= im->channels) {
397 i_push_errorf(0, "No channel %d in this image", chans[ch]);
398 return 0;
399 }
400 }
401 for (i = 0; i < w; ++i) {
402 for (ch = 0; ch < chan_count; ++ch) {
403 *samps++ = GET16as8(im->idata, off+chans[ch]);
404 ++count;
405 }
406 off += im->channels;
407 }
408 }
409 else {
410 for (i = 0; i < w; ++i) {
411 for (ch = 0; ch < chan_count; ++ch) {
412 *samps++ = GET16as8(im->idata, off+ch);
413 ++count;
414 }
415 off += im->channels;
416 }
417 }
418
419 return count;
420 }
421 else {
422 return 0;
423 }
424}
425
426static int i_gsampf_d16(i_img *im, int l, int r, int y, i_fsample_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++ = Sample16ToF(GET16(im->idata, off+chans[ch]));
449 ++count;
450 }
451 off += im->channels;
452 }
453 }
454 else {
455 for (i = 0; i < w; ++i) {
456 for (ch = 0; ch < chan_count; ++ch) {
457 *samps++ = Sample16ToF(GET16(im->idata, off+ch));
458 ++count;
459 }
460 off += im->channels;
461 }
462 }
463
464 return count;
465 }
466 else {
467 return 0;
468 }
469}
470
b8c2033e
AMH
471/*
472=back
473
474=head1 AUTHOR
475
476Tony Cook <tony@develop-help.com>
477
478=head1 SEE ALSO
479
480Imager(3)
481
482=cut
483*/