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     }
154     ubyte* outputPointer;
155     size_t outputSize = WebPEncodeRGBA(
156             inputImage.data.ptr,
157             img.width(),
158             img.height(),
159             img.width() * 4,
160             quality,
161             &outputPointer);
162     ubyte[] result = outputPointer[0 .. outputSize];
163     free(outputPointer);
164     return result;
165 }
166 private ubyte[] saveLossy(SuperImage img, int quality) {
167     SuperImage inputImage = img;
168     if (PixelFormat.RGB8 != img.pixelFormat) {
169         inputImage = convert!(Image!(PixelFormat.RGB8))(img);
170     }
171     ubyte* outputPointer;
172     size_t outputSize = WebPEncodeRGB(
173             inputImage.data.ptr,
174             img.width(),
175             img.height(),
176             img.width() * 3,
177             quality,
178             &outputPointer);
179     ubyte[] result = outputPointer[0 .. outputSize];
180     free(outputPointer);
181     return result;
182 }
183 
184 private ubyte[] saveLosslessWithAlpha(SuperImage img) {
185     SuperImage inputImage = img;
186     if (PixelFormat.RGBA8 != img.pixelFormat) {
187         inputImage = convert!(Image!(PixelFormat.RGBA8))(img);
188     }
189     ubyte* outputPointer;
190     size_t outputSize = WebPEncodeLosslessRGBA(
191             inputImage.data.ptr,
192             inputImage.width(),
193             inputImage.height(),
194             inputImage.width() * 4,
195             &outputPointer);
196     ubyte[] result = outputPointer[0 .. outputSize];
197     free(outputPointer);
198     return result;
199 }
200 private ubyte[] saveLossless(SuperImage img) {
201     SuperImage inputImage = img;
202     if (PixelFormat.RGB8 != img.pixelFormat) {
203         inputImage = convert!(Image!(PixelFormat.RGB8))(img);
204     }
205     ubyte* outputPointer;
206     size_t outputSize = WebPEncodeLosslessRGB(
207             inputImage.data.ptr,
208             inputImage.width(),
209             inputImage.height(),
210             inputImage.width() * 3,
211             &outputPointer);
212     ubyte[] result = outputPointer[0 .. outputSize];
213     free(outputPointer);
214     return result;
215 }