1 module sbylib.wrapper.freeimage.imageloader;
2 
3 public import sbylib.wrapper.freeimage.image;
4 public import sbylib.wrapper.freeimage.constants;
5 
6 import derelict.freeimage.freeimage;
7 import sbylib.wrapper.freeimage.freeimage;
8 
9 import std.format : format;
10 import std.file : exists;
11 
12 /** 
13   Class for load image.
14   This class cannot be instantiated.
15 */
16 class ImageLoader {
17 
18     @disable this();
19 
20     /**
21     Load image.
22 
23     The file type is automatically selected.
24 
25     Params:
26         path = image file path
27         loadNoPixels = When this flag is supported by a plugin, load only header data and possibly metadata (including embedded thumbnail). When the flag is not supported, pixels are loaded. 
28 
29     Returns: loaded image
30     */
31     static Image load(string path, bool loadNoPixels = false) {
32         const format = getFormat(path);
33         assert(format != ImageFormat.Unknown, path ~ " was not found.");
34 
35         int option = 0;
36         if (loadNoPixels) option |= FIF_LOAD_NOPIXELS;
37 
38         auto bitmap = load(format, path, option);
39         return new Image(bitmap);
40     }
41 
42     /**
43     Load image as gif.
44 
45     When an image which has another file type, assertion error is thrown.
46 
47     Params:
48         path = image file path
49         loadNoPixels = When this flag is supported by a plugin, load only header data and possibly metadata (including embedded thumbnail). When the flag is not supported, pixels are loaded. 
50         load256Color = Load the image as a 256 color image with unused palette entries, if it's 16 or 2 color
51         playBack = 'Play' the GIF to generate each frame (as 32bpp) instead of returning raw frame data when loading
52 
53     Returns: loaded gif image
54     */
55     static Image loadAsGif(string path, bool loadNoPixels = false, bool load256Color = false, bool playBack = false) {
56         return new Image(load(ImageFormat.Gif, path,
57                       (loadNoPixels & FIF_LOAD_NOPIXELS) 
58                     | (load256Color & GIF_LOAD256)
59                     | (playBack     & GIF_PLAYBACK)));
60     }
61 
62     /**
63     Load image as ico.
64 
65     When an image which has another file type, assertion error is thrown.
66 
67     Params:
68         path = image file path
69         loadNoPixels = When this flag is supported by a plugin, load only header data and possibly metadata (including embedded thumbnail). When the flag is not supported, pixels are loaded. 
70         makeAlpha = Convert to 32-bit and create an alpha channel from the AND-mask when loading
71 
72     Returns: loaded ico image
73     */
74     static Image loadAsIco(string path, bool loadNoPixels = false, bool makeAlpha = false) {
75         int option = 0;
76         if (loadNoPixels) option |= FIF_LOAD_NOPIXELS;
77         if (makeAlpha) option |= ICO_MAKEALPHA;
78 
79         return new Image(load(ImageFormat.Ico, path,
80                       (loadNoPixels & FIF_LOAD_NOPIXELS)
81                     | (makeAlpha & ICO_MAKEALPHA)));
82     }
83 
84     /**
85     Load image as jpeg.
86 
87     When an image which has another file type, assertion error is thrown.
88 
89     Params:
90         path = image file path
91         loadNoPixels = When this flag is supported by a plugin, load only header data and possibly metadata (including embedded thumbnail). When the flag is not supported, pixels are loaded. 
92         quality = When 'Fast' is selected, load the file as fast as possible, sacrificing some quality. When 'Accurate' is selected, load the file with the best quality, sacrificing some speed
93         cmyk = This flag will load CMYK bitmaps as 32-bit separated CMYK
94         grayScale = Load and convert to a 8-bit greyscale image (faster than loading as 24-bit and converting to 8-bit)
95         scale = Load and resize the file such that size/X = max(width, height)/X will return an image scaled by 2, 4 or 8 (i.e. the most appropriate requested size).
96         exifRotate = Load and rotate according to Exif 'Orientation' tag if available
97 
98     Returns: loaded jpeg image
99     */
100     static Image loadAsJpeg(string path, bool loadNoPixels = false, JpegLoadQuality quality = JpegLoadQuality.Fast,
101             bool cmyk = false, bool grayScale = false, int scale = 1, bool exifRotate = false) {
102         return new Image(load(ImageFormat.Jpeg, path,
103                       (loadNoPixels & FIF_LOAD_NOPIXELS)
104                     | (quality)
105                     | (cmyk         & JPEG_CMYK)
106                     | (grayScale    & JPEG_GRAYSCALE)
107                     | (scale << 16)
108                     | (exifRotate   & JPEG_EXIFROTATE)));
109     }
110 
111     /**
112     Load image as pcd.
113 
114     When an image which has another file type, assertion error is thrown.
115 
116     Params:
117         path = image file path
118         loadNoPixels = When this flag is supported by a plugin, load only header data and possibly metadata (including embedded thumbnail). When the flag is not supported, pixels are loaded. 
119         option = A PhotoCD picture comes in many sizes. 'Base' will load the one sized 768 x 512
120 
121     Returns: loaded pcd image
122     */
123     static Image loadAsPcd(string path, bool loadNoPixels = false, PcdLoadOption option = PcdLoadOption.Base) {
124         return new Image(load(ImageFormat.Pcd, path,
125                       (loadNoPixels & FIF_LOAD_NOPIXELS)
126                     | (option)));
127     }
128 
129     /**
130     Load image as png.
131 
132     When an image which has another file type, assertion error is thrown.
133 
134     Params:
135         path = image file path
136         loadNoPixels = When this flag is supported by a plugin, load only header data and possibly metadata (including embedded thumbnail). When the flag is not supported, pixels are loaded. 
137         ignoreGamma = Avoid gamma correction on loading
138 
139     Returns: loaded png image
140     */
141     static Image loadAsPng(string path, bool loadNoPixels = false, bool ignoreGamma = false) {
142         return new Image(load(ImageFormat.Png, path,
143                       (loadNoPixels & FIF_LOAD_NOPIXELS)
144                     | (ignoreGamma  & PNG_IGNOREGAMMA)));
145     }
146 
147     /**
148     Load image as raw.
149     By default, load the file as linear RGB 48-bit
150 
151     When an image which has another file type, assertion error is thrown.
152 
153     Params:
154         path = image file path
155         loadNoPixels = When this flag is supported by a plugin, load only header data and possibly metadata (including embedded thumbnail). When the flag is not supported, pixels are loaded. 
156         preview = Try to load the embedded JPEG preview with included Exif data or default to RGB 24-bit
157         display = Load the file as RGB 24-bit
158         halfSize = Output a half-size color image
159         unprocessed = Output a FIT_UINT16 raw Bayer image
160 
161     Returns: loaded raw image
162     */
163     static Image loadAsRaw(string path, bool loadNoPixels = false,
164             bool preview = false, bool display = false, bool halfSize = false, bool unprocessed = false) {
165         return new Image(load(ImageFormat.Raw, path, 
166                       (loadNoPixels & FIF_LOAD_NOPIXELS)
167                     | (preview      & RAW_PREVIEW)
168                     | (display      & RAW_DISPLAY)
169                     | (halfSize     & RAW_HALFSIZE)
170                     | (unprocessed  & RAW_UNPROCESSED)));
171     }
172 
173     /**
174     Load image as targa.
175 
176     When an image which has another file type, assertion error is thrown.
177 
178     Params:
179         path = image file path
180         loadNoPixels = When this flag is supported by a plugin, load only header data and possibly metadata (including embedded thumbnail). When the flag is not supported, pixels are loaded. 
181         loadRGB888 = If set the loader converts RGB555 and ARGB8888 -> RGB888
182 
183     Returns: loaded targa image
184     */
185     static Image loadAsTarga(string path, bool loadNoPixels = false, bool loadRGB888 = false) {
186         return new Image(load(ImageFormat.Targa, path,
187                       (loadNoPixels & FIF_LOAD_NOPIXELS)
188                     | (loadRGB888   & TARGA_LOAD_RGB888)));
189     }
190 
191     /**
192     Load image as tiff.
193 
194     When an image which has another file type, assertion error is thrown.
195 
196     Params:
197         path = image file path
198         loadNoPixels = When this flag is supported by a plugin, load only header data and possibly metadata (including embedded thumbnail). When the flag is not supported, pixels are loaded. 
199         cmyk = This flag will load CMYK bitmaps as separated CMYK (default is conversion to RGB)
200 
201     Returns: loaded tiff image
202     */
203     static Image loadAsTiff(string path, bool loadNoPixels = false, bool cmyk = false) {
204         return new Image(load(ImageFormat.Tiff, path,
205                       (loadNoPixels & FIF_LOAD_NOPIXELS)
206                     | (cmyk         & TIFF_CMYK)
207                     ));
208     }
209 
210     static ImageFormat getFormat(string path)
211     in (exists(path), format!"'%s' does not exist."(path))
212     {
213         return FreeImage().getFileType(path);
214     }
215 
216     private static FIBITMAP* load(ImageFormat fmt, string path, int option = 0)
217     in (exists(path), format!"'%s' does not exist."(path))
218     out(result; result, path ~ " exists, but cannot load.")
219     {
220         return FreeImage().load(fmt, path, option);
221     }
222 
223     unittest {
224         import std : buildNormalizedPath;
225         import std.exception : assertThrown, assertNotThrown;
226         import core.exception : AssertError;
227 
228         auto path = __FILE_FULL_PATH__.buildNormalizedPath("../../../../../test/dman.png");
229         assertThrown!(AssertError)(ImageLoader.loadAsGif(path));
230         assertThrown!(AssertError)(ImageLoader.loadAsIco(path));
231         assertThrown!(AssertError)(ImageLoader.loadAsJpeg(path));
232         assertNotThrown!(AssertError)(ImageLoader.loadAsPcd(path));
233         assertNotThrown!(AssertError)(ImageLoader.loadAsPng(path));
234         assertThrown!(AssertError)(ImageLoader.loadAsRaw(path));
235         assertThrown!(AssertError)(ImageLoader.loadAsTarga(path));
236         assertThrown!(AssertError)(ImageLoader.loadAsTiff(path));
237     }
238 }