1 /**
2 Various public types.
3 
4 Copyright: Copyright Guillaume Piolat 2022
5 License:   $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
6 */
7 module gamut.types;
8 
9 nothrow @nogc:
10 @safe:
11 
12 /// Image format.
13 /// It is the kind of container/codec formats Gamut can read and write to.
14 enum ImageFormat
15 {
16     unknown = -1, /// Unknown format (returned value only, never use it as input value)
17     first   =  0,
18     JPEG    =  0, /// Independent JPEG Group (*.JPG, *.JIF, *.JPEG, *.JPE)
19     PNG     =  1, /// Portable Network Graphics (*.PNG)
20     QOI     =  2, /// Quite OK Image format (*.QOI)
21     QOIX    =  3, /// Quite OK Image format, eXtended as in Gamut (*.QOIX)
22     DDS     =  4  /// Compressed texture formats.
23 }
24 
25 /// Pixel component type.
26 /// Integer components are stored normalized (255 or 65535 being the maximum of intensity).
27 enum PixelType
28 {
29     unknown = -1, /// Unknown format (returned value only, never use it as input value)
30 
31     l8,           /// Array of ubyte: unsigned 8-bit
32     l16,          /// Array of ushort: unsigned 16-bit
33     lf32,         /// Array of float: 32-bit IEEE floating point
34     
35     la8,          /// 16-bit Luminance Alpha image: 2 x unsigned 8-bit
36     la16,         /// 32-bit Luminance Alpha image: 2 x unsigned 16-bit
37     laf32,        /// 64-bit Luminance Alpha image: 2 x 32-bit IEEE floating point
38 
39     rgb8,         /// 24-bit RGB image: 3 x unsigned 8-bit
40     rgb16,        /// 48-bit RGB image: 3 x unsigned 16-bit
41     rgbf32,       /// 96-bit RGB float image: 3 x 32-bit IEEE floating point
42 
43     rgba8,        /// 32-bit RGBA image: 4 x unsigned 8-bit
44     rgba16,       /// 64-bit RGBA image: 4 x unsigned 16-bit    
45     rgbaf32,      /// 128-bit RGBA float image: 4 x 32-bit IEEE floating point
46 }
47 
48 
49 // Limits
50 
51 
52 
53 /// When images have an unknown DPI resolution;
54 enum GAMUT_UNKNOWN_RESOLUTION = -1;
55 
56 /// When images have an unknown physical pixel ratio.
57 /// Explanation: it is possible to have a known pixel ratio, but an unknown DPI (eg: PNG).
58 enum GAMUT_UNKNOWN_ASPECT_RATIO = -1;
59 
60 /// No Gamut `Image` can exceed this width in gamut.
61 enum int GAMUT_MAX_IMAGE_WIDTH = 16777216;  
62 
63 /// No Gamut `Image` can exceed this height in gamut.
64 enum int GAMUT_MAX_IMAGE_HEIGHT = 16777216;
65 
66 /// No Gamut `Image` can have a width x height product that exceed this value of 67 Mpixels.
67 enum int GAMUT_MAX_IMAGE_WIDTH_x_HEIGHT = 67108864;
68 
69 
70 /// Converts from meters to inches.
71 float convertMetersToInches(float x) pure
72 {
73     return x * 39.37007874f;
74 }
75 
76 /// Converts from inches to meters.
77 float convertInchesToMeters(float x) pure
78 {
79     return x / 39.37007874f;
80 }
81 
82 /// Converts from PPM (Points Per Meter) to DPI (Dots Per Inch).
83 alias convertPPMToDPI = convertInchesToMeters;
84 
85 /// Converts from DPI (Dots Per Inch) to PPM (Points Per Meter).
86 alias convertDPIToPPM = convertMetersToInches;
87 
88 
89 /// Load flags (range: bits 16 to 23).
90 alias LoadFlags = int;
91 
92 /// No loading options. This will keep the original input pixel format, so as to make the least
93 /// conversions possible.
94 enum LoadFlags LOAD_NORMAL          = 0;
95 
96 
97 /// Load the image in greyscale, can be faster than loading as RGB8 then converting to greyscale.
98 /// This will preserve an alpha channel, if existing.
99 /// The resulting image will have 1 or 2 channels.
100 /// Can't be used with `LOAD_RGB` flag.
101 enum LoadFlags LOAD_GREYSCALE       = 0x10000;
102 
103 /// Load the image in RGB, can be faster than loading a greyscale image and then converting it RGB.
104 /// The resulting image will have 3 or 4 channels.
105 /// Can't be used with `LOAD_GREYSCALE`.
106 enum LoadFlags LOAD_RGB             = 0x80000; 
107 
108 
109 /// Load the image and adds an alpha channel (opaque if not existing).
110 /// This will preserve the color channels.
111 /// The resulting image will have 2 or 4 channels.
112 /// Can't be used with `LOAD_NO_ALPHA` flag.
113 enum LoadFlags LOAD_ALPHA           = 0x20000;
114 
115 /// Load the image and drops an eventual alpha channel, if it exists.
116 /// The resulting image will have 1 or 3 channels.
117 /// Can't be used with `LOAD_ALPHA` flag.
118 enum LoadFlags LOAD_NO_ALPHA        = 0x40000;
119 
120 
121 /// Load the image directly in 8-bit, can be faster than loading as 16-bit PNG and then converting to 8-bit.
122 /// Can't be used with `LOAD_10BIT` or `LOAD_FP32` flag.
123 enum LoadFlags LOAD_8BIT            = 0x100000;
124 
125 /// Load the image directly in 16-bit, can be faster than loading as 8-bit PNG and then converting to 16-bit.
126 /// Can't be used with `LOAD_8BIT` or `LOAD_FP32` flag.
127 enum LoadFlags LOAD_16BIT           = 0x200000;
128 
129 /// Load the image directly in 32-bit floating point.
130 /// Probably the same speed as just calling `convertToFP32` after load though.
131 /// Can't be used with `LOAD_8BIT` or `LOAD_10BIT` flag.
132 enum LoadFlags LOAD_FP32           = 0x400000;
133 
134 
135 /// Only decode metadata, not the pixels themselves.
136 /// NOT SUPPORTED YET!
137 enum LoadFlags LOAD_NO_PIXELS       = 0x800000;
138 
139 
140 
141 
142 
143 
144 // Encode flags
145 
146 /// Do nothing particular.
147 /// Supported by: JPEG, PNG, DDS, QOI, QOIX.
148 enum int ENCODE_NORMAL = 0;
149 
150 /// Internal use, this is to test a variation of a compiler.
151 /// Supported by: JPEG, PNG, DDS, QOI, QOIX.
152 enum int ENCODE_CHALLENGER = 4;
153 
154 
155 
156 
157 /// Layout constraints flags (bits 0 to 15).
158 /// All of those introduce "gap pixels" after the scanline, in order to follow the various constraints.
159 ///
160 /// Example: if you want to process 4x RGBA8 pixels at once, with aligned SSE, use:
161 ///    `LAYOUT_MULTIPLICITY_4 | LAYOUT_SCANLINE_ALIGNED_16`
162 alias LayoutConstraints = ushort;
163 
164 enum LayoutConstraints
165      LAYOUT_DEFAULT               = 0,  /// Default / do-not-care layout options.
166 
167      // Multiplicity: 
168      // -------------
169      //
170      // Allows to access pixels by packing them together, without stepping on the next scanline or segfault.
171      // Multiplicity warrants READ access to needed excess pixels at the end of each scanline.
172      // If the image is owned      => additionally it warrants WRITE access to those excess pixels.
173      //                 not-owned  => can't WRITE to those pixels. 
174      // Subimage: taking a sub-rect of an image REMOVES the constraint guarantee, it forces `LAYOUT_MULTIPLICITY_1`.
175      //
176      LAYOUT_MULTIPLICITY_1        = 0,  /// No particular multiplicity requirements.
177      LAYOUT_MULTIPLICITY_2        = 1,  /// Beginning at the start of a scanline, pixels can be READ 2 by 2 without segfault.
178      LAYOUT_MULTIPLICITY_4        = 2,  /// Beginning at the start of a scanline, pixels can be READ 4 by 4 without segfault.
179      LAYOUT_MULTIPLICITY_8        = 3,  /// Beginning at the start of a scanline, pixels can be READ 8 by 8 without segfault.
180 
181      // Trailing pixels: 
182      // ----------------
183      // Allows to access the very end of a scanline with SIMD, without stepping on the next scanline or segfault.
184      // Trailing pixels warrants READ access to needed excess pixels at the end of each scanline.
185      // If the image is owned      => additionally it warrants WRITE access to those excess pixels.
186      //                 not-owned  => can't WRITE to those pixels. 
187      // Subimage: taking a sub-rect of an image KEEPS the trailing pixels guarantee (but removes ability to write to them).
188      //
189      LAYOUT_TRAILING_0            = 0,  /// Scanlines have no trailing requirements.
190      LAYOUT_TRAILING_1            = 4,  /// Scanlines must be followed by at least 1 READABLE gap pixels.
191      LAYOUT_TRAILING_3            = 8,  /// Scanlines must be followed by at least 3 READABLE gap pixels.
192      LAYOUT_TRAILING_7            = 12, /// Scanlines must be followed by at least 7 READABLE gap pixels.
193 
194      
195      // Scanline alignment:
196      // -------------------
197      // Allows to access pixels from start of scanline with aligned SIMD.
198      // Both scanling addresses, and also pitchInBytes, must be aligned.
199      //
200      // Gap bytes that would exist are READABLE.
201      // If the image is owned      => additionally it warrants WRITE access to those gap bytes, if any.
202      //                 not-owned  => can't WRITE to those bytes. 
203      // Subimage: taking a sub-rect of an image REMOVES the scanline alignment guarantee, it forces `LAYOUT_SCANLINE_ALIGNED_1`.
204      //
205      LAYOUT_SCANLINE_ALIGNED_1    = 0,  /// No particular alignment for scanline.
206      LAYOUT_SCANLINE_ALIGNED_2    = 16, /// Scanlines required to be at least aligned on 2 bytes boundaries.
207      LAYOUT_SCANLINE_ALIGNED_4    = 32, /// Scanlines required to be at least aligned on 4 bytes boundaries.
208      LAYOUT_SCANLINE_ALIGNED_8    = 48, /// Scanlines required to be at least aligned on 8 bytes boundaries.
209      LAYOUT_SCANLINE_ALIGNED_16   = 64, /// Scanlines required to be at least aligned on 16 bytes boundaries.
210      LAYOUT_SCANLINE_ALIGNED_32   = 80, /// Scanlines required to be at least aligned on 32 bytes boundaries.
211      LAYOUT_SCANLINE_ALIGNED_64   = 96, /// Scanlines required to be at least aligned on 64 bytes boundaries.
212      LAYOUT_SCANLINE_ALIGNED_128  = 112, /// Scanlines required to be at least aligned on 128 bytes boundaries.
213 
214 
215      // Scanline alignment:
216      // -------------------
217      // Allow to access additional pixels in every direction, without segfault.
218      //
219      // Border pixels are READABLE.
220      // If the image is owned      => additionally iborder pixels are WRITEABLE.
221      //                 not-owned  => can't WRITE to those pixels. 
222      // Subimage: taking a sub-rect of an image KEEPS the border pixels constraint (but removes ability to write to them).
223      //     
224      LAYOUT_BORDER_0              = 0,   /// No particular border constraint.
225      LAYOUT_BORDER_1              = 128, /// The whole image has a border of at least 1 pixel addressable without segfault.
226      LAYOUT_BORDER_2              = 256, /// The whole image has a border of at least 2 pixels addressable without segfault.
227      LAYOUT_BORDER_3              = 384, /// The whole image has a border of at least 3 pixels addressable without segfault.
228 
229      // Allow to force the image representation to be stored in a certain vertical direction.
230      LAYOUT_VERT_FLIPPED          = 512,  /// The whole image MUST be stored upside down. Can't be used with `LAYOUT_VERT_STRAIGHT` flag.
231      LAYOUT_VERT_STRAIGHT         = 1024, /// The whole image MUST NOT be stored upside down. Can't be used with `LAYOUT_VERT_FLIPPED` flag.
232 
233      // No space between scanlines. 
234      // This is logically incompatible with scanline alignment, border, trailing pixels, and multiplicity.
235      // Subimage: LAYOUT_GAPLESS is immediately lost.
236      LAYOUT_GAPLESS               = 2048; /// There must be no single trailing bytes between scanlines.
237 
238 
239 PixelType convertPixelTypeToGreyscale(PixelType type)
240 {
241     PixelType t = PixelType.unknown;
242     final switch(type) with (PixelType)
243     {
244         case unknown: t = unknown; break;
245         case l8:      t = l8; break;
246         case l16:     t = l16; break;
247         case lf32:    t = lf32; break;
248         case la8:     t = la8; break;
249         case la16:    t = la16; break;
250         case laf32:   t = laf32; break;
251         case rgb8:    t = l8; break;
252         case rgb16:   t = l16; break;
253         case rgbf32:  t = lf32; break;
254         case rgba8:   t = la8; break;
255         case rgba16:  t = la16; break;
256         case rgbaf32: t = laf32; break;
257     }
258     return t;
259 }
260 
261 PixelType convertPixelTypeToRGB(PixelType type)
262 {
263     PixelType t = PixelType.unknown;
264     final switch(type) with (PixelType)
265     {
266         case unknown: t = unknown; break;
267         case l8:      t = rgb8; break;
268         case l16:     t = rgb16; break;
269         case lf32:    t = rgbf32; break;
270         case la8:     t = rgba8; break;
271         case la16:    t = rgba16; break;
272         case laf32:   t = rgbaf32; break;
273         case rgb8:    t = rgb8; break;
274         case rgb16:   t = rgb16; break;
275         case rgbf32:  t = rgbf32; break;
276         case rgba8:   t = rgba8; break;
277         case rgba16:  t = rgba16; break;
278         case rgbaf32: t = rgbaf32; break;
279     }
280     return t;
281 }
282 
283 PixelType convertPixelTypeToAddAlphaChannel(PixelType type)
284 {
285     PixelType t = PixelType.unknown;
286     final switch(type) with (PixelType)
287     {
288         case unknown: t = unknown; break;
289         case l8:      t = la8; break;
290         case l16:     t = la16; break;
291         case lf32:    t = laf32; break;
292         case la8:     t = la8; break;
293         case la16:    t = la16; break;
294         case laf32:   t = laf32; break;
295         case rgb8:    t = rgba8; break;
296         case rgb16:   t = rgba16; break;
297         case rgbf32:  t = rgbaf32; break;
298         case rgba8:   t = rgba8; break;
299         case rgba16:  t = rgba16; break;
300         case rgbaf32: t = rgbaf32; break;
301     }
302     return t;
303 }
304 
305 PixelType convertPixelTypeToDropAlphaChannel(PixelType type)
306 {
307     PixelType t = PixelType.unknown;
308     final switch(type) with (PixelType)
309     {
310         case unknown: t = unknown; break;
311         case l8:      t = l8; break;
312         case l16:     t = l16; break;
313         case lf32:    t = lf32; break;
314         case la8:     t = l8; break;
315         case la16:    t = l16; break;
316         case laf32:   t = lf32; break;
317         case rgb8:    t = rgb8; break;
318         case rgb16:   t = rgb16; break;
319         case rgbf32:  t = rgbf32; break;
320         case rgba8:   t = rgb8; break;
321         case rgba16:  t = rgb16; break;
322         case rgbaf32: t = rgbf32; break;
323     }
324     return t;
325 }
326 
327 PixelType convertPixelTypeTo8Bit(PixelType type)
328 {
329     PixelType t = PixelType.unknown;       
330     final switch(type) with (PixelType)
331     {
332         case unknown: t = unknown; break;
333         case l8:      t = l8; break;
334         case l16:     t = l8; break;
335         case lf32:    t = l8; break;
336         case la8:     t = la8; break;
337         case la16:    t = la8; break;
338         case laf32:   t = la8; break;
339         case rgb8:    t = rgb8; break;
340         case rgb16:   t = rgb8; break;
341         case rgbf32:  t = rgb8; break;
342         case rgba8:   t = rgba8; break;
343         case rgba16:  t = rgba8; break;
344         case rgbaf32: t = rgba8; break;
345     }
346     return t;
347 }
348 
349 PixelType convertPixelTypeTo16Bit(PixelType type)
350 {
351     PixelType t = PixelType.unknown;       
352     final switch(type) with (PixelType)
353     {
354         case unknown: t = unknown; break;
355         case l8:      t = l16; break;
356         case l16:     t = l16; break;
357         case lf32:    t = l16; break;
358         case la8:     t = la16; break;
359         case la16:    t = la16; break;
360         case laf32:   t = la16; break;
361         case rgb8:    t = rgb16; break;
362         case rgb16:   t = rgb16; break;
363         case rgbf32:  t = rgb16; break;
364         case rgba8:   t = rgba16; break;
365         case rgba16:  t = rgba16; break;
366         case rgbaf32: t = rgba16; break;
367     }
368     return t;
369 }
370 
371 
372 PixelType convertPixelTypeToFP32(PixelType type)
373 {
374     PixelType t = PixelType.unknown;       
375     final switch(type) with (PixelType)
376     {
377         case unknown: t = unknown; break;
378         case l8:      t = lf32; break;
379         case l16:     t = lf32; break;
380         case lf32:    t = lf32; break;
381         case la8:     t = laf32; break;
382         case la16:    t = laf32; break;
383         case laf32:   t = laf32; break;
384         case rgb8:    t = rgbf32; break;
385         case rgb16:   t = rgbf32; break;
386         case rgbf32:  t = rgbf32; break;
387         case rgba8:   t = rgbaf32; break;
388         case rgba16:  t = rgbaf32; break;
389         case rgbaf32: t = rgbaf32; break;
390     }
391     return t;
392 }
393