The OpenD Programming Language

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