1 /*
2  *  options.c:		FIASCO options handling
3  *
4  *  Written by:		Ullrich Hafner
5  *
6  *  This file is part of FIASCO (Fractal Image And Sequence COdec)
7  *  Copyright (C) 1994-2000 Ullrich Hafner
8  */
9 
10 /*
11  *  $Date: 2000/10/28 17:39:31 $
12  *  $Author: hafner $
13  *  $Revision: 5.5 $
14  *  $State: Exp $
15  */
16 
17 #define _DEFAULT_SOURCE 1 /* New name for SVID & BSD source defines */
18 #define _BSD_SOURCE 1   /* Make sure strdup() is in string.h */
19 #define _XOPEN_SOURCE 500  /* Make sure strdup() is in string.h */
20 
21 #include "config.h"
22 
23 #include <string.h>
24 #include <stdlib.h>
25 #include <stdio.h>
26 
27 #include "nstring.h"
28 
29 #include "types.h"
30 #include "macros.h"
31 #include "error.h"
32 
33 #include "wfa.h"
34 #include "misc.h"
35 #include "bit-io.h"
36 #include "fiasco.h"
37 #include "options.h"
38 
39 fiasco_c_options_t *
fiasco_c_options_new(void)40 fiasco_c_options_new (void)
41 /*
42  *  FIASCO options constructor.
43  *  Allocate memory for the FIASCO coder options structure and
44  *  fill in default values.
45  *
46  *  Return value:
47  *	pointer to the new option structure
48  */
49 {
50    c_options_t 	      *options = calloc (1, sizeof (c_options_t));
51    fiasco_c_options_t *public  = calloc (1, sizeof (fiasco_c_options_t));
52 
53    if (!options || !public)
54    {
55       set_error (_("Out of memory."));
56       return NULL;
57    }
58    public->private 	      = options;
59    public->delete 	      = fiasco_c_options_delete;
60    public->set_tiling 	      = fiasco_c_options_set_tiling;
61    public->set_frame_pattern  = fiasco_c_options_set_frame_pattern;
62    public->set_basisfile      = fiasco_c_options_set_basisfile;
63    public->set_chroma_quality = fiasco_c_options_set_chroma_quality;
64    public->set_optimizations  = fiasco_c_options_set_optimizations;
65    public->set_video_param    = fiasco_c_options_set_video_param;
66    public->set_quantization   = fiasco_c_options_set_quantization;
67    public->set_progress_meter = fiasco_c_options_set_progress_meter;
68    public->set_smoothing      = fiasco_c_options_set_smoothing;
69    public->set_title   	      = fiasco_c_options_set_title;
70    public->set_comment        = fiasco_c_options_set_comment;
71 
72    strcpy (options->id, "COFIASCO");
73 
74    /*
75     *  Set default value of fiasco options
76     */
77    options->basis_name 		  = strdup ("small.fco");
78    options->lc_min_level 	  = 4;
79    options->lc_max_level 	  = 12;
80    options->p_min_level 	  = 8;
81    options->p_max_level 	  = 10;
82    options->images_level 	  = 5;
83    options->max_states 		  = MAXSTATES;
84    options->chroma_max_states 	  = 40;
85    options->max_elements 	  = MAXEDGES;
86    options->tiling_exponent 	  = 4;
87    options->tiling_method 	  = FIASCO_TILING_VARIANCE_DSC;
88    options->id_domain_pool 	  = strdup ("rle");
89    options->id_d_domain_pool 	  = strdup ("rle");
90    options->id_rpf_model 	  = strdup ("adaptive");
91    options->id_d_rpf_model 	  = strdup ("adaptive");
92    options->rpf_mantissa 	  = 3;
93    options->rpf_range 		  = FIASCO_RPF_RANGE_1_50;
94    options->dc_rpf_mantissa 	  = 5;
95    options->dc_rpf_range 	  = FIASCO_RPF_RANGE_1_00;
96    options->d_rpf_mantissa 	  = 3;
97    options->d_rpf_range 	  = FIASCO_RPF_RANGE_1_50;
98    options->d_dc_rpf_mantissa 	  = 5;
99    options->d_dc_rpf_range 	  = FIASCO_RPF_RANGE_1_00;
100    options->chroma_decrease 	  = 2.0;
101    options->prediction 		  = NO;
102    options->delta_domains 	  = YES;
103    options->normal_domains 	  = YES;
104    options->search_range 	  = 16;
105    options->fps 		  = 25;
106    options->pattern 		  = strdup ("IPPPPPPPPP");
107    options->reference_filename 	  = NULL;
108    options->half_pixel_prediction = NO;
109    options->cross_B_search 	  = YES;
110    options->B_as_past_ref 	  = YES;
111    options->check_for_underflow   = NO;
112    options->check_for_overflow 	  = NO;
113    options->second_domain_block   = NO;
114    options->full_search 	  = NO;
115    options->progress_meter 	  = FIASCO_PROGRESS_NONE;
116    options->smoothing 	 	  = 70;
117    options->comment 		  = strdup ("");
118    options->title 		  = strdup ("");
119 
120    return public;
121 }
122 
123 void
fiasco_c_options_delete(fiasco_c_options_t * options)124 fiasco_c_options_delete (fiasco_c_options_t *options)
125 /*
126  *  FIASCO options destructor.
127  *  Free memory of FIASCO options struct.
128  *
129  *  No return value.
130  *
131  *  Side effects:
132  *	structure 'options' is discarded.
133  */
134 {
135    c_options_t *this = cast_c_options (options);
136 
137    if (!this)
138       return;
139 
140    Free (this->id_domain_pool);
141    Free (this->id_d_domain_pool);
142    Free (this->id_rpf_model);
143    Free (this->id_d_rpf_model);
144    Free (this->pattern);
145    Free (this->comment);
146    Free (this->title);
147 
148    Free (this);
149 
150    return;
151 }
152 
153 int
fiasco_c_options_set_tiling(fiasco_c_options_t * options,fiasco_tiling_e method,unsigned exponent)154 fiasco_c_options_set_tiling (fiasco_c_options_t *options,
155 			     fiasco_tiling_e method, unsigned exponent)
156 /*
157  *  Set tiling `method' and `exponent'.
158  *  See type `fiasco_tiling_e' for a list of valid  tiling `methods'.
159  *  The image is subdivied into 2^`exponent' tiles
160  *
161  *  Return value:
162  *	1 on success
163  *	0 otherwise
164  */
165 {
166    c_options_t *this = (c_options_t *) cast_c_options (options);
167 
168    if (!this)
169    {
170       return 0;
171    }
172    switch (method)
173    {
174       case FIASCO_TILING_SPIRAL_ASC:
175       case FIASCO_TILING_SPIRAL_DSC:
176       case FIASCO_TILING_VARIANCE_ASC:
177       case FIASCO_TILING_VARIANCE_DSC:
178 	 this->tiling_method = method;
179 	 break;
180       default:
181 	 set_error (_("Invalid tiling method `%d' specified "
182 		      "(valid methods are 0, 1, 2, or 3)."), method);
183 	 return 0;
184    }
185    this->tiling_exponent = exponent;
186 
187    return 1;
188 }
189 
190 int
fiasco_c_options_set_frame_pattern(fiasco_c_options_t * options,const char * pattern)191 fiasco_c_options_set_frame_pattern (fiasco_c_options_t *options,
192 				    const char *pattern)
193 /*
194  *  Set `pattern' of input frames.
195  *  `pattern' has to be a sequence of the following
196  *  characters (case insensitive):
197  *  'i' intra frame
198  *  'p' predicted frame
199  *  'b' bidirectional predicted frame
200  *  E.g. pattern = 'IBBPBBPBB'
201  *
202  *  When coding video frames the prediction type of input frame N is determined
203  *  by reading `pattern' [N] (`pattern' is periodically extended).
204  *
205  *  Return value:
206  *	1 on success
207  *	0 otherwise
208  */
209 {
210    c_options_t *this = (c_options_t *) cast_c_options (options);
211 
212    if (!this)
213    {
214       return 0;
215    }
216    else if (!pattern)
217    {
218       set_error (_("Parameter `%s' not defined (NULL)."), "pattern");
219       return 0;
220    }
221    else if (strlen (pattern) < 1)
222    {
223       set_error (_("Frame type pattern doesn't contain any character."));
224       return 0;
225    }
226    else
227    {
228       const char *str;
229       bool_t 	  parse_error = NO;
230       int	  c 	      = 0;
231 
232       for (str = pattern; *str && !parse_error; str++)
233 	 switch (*str)
234 	 {
235 	    case 'i':
236 	    case 'I':
237 	    case 'b':
238 	    case 'B':
239 	    case 'p':
240 	    case 'P':
241 	       break;
242 	    default:
243 	       c = *str;
244 	       parse_error = YES;
245 	 }
246 
247       if (parse_error)
248       {
249 	 set_error (_("Frame type pattern contains invalid character `%c' "
250 		      "(choose I, B or P)."), c);
251 	 return 0;
252       }
253       else
254       {
255 	 Free (this->pattern);
256 	 this->pattern = strdup (pattern);
257 
258 	 return 1;
259       }
260    }
261 }
262 
263 int
fiasco_c_options_set_basisfile(fiasco_c_options_t * options,const char * filename)264 fiasco_c_options_set_basisfile (fiasco_c_options_t *options,
265 				const char *filename)
266 /*
267  *  Set `filename' of FIASCO initial basis.
268  *
269  *  Return value:
270  *	1 on success (if the file is readable)
271  *	0 otherwise
272  */
273 {
274    c_options_t *this = (c_options_t *) cast_c_options (options);
275 
276    if (!this)
277    {
278       return 0;
279    }
280    else if (!filename)
281    {
282       set_error (_("Parameter `%s' not defined (NULL)."), "filename");
283       return 0;
284    }
285    else
286    {
287        /* Skip this because basis file may be linked with program, not
288           in a separate file.  See get_linked_basis().  NETPBM
289       FILE *file = open_file (filename, "FIASCO_DATA", READ_ACCESS);
290       if (file)
291       {
292 	 fclose (file);
293 	 return 1;
294       }
295       else
296       {
297 	 set_error (_("Can't read basis file `%s'.\n%s."), filename,
298 		    get_system_error ());
299 	 return 0;
300       }
301       */ return 1;
302    }
303 }
304 
305 int
fiasco_c_options_set_chroma_quality(fiasco_c_options_t * options,float quality_factor,unsigned dictionary_size)306 fiasco_c_options_set_chroma_quality (fiasco_c_options_t *options,
307 				     float quality_factor,
308 				     unsigned dictionary_size)
309 /*
310  *  Set color compression parameters.
311  *  When coding chroma channels (Cb and Cr)
312  *  - approximation quality is given by `quality_factor' * `Y quality' and
313  *  - `dictionary_size' gives the number of dictionary elements.
314  *
315  *  If 'quality' <= 0 then the luminancy coding quality is also during
316  *  chroma channel coding.
317  *
318  *  Return value:
319  *	1 on success
320  *	0 otherwise
321  */
322 {
323    c_options_t *this = (c_options_t *) cast_c_options (options);
324 
325    if (!this)
326    {
327       return 0;
328    }
329    else if (!dictionary_size)
330    {
331       set_error (_("Size of chroma compression dictionary has to be "
332 		   "a positive number."));
333       return 0;
334    }
335    else if (quality_factor <= 0)
336    {
337       set_error (_("Quality of chroma channel compression has to be "
338 		   "positive value."));
339       return 0;
340    }
341    else
342    {
343       this->chroma_decrease   = quality_factor;
344       this->chroma_max_states = dictionary_size;
345 
346       return 1;
347    }
348 }
349 
350 int
fiasco_c_options_set_optimizations(fiasco_c_options_t * options,unsigned min_block_level,unsigned max_block_level,unsigned max_elements,unsigned dictionary_size,unsigned optimization_level)351 fiasco_c_options_set_optimizations (fiasco_c_options_t *options,
352 				    unsigned min_block_level,
353 				    unsigned max_block_level,
354 				    unsigned max_elements,
355 				    unsigned dictionary_size,
356 				    unsigned optimization_level)
357 /*
358  *  Set various optimization parameters.
359  *  - During compression only image blocks of size
360  *    {`min_block_level', ... ,`max_block_level'} are considered.
361  *    The smaller this set of blocks is the faster the coder runs
362  *    and the worse the image quality will be.
363  *  - An individual approximation may use at most `max_elements'
364  *    elements of the dictionary which itself contains at most
365  *    `dictionary_size' elements. The smaller these values are
366  *    the faster the coder runs and the worse the image quality will be.
367  *  - `optimization_level' enables some additional low level optimizations.
368  *    0: standard approximation method
369  *    1: significantly increases the approximation quality,
370  *       running time is twice as high as with the standard method
371  *    2: hardly increases the approximation quality of method 1,
372  *       running time is twice as high as with method 1
373  *       (this method just remains for completeness)
374  *
375  *  Return value:
376  *	1 on success
377  *	0 otherwise
378  */
379 {
380    c_options_t *this = (c_options_t *) cast_c_options (options);
381 
382    if (!this)
383    {
384       return 0;
385    }
386    else if (!dictionary_size)
387    {
388       set_error (_("Size of dictionary has to be a positive number."));
389       return 0;
390    }
391    else if (!max_elements)
392    {
393       set_error (_("At least one dictionary element has to be used "
394 		   "in an approximation."));
395       return 0;
396    }
397    else if (max_block_level < 4)
398    {
399       set_error (_("Maximum image block size has to be at least level 4."));
400       return 0;
401    }
402    else if (min_block_level < 4)
403    {
404       set_error (_("Minimum image block size has to be at least level 4."));
405       return 0;
406    }
407    else if (max_block_level < min_block_level)
408    {
409       set_error (_("Maximum block size has to be larger or "
410 		   "equal minimum block size."));
411       return 0;
412    }
413    else
414    {
415       this->lc_min_level 	= min_block_level;
416       this->lc_max_level 	= max_block_level;
417       this->max_states 	 	= dictionary_size;
418       this->max_elements 	= max_elements;
419       this->second_domain_block = optimization_level > 0 ? YES : NO;
420       this->check_for_overflow  = optimization_level > 1 ? YES : NO;
421       this->check_for_underflow = optimization_level > 1 ? YES : NO;
422       this->full_search 	= optimization_level > 1 ? YES : NO;
423 
424       return 1;
425    }
426 }
427 
428 int
fiasco_c_options_set_prediction(fiasco_c_options_t * options,int intra_prediction,unsigned min_block_level,unsigned max_block_level)429 fiasco_c_options_set_prediction (fiasco_c_options_t *options,
430 				 int intra_prediction,
431 				 unsigned min_block_level,
432 				 unsigned max_block_level)
433 /*
434  *  Set minimum and maximum size of image block prediction to
435  *  `min_block_level' and `max_block_level'.
436  *  (For either motion compensated prediction of inter frames
437  *   or DC based prediction of intra frames)
438  *  Prediction of intra frames is only used if `intra_prediction' != 0.
439  *
440  *  Return value:
441  *	1 on success
442  *	0 otherwise
443  */
444 {
445    c_options_t *this = (c_options_t *) cast_c_options (options);
446 
447    if (!this)
448    {
449       return 0;
450    }
451    else if (max_block_level < 6)
452    {
453       set_error (_("Maximum prediction block size has to be "
454 		   "at least level 6"));
455       return 0;
456    }
457    else if (min_block_level < 6)
458    {
459       set_error (_("Minimum prediction block size has to be "
460 		   "at least level 6"));
461       return 0;
462    }
463    else if (max_block_level < min_block_level)
464    {
465       set_error (_("Maximum prediction block size has to be larger or "
466 		   "equal minimum block size."));
467       return 0;
468    }
469    else
470    {
471       this->p_min_level = min_block_level;
472       this->p_max_level = max_block_level;
473       this->prediction  = intra_prediction;
474 
475       return 1;
476    }
477 }
478 
479 int
fiasco_c_options_set_video_param(fiasco_c_options_t * options,unsigned frames_per_second,int half_pixel_prediction,int cross_B_search,int B_as_past_ref)480 fiasco_c_options_set_video_param (fiasco_c_options_t *options,
481 				  unsigned frames_per_second,
482 				  int half_pixel_prediction,
483 				  int cross_B_search,
484 				  int B_as_past_ref)
485 /*
486  *  Set various parameters used for video compensation.
487  *  'frames_per_second' defines the frame rate which should be
488  *  used when the video is decoded. This value has no effect during coding,
489  *  it is just passed to the FIASCO output file.
490  *  If 'half_pixel_prediction' is not 0 then half pixel precise
491  *  motion compensated prediction is used.
492  *  If 'cross_B_search' is not 0 then the fast Cross-B-Search algorithm is
493  *  used to determine the motion vectors of interpolated prediction. Otherwise
494  *  exhaustive search (in the given search range) is used.
495  *  If 'B_as_past_ref' is not 0 then B frames are allowed to be used
496  *  for B frame predicion.
497  *
498  *  Return value:
499  *	1 on success
500  *	0 otherwise
501  */
502 {
503    c_options_t *this = (c_options_t *) cast_c_options (options);
504 
505    if (!this)
506    {
507       return 0;
508    }
509    else
510    {
511       this->fps 	  	  = frames_per_second;
512       this->half_pixel_prediction = half_pixel_prediction;
513       this->cross_B_search 	  = cross_B_search;
514       this->B_as_past_ref 	  = B_as_past_ref;
515 
516       return 1;
517    }
518 }
519 
520 int
fiasco_c_options_set_quantization(fiasco_c_options_t * options,unsigned mantissa,fiasco_rpf_range_e range,unsigned dc_mantissa,fiasco_rpf_range_e dc_range)521 fiasco_c_options_set_quantization (fiasco_c_options_t *options,
522 				   unsigned mantissa,
523 				   fiasco_rpf_range_e range,
524 				   unsigned dc_mantissa,
525 				   fiasco_rpf_range_e dc_range)
526 /*
527  *  Set accuracy of coefficients quantization.
528  *  DC coefficients (of the constant dictionary vector f(x,y) = 1)
529  *  are quantized to values of the interval [-`dc_range', `dc_range'] using
530  *  #`dc_mantissa' bits. All other quantized coefficients are quantized in
531  *  an analogous way using the parameters `range' and `mantissa'.
532  *
533  *  Return value:
534  *	1 on success
535  *	0 otherwise
536  */
537 {
538    c_options_t *this = (c_options_t *) cast_c_options (options);
539 
540    if (!this)
541    {
542       return 0;
543    }
544    else if (mantissa < 2 || mantissa > 8 || dc_mantissa < 2 || dc_mantissa > 8)
545    {
546       set_error (_("Number of RPF mantissa bits `%d', `%d' have to be in "
547 		   "the interval [2,8]."), mantissa, dc_mantissa);
548       return 0;
549    }
550    else
551    {
552       if ((range == FIASCO_RPF_RANGE_0_75
553 	  || range == FIASCO_RPF_RANGE_1_00
554 	  || range == FIASCO_RPF_RANGE_1_50
555 	   || range == FIASCO_RPF_RANGE_2_00)
556 	  &&
557 	  (dc_range == FIASCO_RPF_RANGE_0_75
558 	   || dc_range == FIASCO_RPF_RANGE_1_00
559 	   || dc_range == FIASCO_RPF_RANGE_1_50
560 	   || dc_range == FIASCO_RPF_RANGE_2_00))
561       {
562 	 this->rpf_range       = range;
563 	 this->dc_rpf_range    = dc_range;
564 	 this->rpf_mantissa    = mantissa;
565 	 this->dc_rpf_mantissa = dc_mantissa;
566 
567 	 return 1;
568       }
569       else
570       {
571 	 set_error (_("Invalid RPF ranges `%d', `%d' specified."),
572 		    range, dc_range);
573 	 return 0;
574       }
575    }
576 }
577 
578 int
fiasco_c_options_set_progress_meter(fiasco_c_options_t * options,fiasco_progress_e type)579 fiasco_c_options_set_progress_meter (fiasco_c_options_t *options,
580 				     fiasco_progress_e type)
581 /*
582  *  Set type of progress meter.
583  *
584  *  Return value:
585  *	1 on success
586  *	0 otherwise
587  */
588 {
589    c_options_t *this = (c_options_t *) cast_c_options (options);
590 
591    if (!this)
592    {
593       return 0;
594    }
595    switch (type)
596    {
597       case FIASCO_PROGRESS_BAR:
598       case FIASCO_PROGRESS_PERCENT:
599       case FIASCO_PROGRESS_NONE:
600 	 this->progress_meter = type;
601 	 break;
602       default:
603 	 set_error (_("Invalid progress meter `%d' specified "
604 		      "(valid values are 0, 1, or 2)."), type);
605 	 return 0;
606    }
607    return 1;
608 }
609 
610 int
fiasco_c_options_set_smoothing(fiasco_c_options_t * options,int smoothing)611 fiasco_c_options_set_smoothing (fiasco_c_options_t *options, int smoothing)
612 /*
613  *  Define `smoothing'-percentage along partitioning borders.
614  *
615  *  Return value:
616  *	1 on success
617  *	0 otherwise
618  */
619 {
620    c_options_t *this = (c_options_t *) cast_c_options (options);
621 
622    if (!this)
623    {
624       return 0;
625    }
626    else if (smoothing < -1 || smoothing > 100)
627    {
628       set_error (_("Smoothing percentage must be in the range [-1, 100]."));
629       return 0;
630    }
631    else
632    {
633       this->smoothing = smoothing;
634       return 1;
635    }
636 }
637 
638 int
fiasco_c_options_set_comment(fiasco_c_options_t * options,const char * comment)639 fiasco_c_options_set_comment (fiasco_c_options_t *options, const char *comment)
640 /*
641  *  Define `comment' of FIASCO stream.
642  *
643  *  Return value:
644  *	1 on success
645  *	0 otherwise
646  */
647 {
648    c_options_t *this = (c_options_t *) cast_c_options (options);
649 
650    if (!this)
651    {
652       return 0;
653    }
654    else if (!comment)
655    {
656       set_error (_("Parameter `%s' not defined (NULL)."), "title");
657       return 0;
658    }
659    else
660    {
661       this->comment = strdup (comment);
662       return 1;
663    }
664 }
665 
666 int
fiasco_c_options_set_title(fiasco_c_options_t * options,const char * title)667 fiasco_c_options_set_title (fiasco_c_options_t *options, const char *title)
668 /*
669  *  Define `title' of FIASCO stream.
670  *
671  *  Return value:
672  *	1 on success
673  *	0 otherwise
674  */
675 {
676    c_options_t *this = (c_options_t *) cast_c_options (options);
677 
678    if (!this)
679    {
680       return 0;
681    }
682    else if (!title)
683    {
684       set_error (_("Parameter `%s' not defined (NULL)."), "title");
685       return 0;
686    }
687    else
688    {
689       this->title = strdup (title);
690       return 1;
691    }
692 }
693 
694 c_options_t *
cast_c_options(fiasco_c_options_t * options)695 cast_c_options (fiasco_c_options_t *options)
696 /*
697  *  Cast generic pointer `options' to type c_options_t.
698  *  Check whether `options' is a valid object of type c_options_t.
699  *
700  *  Return value:
701  *	pointer to options struct on success
702  *      NULL otherwise
703  */
704 {
705    c_options_t *this = (c_options_t *) options->private;
706    if (this)
707    {
708       if (!streq (this->id, "COFIASCO"))
709       {
710 	 set_error (_("Parameter `options' doesn't match required type."));
711 	 return NULL;
712       }
713    }
714    else
715    {
716       set_error (_("Parameter `%s' not defined (NULL)."), "options");
717    }
718 
719    return this;
720 }
721 
722 /**************************************************************************
723 ***************************************************************************
724 			       DECODER
725 ***************************************************************************
726 **************************************************************************/
727 
728 fiasco_d_options_t *
fiasco_d_options_new(void)729 fiasco_d_options_new (void)
730 /*
731  *  FIASCO options constructor.
732  *  Allocate memory for the FIASCO coder options structure and
733  *  fill in default values.
734  *
735  *  Return value:
736  *	pointer to the new option structure
737  */
738 {
739    d_options_t 	      *options = calloc (1, sizeof (d_options_t));
740    fiasco_d_options_t *public  = calloc (1, sizeof (fiasco_d_options_t));
741 
742    if (!options || !public)
743    {
744       set_error (_("Out of memory."));
745       return NULL;
746    }
747    public->private 	      = options;
748    public->delete 	      = fiasco_d_options_delete;
749    public->set_smoothing      = fiasco_d_options_set_smoothing;
750    public->set_magnification  = fiasco_d_options_set_magnification;
751    public->set_4_2_0_format   = fiasco_d_options_set_4_2_0_format;
752 
753    strcpy (options->id, "DOFIASCO");
754 
755    /*
756     *  Set default value of fiasco decoder options
757     */
758    options->smoothing 	  = 70;
759    options->magnification = 0;
760    options->image_format  = FORMAT_4_4_4;
761 
762    return public;
763 }
764 
765 void
fiasco_d_options_delete(fiasco_d_options_t * options)766 fiasco_d_options_delete (fiasco_d_options_t *options)
767 /*
768  *  FIASCO options destructor.
769  *  Free memory of FIASCO options struct.
770  *
771  *  No return value.
772  *
773  *  Side effects:
774  *	structure 'options' is discarded.
775  */
776 {
777    d_options_t *this = cast_d_options (options);
778 
779    if (!this)
780       return;
781 
782    Free (this);
783 
784    return;
785 }
786 
787 int
fiasco_d_options_set_smoothing(fiasco_d_options_t * options,int smoothing)788 fiasco_d_options_set_smoothing (fiasco_d_options_t *options, int smoothing)
789 /*
790  *  Define `smoothing'-percentage along partitioning borders.
791  *
792  *  Return value:
793  *	1 on success
794  *	0 otherwise
795  */
796 {
797    d_options_t *this = (d_options_t *) cast_d_options (options);
798 
799    if (!this)
800    {
801       return 0;
802    }
803    else if (smoothing < -1 || smoothing > 100)
804    {
805       set_error (_("Smoothing percentage must be in the range [-1, 100]."));
806       return 0;
807    }
808    else
809    {
810       this->smoothing = smoothing;
811       return 1;
812    }
813 }
814 
815 int
fiasco_d_options_set_magnification(fiasco_d_options_t * options,int level)816 fiasco_d_options_set_magnification (fiasco_d_options_t *options, int level)
817 /*
818  *  Set magnification-'level' of decoded image.
819  *  0: width x height of original image
820  *  1: (2 * width) x (2 * height) of original image
821  *  -1: (width / 2 ) x (height / 2) of original image
822  *  etc.
823  *
824  *  Return value:
825  *	1 on success
826  *	0 otherwise
827  */
828 {
829    d_options_t *this = (d_options_t *) cast_d_options (options);
830 
831    if (!this)
832    {
833       return 0;
834    }
835    else
836    {
837       this->magnification = level;
838       return 1;
839    }
840 }
841 
842 int
fiasco_d_options_set_4_2_0_format(fiasco_d_options_t * options,int format)843 fiasco_d_options_set_4_2_0_format (fiasco_d_options_t *options, int format)
844 /*
845  *  Set image format to 4:2:0 or 4:4:4.
846  *
847  *  Return value:
848  *	1 on success
849  *	0 otherwise
850  */
851 {
852    d_options_t *this = (d_options_t *) cast_d_options (options);
853 
854    if (!this)
855    {
856       return 0;
857    }
858    else
859    {
860       this->image_format = format ? FORMAT_4_2_0 : FORMAT_4_4_4;
861       return 1;
862    }
863 }
864 
865 d_options_t *
cast_d_options(fiasco_d_options_t * options)866 cast_d_options (fiasco_d_options_t *options)
867 /*
868  *  Cast generic pointer `options' to type d_options_t.
869  *  Check whether `options' is a valid object of type d_options_t.
870  *
871  *  Return value:
872  *	pointer to options struct on success
873  *      NULL otherwise
874  */
875 {
876    d_options_t *this = (d_options_t *) options->private;
877 
878    if (this)
879    {
880       if (!streq (this->id, "DOFIASCO"))
881       {
882 	 set_error (_("Parameter `options' doesn't match required type."));
883 	 return NULL;
884       }
885    }
886    else
887    {
888       set_error (_("Parameter `%s' not defined (NULL)."), "options");
889    }
890 
891    return this;
892 }
893 
894 
895