1 module vips.option;
2 
3 import std.variant : Variant;
4 
5 import vips.bindings;
6 import vips.image;
7 import vips.operation;
8 import vips.conv : toGObject;
9 import gobject.Value;
10 import gobject.ObjectG;
11 
12 private struct ParamConfig
13 {
14     string key;
15     bool isOutput;
16     Value value;
17     Variant output;
18 
19     this(string key)
20     {
21         this.key = key;
22     }
23 }
24 
25 extern(C)
26 {
27     bool g_type_is_a(GType src, GType target);
28 }
29 
30 struct VOption
31 {
32 public:
33      ~this()
34     {
35         foreach (config; options)
36         {
37             config.value.unset();
38         }
39     }
40 
41     ref VOption set(string key, VImage value)
42     {
43         auto config = ParamConfig(key);
44         config.value = new Value().init(VImage.getType());
45         g_value_set_object(config.value.getValueStruct, value.img.toGObject);
46         options[key] = config;
47         return this;
48     }
49 
50     ref VOption set(string key, VImage* value)
51     {
52         import gobject.Type : Type;
53 
54         auto config = ParamConfig(key);
55         config.value = new Value().init(VImage.getType());
56         config.isOutput = true;
57         config.output = value;
58         options[key] = config;
59         return this;
60     }
61 
62     ref VOption set(string key, VImage[] value)
63     {
64         auto config = ParamConfig(key);
65         config.value = new Value();
66         config.value.init(vips_array_image_get_type());
67         vips_value_set_array_image(config.value.getValueStruct(), cast(int)(value.length));
68         auto array = vips_value_get_array_image(config.value.getValueStruct, null);
69         foreach (i, image; value)
70         {
71             array[i] = image.img;
72         }
73         options[key] = config;
74         return this;
75     }
76 
77     ref VOption set(T)(string key, T value)
78     {
79         auto config = ParamConfig(key);
80         config.value = new Value(value);
81         options[key] = config;
82         return this;
83     }
84 
85     ref VOption set(string key, VipsBlob* blob)
86     {
87         auto config = ParamConfig(key);
88         config.value = new Value(new ObjectG(cast(GObject*) blob));
89         options[key] = config;
90         return this;
91     }
92 
93     ref VOption set(T : U*, U)(string key, T value)
94     {
95         import std.traits : isScalarType;
96 
97         auto config = ParamConfig(key);
98         config.isOutput = true;
99         static if (isScalarType!U)
100         {
101             config.value = new Value(U.init);
102         }
103         else static if (is(U == double[]))
104         {
105             config.value = new Value().init(vips_array_double_get_type());
106             //TODO need to add corresponding reader method for this
107         }
108         else static if (is(U == VipsBlob*))
109         {
110             config.value = new Value().init(vips_blob_get_type());
111             //TODO need to add corresponding reader handler for this
112         }
113         else
114         {
115             static assert(false, "Unknown output value: " ~ U.stringof);
116         }
117         config.output = value;
118         options[key] = config;
119         return this;
120     }
121 
122     ref VOption set(string key, double[] vals)
123     {
124         auto config = ParamConfig(key);
125         config.value = new Value();
126         config.value.init(vips_array_double_get_type());
127         vips_value_set_array_double(config.value.getValueStruct(), vals.ptr,
128                 cast(int) vals.length,);
129         return this;
130     }
131 
132     ref VOption set(string key, int[] vals)
133     {
134         auto config = ParamConfig(key);
135         config.value = new Value().init(vips_array_int_get_type());
136         vips_value_set_array_int(config.value.getValueStruct(), vals.ptr, cast(int) vals.length,);
137         return this;
138     }
139 
140     void setInputs(ref VOperation operation)
141     {
142         foreach (option; options)
143         {
144             if (!option.isOutput)
145             {
146                 operation.setProperty(option.key, option.value);
147             }
148         }
149     }
150 
151     void readOutputs(ref VOperation operation)
152     {
153         import gobject.Type : Type;
154         import vips.bindings : g_value_get_object;
155         foreach (option; options)
156         {
157             if (option.isOutput)
158             {
159                 operation.getProperty(option.key, option.value);
160                 immutable type = option.value.getValueStruct().gType;
161                 if (type == vips_image_get_type())
162                 {
163                     auto obj = cast(VipsImage*)
164                         g_value_get_object(option.value.getValueStruct);
165                     *(option.output.get!(VImage*)) = VImage(obj);
166                 }
167                 else if (type == GType.INT)
168                 {
169                     *(option.output.get!(int*)) = option.value.getInt();
170                 }
171                 else if (type == GType.BOOLEAN)
172                 {
173                     *(option.output.get!(bool*)) = option.value.getBoolean();
174                 }
175                 else if (type == GType.DOUBLE)
176                 {
177                     *(option.output.get!(double*)) = option.value.getDouble();
178                 }
179                 else
180                 {
181                     // still need to handle double arrays
182                     // and blobs
183                 }
184             }
185         }
186     }
187 
188 private:
189     ParamConfig[string] options;
190 }