1 // Written in the D programming language.
2 
3 /**
4 This module contains image loading functions.
5 
6 Currently uses FreeImage.
7 
8 Usage of libpng is not feasible under linux due to conflicts of library and binding versions.
9 
10 Synopsis:
11 
12 ----
13 import dlangui.graphics.images;
14 
15 ----
16 
17 Copyright: Vadim Lopatin, 2014
18 License:   Boost License 1.0
19 Authors:   Vadim Lopatin, coolreader.org@gmail.com
20 */
21 module dlangui.graphics.images;
22 
23 public import dlangui.core.config;
24 static if (BACKEND_GUI):
25 
26 //version = USE_DEIMAGE;
27 //version = USE_DLIBIMAGE;
28 version = USE_DIMAGE;
29 
30 version (USE_DEIMAGE) {
31     import devisualization.image;
32     import devisualization.image.png;
33 } else version (USE_DIMAGE) {
34     //import dimage.io;
35     import dimage.image;
36     import dimage.png;
37     import dimage.jpeg;
38 } else version (USE_DLIBIMAGE) {
39     import dlib.image.io.io;
40     import dlib.image.image;
41     import dlib.image.io.png;
42     import dlib.image.io.jpeg;
43     version = ENABLE_DLIBIMAGE_JPEG;
44 }
45 
46 import dlangui.core.logger;
47 import dlangui.core.types;
48 import dlangui.graphics.colors;
49 import dlangui.graphics.drawbuf;
50 import dlangui.core.streams;
51 import std.path;
52 import std.conv : to;
53 
54 
55 /// load and decode image from file to ColorDrawBuf, returns null if loading or decoding is failed
56 ColorDrawBuf loadImage(string filename) {
57     static import std.file;
58     try {
59         immutable ubyte[] data = cast(immutable ubyte[])std.file.read(filename);
60         return loadImage(data, filename);
61     } catch (Exception e) {
62         Log.e("exception while loading image from file ", filename);
63         Log.e(to!string(e));
64         return null;
65     }
66 }
67 
68 /// load and decode image from input stream to ColorDrawBuf, returns null if loading or decoding is failed
69 ColorDrawBuf loadImage(immutable ubyte[] data, string filename) {
70     Log.d("Loading image from file " ~ filename);
71 
72     import std.algorithm : endsWith;
73     if (filename.endsWith(".xpm")) {
74         import dlangui.graphics.xpm.reader : parseXPM;
75         try {
76             return parseXPM(data);
77         }
78         catch(Exception e) {
79             Log.e("Failed to load image from file ", filename);
80             Log.e(to!string(e));
81             return null;
82         }
83     }
84 
85     version (USE_DEIMAGE) {
86         try {
87             Image image = imageFromData(extension(filename)[1 ..$], cast(ubyte[])data); //imageFromFile(filename);
88             int w = cast(int)image.width;
89             int h = cast(int)image.height;
90             ColorDrawBuf buf = new ColorDrawBuf(w, h);
91             Color_RGBA[] pixels = image.rgba.allPixels;
92             int index = 0;
93             foreach(y; 0 .. h) {
94                 uint * dstLine = buf.scanLine(y);
95                 foreach(x; 0 .. w) {
96                     Color_RGBA * pixel = &pixels[index + x];
97                     dstLine[x] = makeRGBA(pixel.r_ubyte, pixel.g_ubyte, pixel.b_ubyte, pixel.a_ubyte);
98                 }
99                 index += w;
100             }
101             //destroy(image);
102             return buf;
103         } catch (NotAnImageException e) {
104             Log.e("Failed to load image from file ", filename, " using de_image");
105             Log.e(to!string(e));
106             return null;
107         }
108     } else version (USE_DLIBIMAGE) {
109         static import dlib.core.stream;
110         try {
111             version (ENABLE_DLIBIMAGE_JPEG) {
112             } else {
113                 // temporary disabling of JPEG support - until DLIB included it
114                 if (filename.endsWith(".jpeg") || filename.endsWith(".jpg") || filename.endsWith(".JPG") || filename.endsWith(".JPEG"))
115                     return null;
116             }
117             SuperImage image = null;
118             dlib.core.stream.ArrayStream dlibstream = new dlib.core.stream.ArrayStream(cast(ubyte[])data, data.length);
119             switch(filename.extension)
120             {
121                 case ".jpg", ".JPG", ".jpeg":
122                     image = dlib.image.io.jpeg.loadJPEG(dlibstream);
123                     break;
124                 case ".png", ".PNG":
125                     image = dlib.image.io.png.loadPNG(dlibstream);
126                     break;
127                 default:
128                     break;
129             }
130             //SuperImage image = dlib.image.io.io.loadImage(filename);
131             if (!image)
132                 return null;
133             ColorDrawBuf buf = importImage(image);
134             destroy(image);
135             return buf;
136         } catch (Exception e) {
137             Log.e("Failed to load image from file ", filename, " using dlib image");
138             Log.e(to!string(e));
139             return null;
140         }
141     } else version (USE_DIMAGE) {
142         static import dimage.stream;
143         try {
144             SuperImage image = null;
145             dimage.stream.ArrayStream dlibstream = new dimage.stream.ArrayStream(cast(ubyte[])data, data.length);
146             switch(filename.extension)
147             {
148                 case ".jpg", ".JPG", ".jpeg":
149                     image = dimage.jpeg.loadJPEG(dlibstream);
150                     break;
151                 case ".png", ".PNG":
152                     image = dimage.png.loadPNG(dlibstream);
153                     break;
154                 default:
155                     break;
156             }
157             //SuperImage image = dlib.image.io.io.loadImage(filename);
158             if (!image)
159                 return null;
160             ColorDrawBuf buf = importImage(image);
161             destroy(image);
162             return buf;
163         } catch (Exception e) {
164             Log.e("Failed to load image from file ", filename, " using dlib image");
165             Log.e(to!string(e));
166             return null;
167         }
168     } else {
169         try {
170             std.stream.File f = new std.stream.File(filename);
171             scope(exit) { f.close(); }
172             return loadImage(f);
173         } catch (Exception e) {
174             Log.e("exception while loading image from file ", filename);
175             Log.e(to!string(e));
176             return null;
177         }
178     }
179 
180 }
181 
182 version (USE_DLIBIMAGE) {
183     ColorDrawBuf importImage(SuperImage image) {
184         int w = image.width;
185         int h = image.height;
186         ColorDrawBuf buf = new ColorDrawBuf(w, h);
187         foreach(y; 0 .. h) {
188             uint * dstLine = buf.scanLine(y);
189             foreach(x; 0 .. w) {
190                 auto pixel = image[x, y].convert(8);
191                 dstLine[x] = makeRGBA(pixel.r, pixel.g, pixel.b, 255 - pixel.a);
192             }
193         }
194         return buf;
195     }
196 }
197 
198 version (USE_DIMAGE) {
199     ColorDrawBuf importImage(SuperImage image) {
200         int w = image.width;
201         int h = image.height;
202         ColorDrawBuf buf = new ColorDrawBuf(w, h);
203         foreach(y; 0 .. h) {
204             uint * dstLine = buf.scanLine(y);
205             foreach(x; 0 .. w) {
206                 uint pixel = image[x, y];
207                 dstLine[x] = pixel ^ 0xFF000000;
208             }
209         }
210         return buf;
211     }
212 }
213 
214 class ImageDecodingException : Exception {
215     this(string msg) {
216         super(msg);
217     }
218 }
219