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