1 /* read and write masks
2 */
3
4 /* Copyright: 1990, N. Dessipris.
5 *
6 * Author: Nicos Dessipris
7 * Written on: 29/04/1991
8 * Modified on: 10/8/1992, J.Cupitt
9 * - Mask reading routines no longer fail if scale and offset are missing.
10 * Instead, they set default values of scale=1, offset=0.
11 * - Code tidied up, better error recovery.
12 * - Bugs fixed in im_dup_*mask. No longer coredump.
13 * - Bugs fixed in im_write_*mask. Now work for non-square matricies.
14 * - im_copy_*mask_matrix, im_copy_matrix_*mask added: copy VIPS mask
15 * structures into Numerical Recipies in C style matricies and vice
16 * versa. Both structures should have been built before copy attempted.
17 * See im_create_*mask, im_*mat_alloc. The matrix should be indexed by 0
18 * to size-1.
19 * 9/7/93 JC
20 * - some ANSIfication and tidies
21 * - im_free_*mask() now return zero, so they can be used as close
22 * callbacks.
23 * 7/10/94 JC
24 * - new IM_NEW(), IM_ARRAY() macros added
25 * 27/4/95 JC
26 * - oops! forgot to init IM_ARRAY() memory to zero
27 * 7/8/96 JC
28 * - im_scale_dmask() rewritten
29 * 7/5/98 JC
30 * - im_read_*mask() rewritten, now more robust
31 * - im_write_*mask() rewritten
32 * - new functions im_write_*mask_name()
33 * 28/7/99 JC
34 * - im_create_imaskv(), im_create_dmaskv() make masks and init from
35 * varargs
36 * - tabs allowed as column separators
37 * 9/2/05
38 * - "," allowed as column separator ... helps CSV read
39 * 31/5/06
40 * - use g_ascii_strtod() and friends
41 * 2006-09-08 tcv
42 * - add im_norm_dmask()
43 * 1/9/09
44 * - move im_print_*mask() here
45 * 12/11/09
46 * - reading a float mask with im_read_imask() produced an incorrect
47 * error messagge
48 * 21/10/10
49 * - gtk-doc
50 * - you can use commas to separate header fields
51 * - small cleanups
52 * 30/11/10
53 * - im_scale_dmask() normalises to 20, not 100 ... we hit the fast
54 * conv path more often
55 * 24/1/10
56 * - oops, missing braces in write dmask removed spaces between items
57 */
58
59 /*
60
61 This file is part of VIPS.
62
63 VIPS is free software; you can redistribute it and/or modify
64 it under the terms of the GNU Lesser General Public License as published by
65 the Free Software Foundation; either version 2 of the License, or
66 (at your option) any later version.
67
68 This program is distributed in the hope that it will be useful,
69 but WITHOUT ANY WARRANTY; without even the implied warranty of
70 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
71 GNU Lesser General Public License for more details.
72
73 You should have received a copy of the GNU Lesser General Public License
74 along with this program; if not, write to the Free Software
75 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
76 02110-1301 USA
77
78 */
79
80 /*
81
82 These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
83
84 */
85
86 #ifdef HAVE_CONFIG_H
87 #include <config.h>
88 #endif /*HAVE_CONFIG_H*/
89 #include <vips/intl.h>
90
91 #include <stdio.h>
92 #include <stdlib.h>
93 #include <stdarg.h>
94 #include <string.h>
95 #include <math.h>
96
97 #include <vips/vips.h>
98 #include <vips/vips7compat.h>
99
100 /**
101 * INTMASK:
102 * @xsize: mask width
103 * @ysize: mask height
104 * @scale: mask scale factor
105 * @offset: mask offset
106 * @coeff: array of mask elements
107 * @filename: the file this mask was read from, or should be written to
108 *
109 * An integer mask.
110 *
111 * @scale lets the mask represent fractional values: for
112 * example, in integer convolution (see im_conv()) the result of the
113 * convolution is divided by @scale and then added to @offset before being
114 * written to the output image.
115 *
116 * @scale and @offset default to 1 and 0. Various functions, such as
117 * im_conv(), will fail if @scale is zero.
118 *
119 * You can read and write the matrix elements in @coeff.
120 */
121
122 /**
123 * DOUBLEMASK:
124 * @xsize: mask width
125 * @ysize: mask height
126 * @scale: mask scale factor
127 * @offset: mask offset
128 * @coeff: array of mask elements
129 * @filename: the file this mask was read from, or should be written to
130 *
131 * A floating-point mask.
132 *
133 * As with #INTMASK, in convolution (see im_convf()) the result of the
134 * convolution is divided by @scale and then added to @offset before being
135 * written to the output image.
136 *
137 * @scale and @offset default to 1.0 and 0.0. Various functions, such as
138 * im_conv(), will fail if @scale is zero.
139 *
140 * You can read and write the matrix elements in @coeff.
141 */
142
143 /* Size of line buffer for reading.
144 */
145 #define MAX_LINE (32768)
146
147 /**
148 * im_free_imask:
149 * @in: mask to free
150 *
151 * Free mask structure and any attached arrays. Return zero, so we can use
152 * these functions as close callbacks.
153 *
154 * See also: im_free_dmask().
155 *
156 * Returns: zero.
157 */
158 int
im_free_imask(INTMASK * in)159 im_free_imask( INTMASK *in )
160 {
161 if( !in )
162 return( 0 );
163
164 IM_FREE( in->coeff );
165 IM_FREE( in->filename );
166 IM_FREE( in );
167
168 return( 0 );
169 }
170
171 /**
172 * im_free_dmask:
173 * @in: mask to free
174 *
175 * Free mask structure and any attached arrays. Return zero, so we can use
176 * these functions as close callbacks.
177 *
178 * See also: im_free_dmask().
179 *
180 * Returns: zero.
181 */
182 int
im_free_dmask(DOUBLEMASK * in)183 im_free_dmask( DOUBLEMASK *in )
184 {
185 if( !in )
186 return( 0 );
187
188 IM_FREE( in->coeff );
189 IM_FREE( in->filename );
190 IM_FREE( in );
191
192 return( 0 );
193 }
194
195 /**
196 * im_create_imask:
197 * @filename: set mask filename to this
198 * @xsize: mask width
199 * @ysize: mask height
200 *
201 * Create an empty imask. You need to loop over @coeff to set the values.
202 *
203 * See also: im_create_imaskv().
204 *
205 * Returns: The newly-allocated mask.
206 */
207 INTMASK *
im_create_imask(const char * filename,int xsize,int ysize)208 im_create_imask( const char *filename, int xsize, int ysize )
209 {
210 INTMASK *out;
211 int size = xsize * ysize;
212
213 /* Check args.
214 */
215 if( xsize <= 0 || ysize <= 0 || filename == NULL ) {
216 im_error( "im_create_imask", "%s", _( "bad arguments" ) );
217 return( NULL );
218 }
219
220 /* Allocate and initialise structure.
221 */
222 if( !(out = IM_NEW( NULL, INTMASK )) )
223 return( NULL );
224 out->coeff = NULL;
225 out->filename = NULL;
226 out->scale = 1;
227 out->offset = 0;
228 out->xsize = 0;
229 out->ysize = 0;
230
231 if( !(out->coeff = IM_ARRAY( NULL, size, int )) ) {
232 im_free_imask( out );
233 return( NULL );
234 }
235 (void) memset( (char *) out->coeff, 0, size * sizeof( int ) );
236 if( !(out->filename = im_strdup( NULL, filename )) ) {
237 im_free_imask( out );
238 return( NULL );
239 }
240 out->xsize = xsize;
241 out->ysize = ysize;
242
243 return( out );
244 }
245
246 /**
247 * im_create_imaskv:
248 * @filename: set mask filename to this
249 * @xsize: mask width
250 * @ysize: mask height
251 * @...: values to set for the mask
252 *
253 * Create an imask and initialise it from the function parameter list.
254 *
255 * See also: im_create_imask().
256 *
257 * Returns: The newly-allocated mask.
258 */
259 INTMASK *
im_create_imaskv(const char * filename,int xsize,int ysize,...)260 im_create_imaskv( const char *filename, int xsize, int ysize, ... )
261 {
262 va_list ap;
263
264 INTMASK *out;
265 int i;
266
267 if( !(out = im_create_imask( filename, xsize, ysize )) )
268 return( NULL );
269
270 va_start( ap, ysize );
271 for( i = 0; i < xsize * ysize; i++ )
272 out->coeff[i] = va_arg( ap, int );
273 va_end( ap );
274
275 return( out );
276 }
277
278 /**
279 * im_create_dmask:
280 * @filename: set mask filename to this
281 * @xsize: mask width
282 * @ysize: mask height
283 *
284 * Create an empty dmask. You need to loop over @coeff to set the values.
285 *
286 * See also: im_create_dmaskv(), im_vips2mask().
287 *
288 * Returns: The newly-allocated mask.
289 */
290 DOUBLEMASK *
im_create_dmask(const char * filename,int xsize,int ysize)291 im_create_dmask( const char *filename, int xsize, int ysize )
292 {
293 DOUBLEMASK *out;
294 int size = xsize * ysize;
295
296 /* Check args.
297 */
298 if( xsize <= 0 || ysize <= 0 || filename == NULL ) {
299 im_error( "im_create_dmask", "%s", _( "bad arguments" ) );
300 return( NULL );
301 }
302
303 /* Allocate and initialise structure.
304 */
305 if( !(out = IM_NEW( NULL, DOUBLEMASK )) )
306 return( NULL );
307 out->coeff = NULL;
308 out->filename = NULL;
309 out->scale = 1.0;
310 out->offset = 0.0;
311 out->xsize = 0;
312 out->ysize = 0;
313
314 if( !(out->coeff = IM_ARRAY( NULL, size, double )) ) {
315 im_free_dmask( out );
316 return( NULL );
317 }
318 (void) memset( (char *) out->coeff, 0, size * sizeof( double ) );
319 if( !(out->filename = im_strdup( NULL, filename )) ) {
320 im_free_dmask( out );
321 return( NULL );
322 }
323 out->xsize = xsize;
324 out->ysize = ysize;
325
326 return( out );
327 }
328
329 /**
330 * im_create_dmaskv:
331 * @filename: set mask filename to this
332 * @xsize: mask width
333 * @ysize: mask height
334 * @...: values to set for the mask
335 *
336 * Create a dmask and initialise it from the function parameter list.
337 *
338 * See also: im_create_dmask().
339 *
340 * Returns: The newly-allocated mask.
341 */
342 DOUBLEMASK *
im_create_dmaskv(const char * filename,int xsize,int ysize,...)343 im_create_dmaskv( const char *filename, int xsize, int ysize, ... )
344 {
345 va_list ap;
346
347 DOUBLEMASK *out;
348 int i;
349
350 if( !(out = im_create_dmask( filename, xsize, ysize )) )
351 return( NULL );
352
353 va_start( ap, ysize );
354 for( i = 0; i < xsize * ysize; i++ )
355 out->coeff[i] = va_arg( ap, double );
356 va_end( ap );
357
358 return( out );
359 }
360
361 /* Read a line from a file!
362 */
363 static int
get_line(FILE * fp,char * buf)364 get_line( FILE *fp, char *buf )
365 {
366 if( !fgets( buf, MAX_LINE, fp ) ) {
367 im_error( "read_mask", "%s", _( "unexpected EOF" ) );
368 return( -1 );
369 }
370
371 return( 0 );
372 }
373
374 /* width, height, optional scale, optional offset.
375 */
376 static int
read_header(FILE * fp,int * xs,int * ys,double * scale,double * offset)377 read_header( FILE *fp, int *xs, int *ys, double *scale, double *offset )
378 {
379 char buf[MAX_LINE];
380 char *p, *q;
381 double v[4];
382 int i;
383
384 /* Read the first line: should contain size and optional
385 * scale + offset.
386 */
387 if( get_line( fp, buf ) )
388 return( -1 );
389
390 /* Read as space separated doubles. \n is in the break list because
391 * our line will (usually) have a trailing \n which we want to count
392 * as whitespace.
393 */
394 p = buf;
395 for( i = 0, p = buf;
396 i < 4 && (q = im_break_token( p, " \";,\t\n" ));
397 i++, p = q )
398 v[i] = g_ascii_strtod( p, NULL );
399
400 if( (i != 2 && i != 4) ||
401 ceil( v[0] ) != v[0] ||
402 ceil( v[1] ) != v[1] ||
403 v[0] <= 0 ||
404 v[1] <= 0 ) {
405 im_error( "read_header",
406 "%s", _( "error reading matrix header" ) );
407 return( -1 );
408 }
409 if( i == 4 && v[2] == 0 ) {
410 im_error( "read_header",
411 "%s", _( "scale should be non-zero" ) );
412 return( -1 );
413 }
414
415 *xs = v[0];
416 *ys = v[1];
417 if( i == 2 ) {
418 *scale = 1.0;
419 *offset = 0.0;
420 }
421 else {
422 *scale = v[2];
423 *offset = v[3];
424 }
425
426 return( 0 );
427 }
428
429 /**
430 * im_read_dmask:
431 * @filename: read matrix from this file
432 *
433 * Reads a matrix from a file.
434 *
435 * Matrix files have a simple format that's supposed to be easy to create with
436 * a text editor or a spreadsheet.
437 *
438 * The first line has four numbers for width, height, scale and
439 * offset (scale and offset may be omitted, in which case they default to 1.0
440 * and 0.0). Scale must be non-zero. Width and height must be positive
441 * integers. The numbers are separated by any mixture of spaces, commas,
442 * tabs and quotation marks ("). The scale and offset fields may be
443 * floating-point, and must use '.'
444 * as a decimal separator.
445 *
446 * Subsequent lines each hold one line of matrix data, with numbers again
447 * separated by any mixture of spaces, commas,
448 * tabs and quotation marks ("). The numbers may be floating-point, and must
449 * use '.'
450 * as a decimal separator.
451 *
452 * Extra characters at the ends of lines or at the end of the file are
453 * ignored.
454 *
455 * See also: im_read_imask(), im_gauss_dmask().
456 *
457 * Returns: the loaded mask on success, or NULL on error.
458 */
459 DOUBLEMASK *
im_read_dmask(const char * filename)460 im_read_dmask( const char *filename )
461 {
462 FILE *fp;
463 double sc, off;
464 int xs, ys;
465 DOUBLEMASK *out;
466 int x, y, i;
467 char buf[MAX_LINE];
468
469 if( !(fp = im__file_open_read( filename, NULL, TRUE )) )
470 return( NULL );
471
472 if( read_header( fp, &xs, &ys, &sc, &off ) ) {
473 fclose( fp );
474 return( NULL );
475 }
476
477 if( !(out = im_create_dmask( filename, xs, ys )) ) {
478 fclose( fp );
479 return( NULL );
480 }
481 out->scale = sc;
482 out->offset = off;
483
484 for( i = 0, y = 0; y < ys; y++ ) {
485 char *p;
486
487 if( get_line( fp, buf ) ) {
488 im_free_dmask( out );
489 fclose( fp );
490 return( NULL );
491 }
492
493 for( p = buf, x = 0; p && x < xs;
494 x++, i++, p = im_break_token( p, " \t,\";" ) )
495 out->coeff[i] = g_ascii_strtod( p, NULL );
496 }
497 fclose( fp );
498
499 return( out );
500 }
501
502 /**
503 * im_read_imask:
504 * @filename: read matrix from this file
505 *
506 * Reads an integer matrix from a file.
507 *
508 * This function works exactly as im_read_dmask(), but the loaded matrix is
509 * checked for 'int-ness'. All coefficients must be integers, and scale and
510 * offset must be integers.
511 *
512 * See also: im_read_dmask().
513 *
514 * Returns: the loaded mask on success, or NULL on error.
515 */
516 INTMASK *
im_read_imask(const char * filename)517 im_read_imask( const char *filename )
518 {
519 DOUBLEMASK *dmask;
520 INTMASK *imask;
521 int i;
522
523 if( !(dmask = im_read_dmask( filename )) )
524 return( NULL );
525
526 if( ceil( dmask->scale ) != dmask->scale ||
527 ceil( dmask->offset ) != dmask->offset ) {
528 im_error( "im_read_imask",
529 "%s", _( "scale and offset should be int" ) );
530 im_free_dmask( dmask );
531
532 return( NULL );
533 }
534
535 for( i = 0; i < dmask->xsize * dmask->ysize; i++ )
536 if( ceil( dmask->coeff[i] ) != dmask->coeff[i] ) {
537 im_error( "im_read_imask", _( "ceofficient at "
538 "position (%d, %d) is not int" ),
539 i % dmask->xsize,
540 i / dmask->xsize );
541 im_free_dmask( dmask );
542
543 return( NULL );
544 }
545
546 if( !(imask = im_create_imask( filename,
547 dmask->xsize, dmask->ysize )) ) {
548 im_free_dmask( dmask );
549 return( NULL );
550 }
551 imask->scale = dmask->scale;
552 imask->offset = dmask->offset;
553 for( i = 0; i < dmask->xsize * dmask->ysize; i++ )
554 imask->coeff[i] = dmask->coeff[i];
555
556 im_free_dmask( dmask );
557
558 return( imask );
559 }
560
561 /**
562 * im_scale_dmask:
563 * @in: mask to scale
564 * @filename: filename for returned mask
565 *
566 * Scale the dmask to make an imask with a maximum value of 20.
567 *
568 * See also: im_norm_dmask().
569 *
570 * Returns: the converted mask, or NULL on error.
571 */
572 INTMASK *
im_scale_dmask(DOUBLEMASK * in,const char * filename)573 im_scale_dmask( DOUBLEMASK *in, const char *filename )
574 {
575 const int size = in->xsize * in->ysize;
576
577 INTMASK *out;
578 double maxval, dsum;
579 int i;
580 int isum;
581
582 if( im_check_dmask( "im_scale_dmask", in ) ||
583 !(out = im_create_imask( filename, in->xsize, in->ysize )) )
584 return( NULL );
585
586 /* Find mask max.
587 */
588 maxval = in->coeff[0];
589 for( i = 0; i < size; i++ )
590 if( in->coeff[i] > maxval )
591 maxval = in->coeff[i];
592
593 /* Copy and scale, setting max to 20.
594 */
595 for( i = 0; i < size; i++ )
596 out->coeff[i] = IM_RINT( in->coeff[i] * 20.0 / maxval );
597 out->offset = in->offset;
598
599 /* Set the scale to match the adjustment to max.
600 */
601 isum = 0;
602 dsum = 0.0;
603 for( i = 0; i < size; i++ ) {
604 isum += out->coeff[i];
605 dsum += in->coeff[i];
606 }
607
608 if( dsum == in->scale )
609 out->scale = isum;
610 else if( dsum == 0.0 )
611 out->scale = 1.0;
612 else
613 out->scale = IM_RINT( in->scale * isum / dsum );
614
615 return( out );
616 }
617
618 /**
619 * im_dmask2imask:
620 * @in: mask to convert
621 * @filename: filename for returned mask
622 *
623 * Make an imask from the dmask, rounding to nearest.
624 *
625 * See also: im_scale_dmask().
626 *
627 * Returns: the converted mask, or NULL on error.
628 */
629 INTMASK *
im_dmask2imask(DOUBLEMASK * in,const char * filename)630 im_dmask2imask( DOUBLEMASK *in, const char *filename )
631 {
632 const int size = in->xsize * in->ysize;
633
634 INTMASK *out;
635 int i;
636
637 if( im_check_dmask( "im_dmask2imask", in ) ||
638 !(out = im_create_imask( filename, in->xsize, in->ysize )) )
639 return( NULL );
640
641 for( i = 0; i < size; i++ )
642 out->coeff[i] = IM_RINT( in->coeff[i] );
643 out->offset = IM_RINT( in->offset );
644 out->scale = IM_RINT( in->scale );
645
646 return( out );
647 }
648
649 /**
650 * im_imask2dmask:
651 * @in: mask to convert
652 * @filename: filename for returned mask
653 *
654 * Make a dmask from the imask.
655 *
656 * See also: im_dmask2imask().
657 *
658 * Returns: the converted mask, or NULL on error.
659 */
660 DOUBLEMASK *
im_imask2dmask(INTMASK * in,const char * filename)661 im_imask2dmask( INTMASK *in, const char *filename )
662 {
663 const int size = in->xsize * in->ysize;
664
665 DOUBLEMASK *out;
666 int i;
667
668 if( im_check_imask( "im_imask2dmask", in ) ||
669 !(out = im_create_dmask( filename, in->xsize, in->ysize )) )
670 return( NULL );
671
672 for( i = 0; i < size; i++ )
673 out->coeff[i] = in->coeff[i];
674 out->offset = in->offset;
675 out->scale = in->scale;
676
677 return( out );
678 }
679
680 /**
681 * im_norm_dmask:
682 * @mask: mask to scale
683 *
684 * Normalise the dmask. Apply the scale and offset to each element to make
685 * a mask with scale 1, offset zero.
686 *
687 * See also: im_scale_dmask().
688 *
689 * Returns: 0 on success, or -1 on error.
690 */
691 void
im_norm_dmask(DOUBLEMASK * mask)692 im_norm_dmask( DOUBLEMASK *mask )
693 {
694 const int n = mask->xsize * mask->ysize;
695 const double scale = (mask->scale == 0) ? 0 : (1.0 / mask->scale);
696
697 int i;
698
699 if( im_check_dmask( "im_norm_dmask", mask ) ||
700 (1.0 == scale && 0.0 == mask->offset) )
701 return;
702
703 for( i = 0; i < n; i++ )
704 mask->coeff[i] = mask->coeff[i] * scale + mask->offset;
705
706 mask->scale = 1.0;
707 mask->offset = 0.0;
708 }
709
710 /**
711 * im_dup_imask:
712 * @in: mask to duplicate
713 * @filename: filename to set for the new mask
714 *
715 * Duplicate an imask.
716 *
717 * See also: im_dup_dmask().
718 *
719 * Returns: the mask copy, or NULL on error.
720 */
721 INTMASK *
im_dup_imask(INTMASK * in,const char * filename)722 im_dup_imask( INTMASK *in, const char *filename )
723 {
724 INTMASK *out;
725 int i;
726
727 if( im_check_imask( "im_dup_imask", in ) ||
728 !(out = im_create_imask( filename, in->xsize, in->ysize )) )
729 return( NULL );
730
731 out->offset = in->offset;
732 out->scale = in->scale;
733
734 for( i = 0; i < in->xsize * in->ysize; i++ )
735 out->coeff[i] = in->coeff[i];
736
737 return( out );
738 }
739
740 /**
741 * im_dup_dmask:
742 * @in: mask to duplicate
743 * @filename: filename to set for the new mask
744 *
745 * Duplicate a dmask.
746 *
747 * See also: im_dup_imask().
748 *
749 * Returns: the mask copy, or NULL on error.
750 */
751 DOUBLEMASK *
im_dup_dmask(DOUBLEMASK * in,const char * filename)752 im_dup_dmask( DOUBLEMASK *in, const char *filename )
753 {
754 DOUBLEMASK *out;
755 int i;
756
757 if( im_check_dmask( "im_dup_dmask", in ) ||
758 !(out = im_create_dmask( filename, in->xsize, in->ysize )) )
759 return( NULL );
760
761 out->offset = in->offset;
762 out->scale = in->scale;
763
764 for( i = 0; i < in->xsize * in->ysize; i++ )
765 out->coeff[i] = in->coeff[i];
766
767 return( out );
768 }
769
770 /* Write to file.
771 */
772 static int
write_line(FILE * fp,const char * fmt,...)773 write_line( FILE *fp, const char *fmt, ... )
774 {
775 va_list ap;
776
777 va_start( ap, fmt );
778 if( !vfprintf( fp, fmt, ap ) ) {
779 im_error( "write_mask", "%s", _( "write error, disc full?" ) );
780 return( -1 );
781 }
782 va_end( ap );
783
784 return( 0 );
785 }
786
787 static int
write_double(FILE * fp,double d)788 write_double( FILE *fp, double d )
789 {
790 char buf[G_ASCII_DTOSTR_BUF_SIZE];
791
792 fprintf( fp, "%s", g_ascii_dtostr( buf, sizeof( buf ), d ) );
793
794 return( 0 );
795 }
796
797 /**
798 * im_write_imask_name:
799 * @in: mask to write
800 * @filename: filename to write to
801 *
802 * Write an imask to a file. See im_read_dmask() for a description of the mask
803 * file format.
804 *
805 * See also: im_write_imask().
806 *
807 * Returns: 0 on success, or -1 on error.
808 */
809 int
im_write_imask_name(INTMASK * in,const char * filename)810 im_write_imask_name( INTMASK *in, const char *filename )
811 {
812 FILE *fp;
813 int x, y, i;
814
815 if( im_check_imask( "im_write_imask_name", in ) ||
816 !(fp = im__file_open_write( filename, TRUE )) )
817 return( -1 );
818
819 if( write_line( fp, "%d %d", in->xsize, in->ysize ) ) {
820 fclose( fp );
821 return( -1 );
822 }
823 if( in->scale != 1 || in->offset != 0 )
824 write_line( fp, " %d %d", in->scale, in->offset );
825 write_line( fp, "\n" );
826
827 for( i = 0, y = 0; y < in->ysize; y++ ) {
828 for( x = 0; x < in->xsize; x++, i++ )
829 write_line( fp, "%d ", in->coeff[i] );
830
831 if( write_line( fp, "\n" ) ) {
832 fclose( fp );
833 return( -1 );
834 }
835 }
836 fclose( fp );
837
838 return( 0 );
839 }
840
841 /**
842 * im_write_imask:
843 * @in: mask to write
844 *
845 * Write an imask to a file.
846 *
847 * See also: im_write_imask_name().
848 *
849 * Returns: 0 on success, or -1 on error.
850 */
851 int
im_write_imask(INTMASK * in)852 im_write_imask( INTMASK *in )
853 {
854 if( !in->filename ) {
855 im_error( "im_write_imask", "%s", _( "filename not set" ) );
856 return( -1 );
857 }
858
859 return( im_write_imask_name( in, in->filename ) );
860 }
861
862 /**
863 * im_write_dmask_name:
864 * @in: mask to write
865 * @filename: filename to write to
866 *
867 * Write a dmask to a file. See im_read_dmask() for a description of the mask
868 * file format.
869 *
870 * See also: im_write_dmask().
871 *
872 * Returns: 0 on success, or -1 on error.
873 */
874 int
im_write_dmask_name(DOUBLEMASK * in,const char * filename)875 im_write_dmask_name( DOUBLEMASK *in, const char *filename )
876 {
877 FILE *fp;
878 int x, y, i;
879
880 if( im_check_dmask( "im_write_dmask_name", in ) ||
881 !(fp = im__file_open_write( filename, TRUE )) )
882 return( -1 );
883
884 if( write_line( fp, "%d %d", in->xsize, in->ysize ) ) {
885 fclose( fp );
886 return( -1 );
887 }
888 if( in->scale != 1.0 || in->offset != 0.0 ) {
889 write_line( fp, " " );
890 write_double( fp, in->scale );
891 write_line( fp, " " );
892 write_double( fp, in->offset );
893 }
894 write_line( fp, "\n" );
895
896 for( i = 0, y = 0; y < in->ysize; y++ ) {
897 for( x = 0; x < in->xsize; x++, i++ ) {
898 write_double( fp, in->coeff[i] );
899 write_line( fp, " " );
900 }
901
902 if( write_line( fp, "\n" ) ) {
903 fclose( fp );
904 return( -1 );
905 }
906 }
907 fclose( fp );
908
909 return( 0 );
910 }
911
912 /**
913 * im_write_dmask:
914 * @in: mask to write
915 *
916 * Write a dmask to a file. See im_read_dmask() for a description of the mask
917 * file format.
918 *
919 * See also: im_write_dmask_name().
920 *
921 * Returns: 0 on success, or -1 on error.
922 */
923 int
im_write_dmask(DOUBLEMASK * in)924 im_write_dmask( DOUBLEMASK *in )
925 {
926 if( !in->filename ) {
927 im_error( "im_write_dmask", "%s", _( "filename not set" ) );
928 return( -1 );
929 }
930
931 return( im_write_dmask_name( in, in->filename ) );
932 }
933
934 /* Copy an imask into a matrix. Only used internally by matrix package for
935 * invert.
936 */
937 void
im_copy_imask_matrix(INTMASK * mask,int ** matrix)938 im_copy_imask_matrix( INTMASK *mask, int **matrix )
939 {
940 int x, y;
941 int *p = mask->coeff;
942
943 for( y = 0; y < mask->ysize; y++ )
944 for( x = 0; x < mask->xsize; x++ )
945 matrix[x][y] = *p++;
946 }
947
948
949 /* Copy a matrix into an imask.
950 */
951 void
im_copy_matrix_imask(int ** matrix,INTMASK * mask)952 im_copy_matrix_imask( int **matrix, INTMASK *mask )
953 {
954 int x, y;
955 int *p = mask->coeff;
956
957 for( y = 0; y < mask->ysize; y++ )
958 for( x = 0; x < mask->xsize; x++ )
959 *p++ = matrix[x][y];
960 }
961
962 /* Copy a dmask into a matrix.
963 */
964 void
im_copy_dmask_matrix(DOUBLEMASK * mask,double ** matrix)965 im_copy_dmask_matrix( DOUBLEMASK *mask, double **matrix )
966 {
967 int x, y;
968 double *p = mask->coeff;
969
970 for( y = 0; y < mask->ysize; y++ )
971 for( x = 0; x < mask->xsize; x++ )
972 matrix[x][y] = *p++;
973 }
974
975 /* Copy a matrix to a dmask.
976 */
977 void
im_copy_matrix_dmask(double ** matrix,DOUBLEMASK * mask)978 im_copy_matrix_dmask( double **matrix, DOUBLEMASK *mask )
979 {
980 int x, y;
981 double *p = mask->coeff;
982
983 for( y = 0; y < mask->ysize; y++ )
984 for( x = 0; x < mask->xsize; x++ )
985 *p++ = matrix[x][y];
986 }
987
988 /**
989 * im_print_imask:
990 * @in: mask to print
991 *
992 * Print an imask to stdout.
993 *
994 * See also: im_print_dmask().
995 */
996 void
im_print_imask(INTMASK * in)997 im_print_imask( INTMASK *in )
998 {
999 int i, j, k;
1000
1001 printf( "%s: %d %d %d %d\n",
1002 in->filename, in->xsize, in->ysize, in->scale, in->offset );
1003
1004 for( k = 0, j = 0; j < in->ysize; j++ ) {
1005 for( i = 0; i < in->xsize; i++, k++ )
1006 printf( "%d\t", in->coeff[k] );
1007
1008 printf( "\n" );
1009 }
1010 }
1011
1012 /**
1013 * im_print_dmask:
1014 * @in: mask to print
1015 *
1016 * Print a dmask to stdout.
1017 *
1018 * See also: im_print_imask().
1019 */
1020 void
im_print_dmask(DOUBLEMASK * in)1021 im_print_dmask( DOUBLEMASK *in )
1022 {
1023 int i, j, k;
1024
1025 printf( "%s: %d %d %f %f\n",
1026 in->filename, in->xsize, in->ysize, in->scale, in->offset );
1027
1028 for( k = 0, j = 0; j < in->ysize; j++ ) {
1029 for( i = 0; i < in->xsize; i++, k++ )
1030 printf( "%f\t", in->coeff[k] );
1031
1032 printf( "\n" );
1033 }
1034 }
1035
1036 /**
1037 * im_local_dmask:
1038 * @out: image to make the mask local to
1039 * @mask: mask to local-ize
1040 *
1041 * @out takes ownership of @mask: when @out is closed, @mask will be closed
1042 * for you. If im_local_dmask() itself fails, the mask is also freed.
1043 *
1044 * See also: im_local_imask().
1045 *
1046 * Returns: the mask, or NULL on error.
1047 */
1048 DOUBLEMASK *
im_local_dmask(VipsImage * out,DOUBLEMASK * mask)1049 im_local_dmask( VipsImage *out, DOUBLEMASK *mask )
1050 {
1051 if( im_check_dmask( "im_local_dmask", mask ) )
1052 return( NULL );
1053
1054 if( im_add_close_callback( out,
1055 (im_callback_fn) im_free_dmask, mask, NULL ) ) {
1056 im_free_dmask( mask );
1057 return( NULL );
1058 }
1059
1060 return( mask );
1061 }
1062
1063 /**
1064 * im_local_imask:
1065 * @out: image to make the mask local to
1066 * @mask: mask to local-ize
1067 *
1068 * @out takes ownership of @mask: when @out is closed, @mask will be closed
1069 * for you. If im_local_imask() itself fails, the mask is also freed.
1070 *
1071 * See also: im_local_dmask().
1072 *
1073 * Returns: the mask, or NULL on error.
1074 */
1075 INTMASK *
im_local_imask(VipsImage * out,INTMASK * mask)1076 im_local_imask( VipsImage *out, INTMASK *mask )
1077 {
1078 if( im_check_imask( "im_local_dmask", mask ) )
1079 return( NULL );
1080
1081 if( im_add_close_callback( out,
1082 (im_callback_fn) im_free_imask, mask, NULL ) ) {
1083 im_free_imask( mask );
1084 return( NULL );
1085 }
1086
1087 return( mask );
1088 }
1089