1 module dlibwebp.impl;
2 
3 import api = dlibwebp.api;
4 
5 import dlib.image;
6 import webp.encode;
7 import webp.decode;
8 import dlib.core.compound;
9 import dlib.core.stream;
10 import dlib.filesystem.local;
11 import core.stdc.stdlib : free;
12 import std.array;
13 import exceptions;
14 
15 
16 
17 package SuperImage loadWEBP(string filename) {
18     InputStream input = openForInput(filename);
19     auto img = loadWEBP(input);
20     input.close();
21     return img;
22 }
23 
24 package SuperImage loadWEBP(InputStream input) {
25     auto fileContent = appender!(ubyte[])();
26     ubyte[0x1000] buffer;
27     while (input.readable) {
28         size_t count = input.readBytes(buffer.ptr, buffer.length);
29         if (count == 0) {
30             break;
31         }
32         for (int i = 0; i < count; i++) {
33             fileContent.put(buffer[i]);
34         }
35     }
36     return loadWEBP(fileContent.data);
37 }
38 
39 package SuperImage loadWEBP(in ubyte[] webp) {
40     int width;
41     int height;
42     ubyte* argbPointer = WebPDecodeRGBA(webp.ptr, webp.length, &width, &height);
43     ubyte[] argbArray = argbPointer[0 .. (width * height * 4)];
44 
45     SuperImage rgbaImage = defaultImageFactory.createImage(width, height, 4, 8);
46     foreach(i, v; argbArray) {
47         rgbaImage.data[i] = v;
48     }
49     free(argbPointer);
50     return rgbaImage;
51 }
52 
53 
54 package void saveWEBP(SuperImage img, int quality, string filename) {
55     OutputStream output;
56     try {
57         output = openForOutput(filename);
58     } catch (Exception e) {
59         throw new IOException("Could now open file for write.", e);
60     }
61 
62     Compound!(bool, string) res = saveWEBP(img, quality, output);
63     output.close();
64 
65     if (!res[0]) {
66         throw new api.WEBPLoadException(res[1]);
67     }
68 }
69 package void saveLosslessWEBP(SuperImage img, string filename) {
70     OutputStream output;
71     try {
72         output = openForOutput(filename);
73     } catch (Exception e) {
74         throw new IOException("Could now open file for write.", e);
75     }
76 
77     Compound!(bool, string) res = saveLosslessWEBP(img, output);
78     output.close();
79 
80     if (!res[0]) {
81         throw new api.WEBPLoadException(res[1]);
82     }
83 }
84 
85 package Compound!(bool, string) saveWEBP(SuperImage img, int quality, OutputStream output) {
86     ubyte[] result;
87     try {
88         result = saveWEBPToArray(img, quality);
89     } catch (api.WEBPLoadException e) {
90         if (e.msg.empty) {
91             return compound(false, "Exception occurred during to saving to the array.");
92         } else {
93             return compound(false, e.msg);
94         }
95     }
96     if (result.length < 1) {
97         return compound(false, "Empty result.");
98     }
99     if (!output.writeArray(result)) {
100         /// By some reason, `writeArray` returns `false` on Travis CI.
101         // return compound(false, "Could not write the result to the output stream.");
102     }
103     return compound(true, "");
104 }
105 package Compound!(bool, string) saveLosslessWEBP(SuperImage img, OutputStream output) {
106     ubyte[] result;
107     try {
108         result = saveLosslessWEBPToArray(img);
109     } catch (api.WEBPLoadException e) {
110         if (e.msg.empty) {
111             return compound(false, "Exception occurred during to saving to the array.");
112         } else {
113             return compound(false, e.msg);
114         }
115     }
116     if (result.length < 1) {
117         return compound(false, "Empty result.");
118     }
119     if (!output.writeArray(result)) {
120         /// By some reason, `writeArray` returns `false` on Travis CI.
121         // return compound(false, "Could not write the result to the output stream.");
122     }
123     return compound(true, "");
124 }
125 
126 package ubyte[] saveWEBPToArray(SuperImage img, int quality) {
127     if (PixelFormat.L8 == img.pixelFormat ||
128             PixelFormat.RGB8 == img.pixelFormat ||
129             PixelFormat.L16 == img.pixelFormat ||
130             PixelFormat.RGB16 == img.pixelFormat) {
131         return saveLossy(img, quality);
132     } else {
133         return saveLossyWithAlpha(img, quality);
134     }
135 }
136 package ubyte[] saveLosslessWEBPToArray(SuperImage img) {
137     if (PixelFormat.L8 == img.pixelFormat ||
138             PixelFormat.RGB8 == img.pixelFormat ||
139             PixelFormat.L16 == img.pixelFormat ||
140             PixelFormat.RGB16 == img.pixelFormat) {
141         return saveLossless(img);
142     } else {
143         return saveLosslessWithAlpha(img);
144     }
145 }
146 
147 
148 
149 private ubyte[] saveLossyWithAlpha(SuperImage img, int quality) {
150     SuperImage inputImage = img;
151     if (PixelFormat.RGBA8 != img.pixelFormat) {
152         inputImage = convert!(Image!(PixelFormat.RGBA8))(img);
153         assert(inputImage.width == img.width);
154         assert(inputImage.height == img.height);
155     }
156     ubyte* outputPointer;
157     size_t outputSize = WebPEncodeRGBA(
158             inputImage.data.ptr,
159             img.width(),
160             img.height(),
161             img.width() * 4,
162             quality,
163             &outputPointer);
164     ubyte[] result = outputPointer[0 .. outputSize];
165     free(outputPointer);
166     return result;
167 }
168 private ubyte[] saveLossy(SuperImage img, int quality) {
169     SuperImage inputImage = img;
170     if (PixelFormat.RGB8 != img.pixelFormat) {
171         inputImage = convert!(Image!(PixelFormat.RGB8))(img);
172         assert(inputImage.width == img.width);
173         assert(inputImage.height == img.height);
174     }
175     ubyte* outputPointer;
176     size_t outputSize = WebPEncodeRGB(
177             inputImage.data.ptr,
178             img.width(),
179             img.height(),
180             img.width() * 3,
181             quality,
182             &outputPointer);
183     ubyte[] result = outputPointer[0 .. outputSize];
184     free(outputPointer);
185     return result;
186 }
187 
188 private ubyte[] saveLosslessWithAlpha(SuperImage img) {
189     SuperImage inputImage = img;
190     if (PixelFormat.RGBA8 != img.pixelFormat) {
191         inputImage = convert!(Image!(PixelFormat.RGBA8))(img);
192         assert(inputImage.width == img.width);
193         assert(inputImage.height == img.height);
194     }
195     ubyte* outputPointer;
196     size_t outputSize = WebPEncodeLosslessRGBA(
197             inputImage.data.ptr,
198             inputImage.width(),
199             inputImage.height(),
200             inputImage.width() * 4,
201             &outputPointer);
202     ubyte[] result = outputPointer[0 .. outputSize];
203     free(outputPointer);
204     return result;
205 }
206 private ubyte[] saveLossless(SuperImage img) {
207     SuperImage inputImage = img;
208     if (PixelFormat.RGB8 != img.pixelFormat) {
209         inputImage = convert!(Image!(PixelFormat.RGB8))(img);
210         assert(inputImage.width == img.width);
211         assert(inputImage.height == img.height);
212     }
213     ubyte* outputPointer;
214     size_t outputSize = WebPEncodeLosslessRGB(
215             inputImage.data.ptr,
216             inputImage.width(),
217             inputImage.height(),
218             inputImage.width() * 3,
219             &outputPointer);
220     ubyte[] result = outputPointer[0 .. outputSize];
221     free(outputPointer);
222     return result;
223 }