fix an unsigned comparison when converting character code to a glyph index with a...
[imager.git] / imgdouble.c
CommitLineData
2ce44e2a
TC
1/*
2=head1 NAME
3
4imgdouble.c - implements double per sample images
5
6=head1 SYNOPSIS
7
8d14daab 8 i_img *im = i_img_double_new(width, height, channels);
2ce44e2a
TC
9 # use like a normal image
10
11=head1 DESCRIPTION
12
13Implements double/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
696cb85d 23#define IMAGER_NO_CONTEXT
92bda632
TC
24#include "imager.h"
25#include "imageri.h"
2ce44e2a 26
8d14daab
TC
27static int i_ppix_ddoub(i_img *im, i_img_dim x, i_img_dim y, const i_color *val);
28static int i_gpix_ddoub(i_img *im, i_img_dim x, i_img_dim y, i_color *val);
29static i_img_dim i_glin_ddoub(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_color *vals);
30static i_img_dim i_plin_ddoub(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, const i_color *vals);
31static int i_ppixf_ddoub(i_img *im, i_img_dim x, i_img_dim y, const i_fcolor *val);
32static int i_gpixf_ddoub(i_img *im, i_img_dim x, i_img_dim y, i_fcolor *val);
33static i_img_dim i_glinf_ddoub(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_fcolor *vals);
34static i_img_dim i_plinf_ddoub(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, const i_fcolor *vals);
35static i_img_dim i_gsamp_ddoub(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_sample_t *samps,
18accb2a 36 int const *chans, int chan_count);
8d14daab 37static i_img_dim i_gsampf_ddoub(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_fsample_t *samps,
18accb2a 38 int const *chans, int chan_count);
836d9f54
TC
39static i_img_dim
40i_psamp_ddoub(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, const i_sample_t *samps, const int *chans, int chan_count);
41static i_img_dim
42i_psampf_ddoub(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, const i_fsample_t *samps, const int *chans, int chan_count);
2ce44e2a
TC
43
44/*
45=item IIM_base_16bit_direct
46
47Base structure used to initialize a 16-bit/sample image.
48
49Internal.
50
51=cut
52*/
53static i_img IIM_base_double_direct =
54{
55 0, /* channels set */
56 0, 0, 0, /* xsize, ysize, bytes */
9a88a5e6 57 ~0U, /* ch_mask */
2ce44e2a
TC
58 i_double_bits, /* bits */
59 i_direct_type, /* type */
60 0, /* virtual */
61 NULL, /* idata */
62 { 0, 0, NULL }, /* tags */
63 NULL, /* ext_data */
64
65 i_ppix_ddoub, /* i_f_ppix */
66 i_ppixf_ddoub, /* i_f_ppixf */
67 i_plin_ddoub, /* i_f_plin */
68 i_plinf_ddoub, /* i_f_plinf */
69 i_gpix_ddoub, /* i_f_gpix */
70 i_gpixf_ddoub, /* i_f_gpixf */
71 i_glin_ddoub, /* i_f_glin */
72 i_glinf_ddoub, /* i_f_glinf */
73 i_gsamp_ddoub, /* i_f_gsamp */
74 i_gsampf_ddoub, /* i_f_gsampf */
75
76 NULL, /* i_f_gpal */
77 NULL, /* i_f_ppal */
bd8052a6
TC
78 NULL, /* i_f_addcolors */
79 NULL, /* i_f_getcolors */
2ce44e2a 80 NULL, /* i_f_colorcount */
bd8052a6 81 NULL, /* i_f_maxcolors */
2ce44e2a 82 NULL, /* i_f_findcolor */
bd8052a6 83 NULL, /* i_f_setcolors */
2ce44e2a
TC
84
85 NULL, /* i_f_destroy */
bd8052a6
TC
86
87 i_gsamp_bits_fb,
88 NULL, /* i_f_psamp_bits */
836d9f54
TC
89
90 i_psamp_ddoub, /* i_f_psamp */
91 i_psampf_ddoub /* i_f_psampf */
2ce44e2a
TC
92};
93
94/*
abffffed
TC
95=item im_img_double_new(ctx, x, y, ch)
96X<im_img_double_new API>X<i_img_double_new API>
9167a5c6 97=category Image creation/destruction
abffffed 98=synopsis i_img *img = im_img_double_new(aIMCTX, width, height, channels);
9167a5c6 99=synopsis i_img *img = i_img_double_new(width, height, channels);
92bda632 100
2ce44e2a
TC
101Creates a new double per sample image.
102
abffffed
TC
103Also callable as C<i_img_double_new(width, height, channels)>.
104
2ce44e2a
TC
105=cut
106*/
696cb85d
TC
107i_img *
108im_img_double_new(pIMCTX, i_img_dim x, i_img_dim y, int ch) {
8d14daab 109 size_t bytes;
bd8052a6 110 i_img *im;
653ea321 111
3f5b6dcc 112 im_log((aIMCTX, 1,"i_img_double_new(x %" i_DF ", y %" i_DF ", ch %d)\n",
8d14daab 113 i_DFc(x), i_DFc(y), ch));
1501d9b3
TC
114
115 if (x < 1 || y < 1) {
696cb85d 116 im_push_error(aIMCTX, 0, "Image sizes must be positive");
1501d9b3
TC
117 return NULL;
118 }
119 if (ch < 1 || ch > MAXCHANNELS) {
696cb85d 120 im_push_errorf(aIMCTX, 0, "channels must be between 1 and %d", MAXCHANNELS);
1501d9b3
TC
121 return NULL;
122 }
653ea321
TC
123 bytes = x * y * ch * sizeof(double);
124 if (bytes / y / ch / sizeof(double) != x) {
696cb85d 125 im_push_errorf(aIMCTX, 0, "integer overflow calculating image allocation");
653ea321
TC
126 return NULL;
127 }
2ce44e2a 128
696cb85d 129 im = im_img_alloc(aIMCTX);
2ce44e2a
TC
130 *im = IIM_base_double_direct;
131 i_tags_new(&im->tags);
132 im->xsize = x;
133 im->ysize = y;
134 im->channels = ch;
653ea321 135 im->bytes = bytes;
2ce44e2a
TC
136 im->ext_data = NULL;
137 im->idata = mymalloc(im->bytes);
bd8052a6 138 memset(im->idata, 0, im->bytes);
696cb85d 139 im_img_init(aIMCTX, im);
2ce44e2a
TC
140
141 return im;
142}
143
8d14daab
TC
144static int i_ppix_ddoub(i_img *im, i_img_dim x, i_img_dim y, const i_color *val) {
145 i_img_dim off;
146 int ch;
2ce44e2a 147
837a4b43 148 if (x < 0 || x >= im->xsize || y < 0 || y >= im->ysize)
2ce44e2a
TC
149 return -1;
150
151 off = (x + y * im->xsize) * im->channels;
35f40526
TC
152 if (I_ALL_CHANNELS_WRITABLE(im)) {
153 for (ch = 0; ch < im->channels; ++ch)
154 ((double*)im->idata)[off+ch] = Sample8ToF(val->channel[ch]);
155 }
156 else {
157 for (ch = 0; ch < im->channels; ++ch)
158 if (im->ch_mask & (1<<ch))
159 ((double*)im->idata)[off+ch] = Sample8ToF(val->channel[ch]);
160 }
2ce44e2a
TC
161
162 return 0;
163}
164
8d14daab
TC
165static int i_gpix_ddoub(i_img *im, i_img_dim x, i_img_dim y, i_color *val) {
166 i_img_dim off;
167 int ch;
2ce44e2a 168
837a4b43 169 if (x < 0 || x >= im->xsize || y < 0 || y >= im->ysize)
2ce44e2a
TC
170 return -1;
171
172 off = (x + y * im->xsize) * im->channels;
173 for (ch = 0; ch < im->channels; ++ch)
174 val->channel[ch] = SampleFTo8(((double *)im->idata)[off+ch]);
175
176 return 0;
177}
178
8d14daab
TC
179static int i_ppixf_ddoub(i_img *im, i_img_dim x, i_img_dim y, const i_fcolor *val) {
180 i_img_dim off;
181 int ch;
2ce44e2a 182
837a4b43 183 if (x < 0 || x >= im->xsize || y < 0 || y >= im->ysize)
2ce44e2a
TC
184 return -1;
185
186 off = (x + y * im->xsize) * im->channels;
35f40526
TC
187 if (I_ALL_CHANNELS_WRITABLE(im)) {
188 for (ch = 0; ch < im->channels; ++ch)
189 ((double *)im->idata)[off+ch] = val->channel[ch];
190 }
191 else {
192 for (ch = 0; ch < im->channels; ++ch)
193 if (im->ch_mask & (1 << ch))
194 ((double *)im->idata)[off+ch] = val->channel[ch];
195 }
2ce44e2a
TC
196
197 return 0;
198}
199
8d14daab
TC
200static int i_gpixf_ddoub(i_img *im, i_img_dim x, i_img_dim y, i_fcolor *val) {
201 i_img_dim off;
202 int ch;
2ce44e2a 203
837a4b43 204 if (x < 0 || x >= im->xsize || y < 0 || y >= im->ysize)
2ce44e2a
TC
205 return -1;
206
207 off = (x + y * im->xsize) * im->channels;
208 for (ch = 0; ch < im->channels; ++ch)
209 val->channel[ch] = ((double *)im->idata)[off+ch];
210
211 return 0;
212}
213
8d14daab
TC
214static i_img_dim i_glin_ddoub(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_color *vals) {
215 int ch;
216 i_img_dim count, i;
217 i_img_dim off;
2ce44e2a
TC
218 if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
219 if (r > im->xsize)
220 r = im->xsize;
221 off = (l+y*im->xsize) * im->channels;
222 count = r - l;
223 for (i = 0; i < count; ++i) {
224 for (ch = 0; ch < im->channels; ++ch) {
225 vals[i].channel[ch] = SampleFTo8(((double *)im->idata)[off]);
226 ++off;
227 }
228 }
229 return count;
230 }
231 else {
232 return 0;
233 }
234}
235
8d14daab
TC
236static i_img_dim i_plin_ddoub(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, const i_color *vals) {
237 int ch;
238 i_img_dim count, i;
239 i_img_dim off;
2ce44e2a
TC
240 if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
241 if (r > im->xsize)
242 r = im->xsize;
243 off = (l+y*im->xsize) * im->channels;
244 count = r - l;
35f40526
TC
245 if (I_ALL_CHANNELS_WRITABLE(im)) {
246 for (i = 0; i < count; ++i) {
247 for (ch = 0; ch < im->channels; ++ch) {
248 ((double *)im->idata)[off] = Sample8ToF(vals[i].channel[ch]);
249 ++off;
250 }
251 }
252 }
253 else {
254 for (i = 0; i < count; ++i) {
255 for (ch = 0; ch < im->channels; ++ch) {
256 if (im->ch_mask & (1 << ch))
257 ((double *)im->idata)[off] = Sample8ToF(vals[i].channel[ch]);
258 ++off;
259 }
2ce44e2a
TC
260 }
261 }
262 return count;
263 }
264 else {
265 return 0;
266 }
267}
268
8d14daab
TC
269static i_img_dim i_glinf_ddoub(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_fcolor *vals) {
270 int ch;
271 i_img_dim count, i;
272 i_img_dim off;
2ce44e2a
TC
273 if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
274 if (r > im->xsize)
275 r = im->xsize;
276 off = (l+y*im->xsize) * im->channels;
277 count = r - l;
278 for (i = 0; i < count; ++i) {
279 for (ch = 0; ch < im->channels; ++ch) {
280 vals[i].channel[ch] = ((double *)im->idata)[off];
281 ++off;
282 }
283 }
284 return count;
285 }
286 else {
287 return 0;
288 }
289}
290
8d14daab
TC
291static i_img_dim i_plinf_ddoub(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, const i_fcolor *vals) {
292 int ch;
293 i_img_dim count, i;
294 i_img_dim off;
2ce44e2a
TC
295 if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
296 if (r > im->xsize)
297 r = im->xsize;
298 off = (l+y*im->xsize) * im->channels;
299 count = r - l;
35f40526
TC
300 if (I_ALL_CHANNELS_WRITABLE(im)) {
301 for (i = 0; i < count; ++i) {
302 for (ch = 0; ch < im->channels; ++ch) {
303 ((double *)im->idata)[off] = vals[i].channel[ch];
304 ++off;
305 }
306 }
307 }
308 else {
309 for (i = 0; i < count; ++i) {
310 for (ch = 0; ch < im->channels; ++ch) {
311 if (im->ch_mask & (1 << ch))
312 ((double *)im->idata)[off] = vals[i].channel[ch];
313 ++off;
314 }
2ce44e2a
TC
315 }
316 }
317 return count;
318 }
319 else {
320 return 0;
321 }
322}
323
8d14daab 324static i_img_dim i_gsamp_ddoub(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_sample_t *samps,
18accb2a 325 int const *chans, int chan_count) {
8d14daab
TC
326 int ch;
327 i_img_dim count, i, w;
328 i_img_dim off;
2ce44e2a
TC
329
330 if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
331 if (r > im->xsize)
332 r = im->xsize;
333 off = (l+y*im->xsize) * im->channels;
334 w = r - l;
335 count = 0;
336
337 if (chans) {
338 /* make sure we have good channel numbers */
339 for (ch = 0; ch < chan_count; ++ch) {
340 if (chans[ch] < 0 || chans[ch] >= im->channels) {
696cb85d
TC
341 dIMCTXim(im);
342 im_push_errorf(aIMCTX, 0, "No channel %d in this image", chans[ch]);
2ce44e2a
TC
343 return 0;
344 }
345 }
346 for (i = 0; i < w; ++i) {
347 for (ch = 0; ch < chan_count; ++ch) {
348 *samps++ = SampleFTo8(((double *)im->idata)[off+chans[ch]]);
349 ++count;
350 }
351 off += im->channels;
352 }
353 }
354 else {
c7481ae1 355 if (chan_count <= 0 || chan_count > im->channels) {
696cb85d
TC
356 dIMCTXim(im);
357 im_push_errorf(aIMCTX, 0, "chan_count %d out of range, must be >0, <= channels",
c7481ae1
TC
358 chan_count);
359 return 0;
360 }
2ce44e2a
TC
361 for (i = 0; i < w; ++i) {
362 for (ch = 0; ch < chan_count; ++ch) {
363 *samps++ = SampleFTo8(((double *)im->idata)[off+ch]);
364 ++count;
365 }
366 off += im->channels;
367 }
368 }
369
370 return count;
371 }
372 else {
373 return 0;
374 }
375}
376
8d14daab 377static i_img_dim i_gsampf_ddoub(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, i_fsample_t *samps,
18accb2a 378 int const *chans, int chan_count) {
8d14daab
TC
379 int ch;
380 i_img_dim count, i, w;
381 i_img_dim off;
2ce44e2a
TC
382
383 if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
384 if (r > im->xsize)
385 r = im->xsize;
386 off = (l+y*im->xsize) * im->channels;
387 w = r - l;
388 count = 0;
389
390 if (chans) {
391 /* make sure we have good channel numbers */
392 for (ch = 0; ch < chan_count; ++ch) {
393 if (chans[ch] < 0 || chans[ch] >= im->channels) {
696cb85d
TC
394 dIMCTXim(im);
395 im_push_errorf(aIMCTX, 0, "No channel %d in this image", chans[ch]);
2ce44e2a
TC
396 return 0;
397 }
398 }
399 for (i = 0; i < w; ++i) {
400 for (ch = 0; ch < chan_count; ++ch) {
401 *samps++ = ((double *)im->idata)[off+chans[ch]];
402 ++count;
403 }
404 off += im->channels;
405 }
406 }
407 else {
c7481ae1 408 if (chan_count <= 0 || chan_count > im->channels) {
696cb85d
TC
409 dIMCTXim(im);
410 im_push_errorf(aIMCTX, 0, "chan_count %d out of range, must be >0, <= channels",
c7481ae1
TC
411 chan_count);
412 return 0;
413 }
2ce44e2a
TC
414 for (i = 0; i < w; ++i) {
415 for (ch = 0; ch < chan_count; ++ch) {
416 *samps++ = ((double *)im->idata)[off+ch];
417 ++count;
418 }
419 off += im->channels;
420 }
421 }
422
423 return count;
424 }
425 else {
426 return 0;
427 }
428}
429
836d9f54
TC
430/*
431=item i_psamp_ddoub(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, const i_sample_t *samps, int *chans, int chan_count)
432
433Writes sample values to im for the horizontal line (l, y) to (r-1,y)
434for the channels specified by chans, an array of int with chan_count
435elements.
436
437Returns the number of samples written (which should be (r-l) *
438bits_set(chan_mask)
439
440=cut
441*/
442
443static
444i_img_dim
445i_psamp_ddoub(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y,
446 const i_sample_t *samps, const int *chans, int chan_count) {
447 int ch;
448 i_img_dim count, i, w;
449
450 if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
836d9f54
TC
451 i_img_dim offset;
452 if (r > im->xsize)
453 r = im->xsize;
454 offset = (l+y*im->xsize) * im->channels;
455 w = r - l;
456 count = 0;
457
458 if (chans) {
459 /* make sure we have good channel numbers */
460 /* and test if all channels specified are in the mask */
461 int all_in_mask = 1;
462 for (ch = 0; ch < chan_count; ++ch) {
463 if (chans[ch] < 0 || chans[ch] >= im->channels) {
696cb85d 464 dIMCTXim(im);
3f5b6dcc 465 im_push_errorf(aIMCTX, 0, "No channel %d in this image", chans[ch]);
836d9f54
TC
466 return -1;
467 }
468 if (!((1 << chans[ch]) & im->ch_mask))
469 all_in_mask = 0;
470 }
471 if (all_in_mask) {
472 for (i = 0; i < w; ++i) {
473 for (ch = 0; ch < chan_count; ++ch) {
474 ((double*)im->idata)[offset + chans[ch]] = Sample8ToF(*samps);
475 ++samps;
476 ++count;
477 }
478 offset += im->channels;
479 }
480 }
481 else {
482 for (i = 0; i < w; ++i) {
483 for (ch = 0; ch < chan_count; ++ch) {
484 if (im->ch_mask & (1 << (chans[ch])))
485 ((double*)im->idata)[offset + chans[ch]] = Sample8ToF(*samps);
486
487 ++samps;
488 ++count;
489 }
490 offset += im->channels;
491 }
492 }
493 }
494 else {
495 if (chan_count <= 0 || chan_count > im->channels) {
696cb85d
TC
496 dIMCTXim(im);
497 im_push_errorf(aIMCTX, 0, "chan_count %d out of range, must be >0, <= channels",
836d9f54
TC
498 chan_count);
499 return -1;
500 }
501 for (i = 0; i < w; ++i) {
502 unsigned mask = 1;
503 for (ch = 0; ch < chan_count; ++ch) {
504 if (im->ch_mask & mask)
505 ((double*)im->idata)[offset + ch] = Sample8ToF(*samps);
506
507 ++samps;
508 ++count;
509 mask <<= 1;
510 }
511 offset += im->channels;
512 }
513 }
514
515 return count;
516 }
517 else {
696cb85d 518 dIMCTXim(im);
836d9f54
TC
519 i_push_error(0, "Image position outside of image");
520 return -1;
521 }
522}
523
524/*
525=item i_psampf_ddoub(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, const i_fsample_t *samps, int *chans, int chan_count)
526
527Writes sample values to im for the horizontal line (l, y) to (r-1,y)
528for the channels specified by chans, an array of int with chan_count
529elements.
530
531Returns the number of samples written (which should be (r-l) *
532bits_set(chan_mask)
533
534=cut
535*/
536
537static
538i_img_dim
539i_psampf_ddoub(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y,
540 const i_fsample_t *samps, const int *chans, int chan_count) {
541 int ch;
542 i_img_dim count, i, w;
543
544 if (y >=0 && y < im->ysize && l < im->xsize && l >= 0) {
836d9f54
TC
545 i_img_dim offset;
546 if (r > im->xsize)
547 r = im->xsize;
548 offset = (l+y*im->xsize) * im->channels;
549 w = r - l;
550 count = 0;
551
552 if (chans) {
553 /* make sure we have good channel numbers */
554 /* and test if all channels specified are in the mask */
555 int all_in_mask = 1;
556 for (ch = 0; ch < chan_count; ++ch) {
557 if (chans[ch] < 0 || chans[ch] >= im->channels) {
696cb85d
TC
558 dIMCTXim(im);
559 im_push_errorf(aIMCTX, 0, "No channel %d in this image", chans[ch]);
836d9f54
TC
560 return -1;
561 }
562 if (!((1 << chans[ch]) & im->ch_mask))
563 all_in_mask = 0;
564 }
565 if (all_in_mask) {
566 for (i = 0; i < w; ++i) {
567 for (ch = 0; ch < chan_count; ++ch) {
568 ((double*)im->idata)[offset + chans[ch]] = *samps;
569 ++samps;
570 ++count;
571 }
572 offset += im->channels;
573 }
574 }
575 else {
576 for (i = 0; i < w; ++i) {
577 for (ch = 0; ch < chan_count; ++ch) {
578 if (im->ch_mask & (1 << (chans[ch])))
579 ((double*)im->idata)[offset + chans[ch]] = *samps;
580
581 ++samps;
582 ++count;
583 }
584 offset += im->channels;
585 }
586 }
587 }
588 else {
589 if (chan_count <= 0 || chan_count > im->channels) {
696cb85d
TC
590 dIMCTXim(im);
591 im_push_errorf(aIMCTX, 0, "chan_count %d out of range, must be >0, <= channels",
836d9f54
TC
592 chan_count);
593 return -1;
594 }
595 for (i = 0; i < w; ++i) {
596 unsigned mask = 1;
597 for (ch = 0; ch < chan_count; ++ch) {
598 if (im->ch_mask & mask)
599 ((double*)im->idata)[offset + ch] = *samps;
600
601 ++samps;
602 ++count;
603 mask <<= 1;
604 }
605 offset += im->channels;
606 }
607 }
608
609 return count;
610 }
611 else {
696cb85d 612 dIMCTXim(im);
836d9f54
TC
613 i_push_error(0, "Image position outside of image");
614 return -1;
615 }
616}
617
bfe6ba3f
TC
618/*
619=item i_img_to_drgb(im)
620
621=category Image creation
622
623Returns a double/sample version of the supplied image.
624
625Returns the image on success, or NULL on failure.
626
627=cut
628*/
629
630i_img *
631i_img_to_drgb(i_img *im) {
632 i_img *targ;
633 i_fcolor *line;
8d14daab 634 i_img_dim y;
696cb85d 635 dIMCTXim(im);
bfe6ba3f 636
696cb85d 637 targ = im_img_double_new(aIMCTX, im->xsize, im->ysize, im->channels);
bfe6ba3f
TC
638 if (!targ)
639 return NULL;
640 line = mymalloc(sizeof(i_fcolor) * im->xsize);
641 for (y = 0; y < im->ysize; ++y) {
642 i_glinf(im, 0, im->xsize, y, line);
643 i_plinf(targ, 0, im->xsize, y, line);
644 }
645
646 myfree(line);
647
648 return targ;
649}
b8c2033e
AMH
650
651/*
652=back
653
654=head1 AUTHOR
655
656Tony Cook <tony@develop-help.com>
657
658=head1 SEE ALSO
659
660Imager(3)
661
662=cut
663*/