core/image
image
Types
63Alpha_Key
Alpha_Key :: union {
GA_Pixel,
RGBA_Pixel,
GA_Pixel_16,
RGBA_Pixel_16,
}SourceBMP_CIEXYZ
BMP_CIEXYZ :: [3]BMP_FXPT2DOT30SourceBMP_CIEXYZTRIPLE
BMP_CIEXYZTRIPLE :: [3]BMP_CIEXYZSourceBMP_Compression
BMP_Compression :: enum u32le {
RGB = 0,
RLE8 = 1,
RLE4 = 2,
Bit_Fields = 3, // If Windows
Huffman1D = 3, // If OS2v2
JPEG = 4, // If Windows
RLE24 = 4, // If OS2v2
PNG = 5,
Alpha_Bit_Fields = 6,
CMYK = 11,
CMYK_RLE8 = 12,
CMYK_RLE4 = 13,
}SourceBMP_Error
BMP_Error :: enum int {
None = 0,
Invalid_File_Size = 1,
Unsupported_BMP_Version = 2,
Unsupported_OS2_File = 3,
Unsupported_Compression = 4,
Unsupported_BPP = 5,
Invalid_Stride = 6,
Invalid_Color_Count = 7,
Implausible_File_Size = 8,
Bitfield_Version_Unhandled = 9, // We don't (yet) handle bit fields for this BMP version.
Bitfield_Sum_Exceeds_BPP = 10, // Total mask bit count > bpp
Bitfield_Overlapped = 11, // Channel masks overlap
}SourceBMP-specific
BMP_FXPT2DOT30
BMP_FXPT2DOT30 :: u32leSourceBMP_GAMMA16_16
BMP_GAMMA16_16 :: [2]u16leSourceBMP_Gamut_Mapping_Intent
BMP_Gamut_Mapping_Intent :: enum u32le {
INVALID = 0, // If not V5, this field will just be zero-initialized and not valid.
ABS_COLORIMETRIC = 8,
BUSINESS = 1,
GRAPHICS = 2,
IMAGES = 4,
}SourceBMP_Header
BMP_Header :: struct #packed {
// File header
magic: BMP_Magic,
size: u32le,
_res1: u16le,
_res2: u16le,
pixel_offset: u32le,
// V3
info_size: BMP_Version,
width: i32le,
height: i32le,
planes: u16le,
bpp: u16le,
compression: BMP_Compression,
image_size: u32le,
pels_per_meter: [2]u32le,
colors_used: u32le,
colors_important: u32le,
// V4
masks: [4]u32le,
colorspace: BMP_Logical_Color_Space,
endpoints: BMP_CIEXYZTRIPLE,
gamma: [3]BMP_GAMMA16_16,
// V5
intent: BMP_Gamut_Mapping_Intent,
profile_data: u32le,
profile_size: u32le,
reserved: u32le,
}SourceBMP_Info
BMP_Info :: struct {
info: BMP_Header,
}Sourceimg.metadata is wrapped in a struct in case we need to add to it later without putting it in BMP_Header
BMP_Logical_Color_Space
BMP_Logical_Color_Space :: enum u32le {
CALIBRATED_RGB = 0,
sRGB = 1934772034, // 'sRGB'
WINDOWS_COLOR_SPACE = 1466527264, // 'Win '
}SourceBMP_Magic
BMP_Magic :: enum u16le {
Bitmap = 19778, // 'BM'
OS2_Bitmap_Array = 16706, // 'BA'
OS2_Icon = 17225, // 'IC',
OS2_Color_Icon = 18755, // 'CI'
OS2_Pointer = 21584, // 'PT'
OS2_Color_Pointer = 20547, // 'CP'
}SourceBMP_Version
BMP_Version :: enum u32le {
OS2_v1 = 12, // BITMAPCOREHEADER (Windows V2 / OS/2 version 1.0)
OS2_v2 = 64, // BITMAPCOREHEADER2 (OS/2 version 2.x)
V3 = 40, // BITMAPINFOHEADER
V4 = 108, // BITMAPV4HEADER
V5 = 124, // BITMAPV5HEADER
ABBR_16 = 16, // Abbreviated
ABBR_24 = 24, // ..
ABBR_48 = 48, // ..
ABBR_52 = 52, // ..
ABBR_56 = 56, // ..
}SourceSee: http://justsolve.archiveteam.org/wiki/BMP#Well-known_versions
Channel
Channel :: enum u8 {
R = 1,
G = 2,
B = 3,
A = 4,
}SourceDestroy_Proc
Destroy_Proc :: proc(img: ^Image)SourceError
Error :: union {
General_Image_Error,
Netpbm_Error,
PNG_Error,
QOI_Error,
BMP_Error,
JPEG_Error,
compress.Error,
compress.General_Error,
compress.Deflate_Error,
compress.ZLIB_Error,
io.Error,
runtime.Allocator_Error,
}SourceExif
Exif :: struct {
byte_order: enum,
data: []u8,
}SourceGA_Pixel
GA_Pixel :: [2]u8SourceGA_Pixel_16
GA_Pixel_16 :: [2]u16SourceG_Pixel
G_Pixel :: [1]u8SourceGrayscale
G_Pixel_16
G_Pixel_16 :: [1]u16SourceGeneral_Image_Error
General_Image_Error :: enum int {
None = 0,
Unsupported_Option = 1,
// File I/O
Unable_To_Read_File = 2,
Unable_To_Write_File = 3,
// Invalid
Unsupported_Format = 4,
Invalid_Signature = 5,
Invalid_Input_Image = 6,
Image_Dimensions_Too_Large = 7,
Invalid_Image_Dimensions = 8,
Invalid_Number_Of_Channels = 9,
Image_Does_Not_Adhere_to_Spec = 10,
Invalid_Image_Depth = 11,
Invalid_Bit_Depth = 12,
Invalid_Color_Space = 13,
// More data than pixels to decode into, for example.
Corrupt = 14,
// Output buffer is the wrong size
Invalid_Output = 15,
// Allocation
Unable_To_Allocate_Or_Resize = 16,
}SourceImage
Image :: struct {
width: int,
height: int,
channels: int,
depth: int,
pixels: bytes.Buffer,
// Some image loaders/writers can return/take an optional background color.
// For convenience, we return them as u16 so we don't need to switch on the type
// in our viewer, and can just test against nil.
background: Maybe(RGB_Pixel_16),
metadata: Image_Metadata,
which: Which_File_Type,
}SourceImage_Metadata
Image_Metadata :: union {
^Netpbm_Info,
^PNG_Info,
^QOI_Info,
^TGA_Info,
^BMP_Info,
^JPEG_Info,
}SourceJFIF_APP0
JFIF_APP0 :: struct {
version: u16be,
x_density: u16be,
y_density: u16be,
units: JFIF_Unit,
x_thumbnail: u8,
y_thumbnail: u8,
greyscale_thumbnail: bool,
thumbnail: []RGB_Pixel,
}SourceJFIF_Unit
JFIF_Unit :: enum u8 {
None = 0,
Dots_Per_Inch = 1,
Dots_Per_Centimeter = 2,
}SourceJFXX_APP0
JFXX_APP0 :: struct {
extension_code: JFXX_Extension_Code,
x_thumbnail: u8,
y_thumbnail: u8,
thumbnail: []u8,
}SourceJFXX_Extension_Code
JFXX_Extension_Code :: enum u8 {
Thumbnail_JPEG = 16,
Thumbnail_1_Byte_Palette = 17,
Thumbnail_3_Byte_RGB = 19,
}SourceJPEG_Error
JPEG_Error :: enum int {
None = 0,
Duplicate_SOI_Marker = 1,
Invalid_JFXX_Extension_Code = 2,
Encountered_SOS_Before_SOF = 3,
Invalid_Quantization_Table_Precision = 4,
Invalid_Quantization_Table_Index = 5,
Invalid_Huffman_Coefficient_Type = 6,
Invalid_Huffman_Table_Index = 7,
Unsupported_Frame_Type = 8,
Invalid_Frame_Bit_Depth_Combo = 9,
Invalid_Sampling_Factor = 10,
Unsupported_12_Bit_Depth = 11,
Multiple_SOS_Markers = 12,
Encountered_RST_Marker_Outside_ECS = 13,
Extra_Data_After_SOS = 14, // Image seemed to have decoded okay, but there's more data after SOS
Invalid_Thumbnail_Size = 15,
Huffman_Symbols_Exceeds_Max = 16,
}SourceJPEG_Info
JPEG_Info :: struct {
jfif_app0: Maybe(JFIF_APP0),
jfxx_app0: Maybe(JFXX_APP0),
comments: [dynamic]string,
exif: [dynamic]Exif,
frame_type: JPEG_Marker,
}SourceJPEG_Marker
JPEG_Marker :: enum u8 {
SOF0 = 192, // Baseline sequential DCT
SOF1 = 193, // Extended sequential DCT
SOF2 = 194, // Progressive DCT
SOF3 = 195, // Lossless (sequential)
SOF5 = 197, // Differential sequential DCT
SOF6 = 198, // Differential progressive DCT
SOF7 = 199, // Differential lossless (sequential)
SOF9 = 201, // Extended sequential DCT, Arithmetic coding
SOF10 = 202, // Progressive DCT, Arithmetic coding
SOF11 = 203, // Lossless (sequential), Arithmetic coding
SOF13 = 205, // Differential sequential DCT, Arithmetic coding
SOF14 = 206, // Differential progressive DCT, Arithmetic coding
SOF15 = 207, // Differential lossless (sequential), Arithmetic coding
DHT = 196,
JPG = 200,
DAC = 204,
RST0 = 208,
RST1 = 209,
RST2 = 210,
RST3 = 211,
RST4 = 212,
RST5 = 213,
RST6 = 214,
RST7 = 215,
SOI = 216,
EOI = 217,
SOS = 218,
DQT = 219,
DNL = 220,
DRI = 221,
DHP = 222,
EXP = 223,
APP0 = 224,
APP1 = 225,
APP2 = 226,
APP3 = 227,
APP4 = 228,
APP5 = 229,
APP6 = 230,
APP7 = 231,
APP8 = 232,
APP9 = 233,
APP10 = 234,
APP11 = 235,
APP12 = 236,
APP13 = 237,
APP14 = 238,
APP15 = 239,
JPG0 = 240,
JPG1 = 241,
JPG2 = 242,
JPG3 = 243,
JPG4 = 244,
JPG5 = 245,
JPG6 = 246,
JPG7 = 247,
JPG8 = 248,
JPG9 = 249,
JPG10 = 250,
JPG11 = 251,
JPG12 = 252,
JPG13 = 253,
COM = 254,
TEM = 1,
}SourceLoader_Proc
Loader_Proc :: proc(data: []u8, options: Options, allocator: mem.Allocator) -> (img: ^Image, err: Error)SourceNetpbm_Error
Netpbm_Error :: enum int {
None = 0,
// reading
Invalid_Header_Token_Character = 1,
Incomplete_Header = 2,
Invalid_Header_Value = 3,
Duplicate_Header_Field = 4,
Buffer_Too_Small = 5,
Invalid_Buffer_ASCII_Token = 6,
Invalid_Buffer_Value = 7,
// writing
Invalid_Format = 8,
}SourceNetpbm_Format
Netpbm_Format :: enum int {
P1 = 0,
P2 = 1,
P3 = 2,
P4 = 3,
P5 = 4,
P6 = 5,
P7 = 6,
Pf = 7,
PF = 8,
}SourceNetpbm-specific definitions
Netpbm_Header
Netpbm_Header :: struct {
format: Netpbm_Format,
width: int,
height: int,
channels: int,
depth: int,
maxval: int,
tupltype: string,
scale: f32,
little_endian: bool,
}SourceNetpbm_Info
Netpbm_Info :: struct {
header: Netpbm_Header,
}SourceOS2_Header
OS2_Header :: struct #packed {
// BITMAPCOREHEADER minus info_size field
width: i16le,
height: i16le,
planes: u16le,
bpp: u16le,
}SourceOption
Option :: enum int {
// LOAD OPTIONS
info = 0,
do_not_decompress_image = 1,
return_header = 2,
return_metadata = 3,
alpha_add_if_missing = 4, // Ignored for QOI. Always returns RGBA8.
alpha_drop_if_present = 5, // Unimplemented for QOI. Returns error.
alpha_premultiply = 6, // Unimplemented for QOI. Returns error.
blend_background = 7, // Ignored for non-PNG formats
// Unimplemented
do_not_expand_grayscale = 8,
do_not_expand_indexed = 9,
do_not_expand_channels = 10,
// SAVE OPTIONS
qoi_all_channels_linear = 11, // QOI, informative only. If not set, defaults to sRGB with linear alpha.
}SourceIMPORTANT: .do_not_expand_* options currently skip handling of the alpha_* options,
therefore Gray+Alpha will be returned as such even if you add `.alpha_drop_if_present`,
and `.alpha_add_if_missing` and keyed transparency will likewise be ignored.
The same goes for indexed images. This will be remedied in a near future update.
Image_Option:
`.info`
This option behaves as `.return_metadata` and `.do_not_decompress_image` and can be used
to gather an image's dimensions and color information.
`.return_header`
Fill out img.metadata.header with the image's format-specific header struct.
If we only care about the image specs, we can set `.return_header` +
`.do_not_decompress_image`, or `.info`.
`.return_metadata`
Returns all chunks not needed to decode the data.
It also returns the header as if `.return_header` was set.
`.do_not_decompress_image`
Skip decompressing IDAT chunk, defiltering and the rest.
`.do_not_expand_grayscale`
Do not turn grayscale (+ Alpha) images into RGB(A).
Returns just the 1 or 2 channels present, although 1, 2 and 4 bit are still scaled to 8-bit.
`.do_not_expand_indexed`
Do not turn indexed (+ Alpha) images into RGB(A).
Returns just the 1 or 2 (with `tRNS`) channels present.
Make sure to use `return_metadata` to also return the palette chunk so you can recolor it yourself.
`.do_not_expand_channels`
Applies both `.do_not_expand_grayscale` and `.do_not_expand_indexed`.
`.alpha_add_if_missing`
If the image has no alpha channel, it'll add one set to max(type).
Turns RGB into RGBA and Gray into Gray+Alpha
`.alpha_drop_if_present`
If the image has an alpha channel, drop it.
You may want to use `.alpha_premultiply` in this case.
NOTE: For PNG, this also skips handling of the tRNS chunk, if present,
unless you select `alpha_premultiply`.
In this case it'll premultiply the specified pixels in question only,
as the others are implicitly fully opaque.
`.alpha_premultiply`
If the image has an alpha channel, returns image data as follows:
RGB *= A, Gray = Gray *= A
`.blend_background`
If a bKGD chunk is present in a PNG, we normally just set `img.background`
with its value and leave it up to the application to decide how to display the image,
as per the PNG specification.
With `.blend_background` selected, we blend the image against the background
color. As this negates the use for an alpha channel, we'll drop it _unless_
you also specify `.alpha_add_if_missing`.
Options that don't apply to an image format will be ignored by their loader.Options
Options :: bit_set[Option; 0..11]SourcePNG_Chunk
PNG_Chunk :: struct #packed {
header: PNG_Chunk_Header,
data: []u8,
crc: u32be,
}SourcePNG_Chunk_Header
PNG_Chunk_Header :: struct #packed {
length: u32be,
type: PNG_Chunk_Type,
}SourcePNG_Chunk_Type
PNG_Chunk_Type :: enum u32be {
// IHDR must come first in a file
IHDR = 'I' << 24 | 'H' << 16 | 'D' << 8 | 'R',
// PLTE must precede the first IDAT chunk
PLTE = 'P' << 24 | 'L' << 16 | 'T' << 8 | 'E',
bKGD = 'b' << 24 | 'K' << 16 | 'G' << 8 | 'D',
tRNS = 't' << 24 | 'R' << 16 | 'N' << 8 | 'S',
IDAT = 'I' << 24 | 'D' << 16 | 'A' << 8 | 'T',
iTXt = 'i' << 24 | 'T' << 16 | 'X' << 8 | 't',
tEXt = 't' << 24 | 'E' << 16 | 'X' << 8 | 't',
zTXt = 'z' << 24 | 'T' << 16 | 'X' << 8 | 't',
iCCP = 'i' << 24 | 'C' << 16 | 'C' << 8 | 'P',
pHYs = 'p' << 24 | 'H' << 16 | 'Y' << 8 | 's',
gAMA = 'g' << 24 | 'A' << 16 | 'M' << 8 | 'A',
tIME = 't' << 24 | 'I' << 16 | 'M' << 8 | 'E',
sPLT = 's' << 24 | 'P' << 16 | 'L' << 8 | 'T',
sRGB = 's' << 24 | 'R' << 16 | 'G' << 8 | 'B',
hIST = 'h' << 24 | 'I' << 16 | 'S' << 8 | 'T',
cHRM = 'c' << 24 | 'H' << 16 | 'R' << 8 | 'M',
sBIT = 's' << 24 | 'B' << 16 | 'I' << 8 | 'T',
// eXIf tags are not part of the core spec, but have been ratified
// in v1.5.0 of the PNG Ext register.
//
// We will provide unprocessed chunks to the caller if `.return_metadata` is set.
// Applications are free to implement an Exif decoder.
eXIf = 'e' << 24 | 'X' << 16 | 'I' << 8 | 'f',
// PNG files must end with IEND
IEND = 'I' << 24 | 'E' << 16 | 'N' << 8 | 'D',
// XCode sometimes produces "PNG" files that don't adhere to the PNG spec.
// We recognize them only in order to avoid doing further work on them.
//
// Some tools like PNG Defry may be able to repair them, but we're not
// going to reward Apple for producing proprietary broken files purporting
// to be PNGs by supporting them.
iDOT = 'i' << 24 | 'D' << 16 | 'O' << 8 | 'T',
CgBI = 'C' << 24 | 'g' << 16 | 'B' << 8 | 'I',
}SourcePNG_Color_Type
PNG_Color_Type :: bit_set[PNG_Color_Value; u8]SourcePNG_Color_Value
PNG_Color_Value :: enum u8 {
Paletted = 0, // 1 << 0 = 1
Color = 1, // 1 << 1 = 2
Alpha = 2, // 1 << 2 = 4
}SourcePNG_Error
PNG_Error :: enum int {
None = 0,
IHDR_Not_First_Chunk = 1,
IHDR_Corrupt = 2,
IDAT_Missing = 3,
IDAT_Must_Be_Contiguous = 4,
IDAT_Corrupt = 5,
IDAT_Size_Too_Large = 6,
PLTE_Encountered_Unexpectedly = 7,
PLTE_Invalid_Length = 8,
PLTE_Missing = 9,
TRNS_Encountered_Unexpectedly = 10,
TNRS_Invalid_Length = 11,
BKGD_Invalid_Length = 12,
Unknown_Color_Type = 13,
Invalid_Color_Bit_Depth_Combo = 14,
Unknown_Filter_Method = 15,
Unknown_Interlace_Method = 16,
Requested_Channel_Not_Present = 17,
Post_Processing_Error = 18,
Invalid_Chunk_Length = 19,
}SourcePNG-specific definitions
PNG_IHDR
PNG_IHDR :: struct #packed {
width: u32be,
height: u32be,
bit_depth: u8,
color_type: PNG_Color_Type,
compression_method: u8,
filter_method: u8,
interlace_method: PNG_Interlace_Method,
}SourcePNG_Info
PNG_Info :: struct {
header: PNG_IHDR,
chunks: [dynamic]PNG_Chunk,
}SourcePNG_Interlace_Method
PNG_Interlace_Method :: enum u8 {
None = 0,
Adam7 = 1,
}SourceQOI_Color_Space
QOI_Color_Space :: enum u8 {
sRGB = 0,
Linear = 1,
}SourceQOI_Error
QOI_Error :: enum int {
None = 0,
Missing_Or_Corrupt_Trailer = 1, // Image seemed to have decoded okay, but trailer is missing or corrupt.
}SourceQOI-specific definitions
QOI_Header
QOI_Header :: struct #packed {
magic: u32be,
width: u32be,
height: u32be,
channels: u8,
color_space: QOI_Color_Space,
}SourceQOI_Info
QOI_Info :: struct {
header: QOI_Header,
}SourceRGBA_Pixel
RGBA_Pixel :: [4]u8SourceRGBA_Pixel_16
RGBA_Pixel_16 :: [4]u16SourceRGB_Pixel
RGB_Pixel :: [3]u8SourceColor
RGB_Pixel_16
RGB_Pixel_16 :: [3]u16SourceTGA_Alpha_Kind
TGA_Alpha_Kind :: enum u8 {
None = 0,
Undefined_Ignore = 1,
Undefined_Retain = 2,
Useful = 3,
Premultiplied = 4,
}SourceTGA_Data_Type
TGA_Data_Type :: enum u8 {
No_Image_Data = 0,
Uncompressed_Color_Mapped = 1,
Uncompressed_RGB = 2,
Uncompressed_Black_White = 3,
Compressed_Color_Mapped = 9,
Compressed_RGB = 10,
Compressed_Black_White = 11,
}SourceTGA_Extension
TGA_Extension :: struct #packed {
extension_size: u16le,
author_name: [41]u8,
author_comments: [324]u8,
datetime: struct {
month: u16le,
day: u16le,
year: u16le,
hour: u16le,
minute: u16le,
second: u16le,
},
job_name: [41]u8,
job_time: struct {
hour: u16le,
minute: u16le,
second: u16le,
},
software_id: [41]u8,
software_version: struct #packed {
number: u16le,
letter: u8,
},
key_color: [4]u8,
aspect_ratio: [2]u16le,
gamma: [2]u16le,
color_correction_offset: u32le,
postage_stamp_offset: u32le,
scanline_offset: u32le,
attributes: TGA_Alpha_Kind,
}SourceTGA_Footer
TGA_Footer :: struct #packed {
extension_area_offset: u32le,
developer_directory_offset: u32le,
signature: [18]u8,
}SourceTGA_Header
TGA_Header :: struct #packed {
id_length: u8,
color_map_type: u8,
data_type_code: TGA_Data_Type,
color_map_origin: u16le,
color_map_length: u16le,
color_map_depth: u8,
origin: [2]u16le,
dimensions: [2]u16le,
bits_per_pixel: u8,
image_descriptor: u8,
}SourceTGA_Info
TGA_Info :: struct {
header: TGA_Header,
image_id: string,
footer: Maybe(TGA_Footer),
extension: Maybe(TGA_Extension),
}SourceWhich_File_Type
Which_File_Type :: enum int {
Unknown = 0,
BMP = 1,
DjVu = 2, // AT&T DjVu file format
EXR = 3,
FLIF = 4,
GIF = 5,
HDR = 6, // Radiance RGBE HDR
ICNS = 7, // Apple Icon Image
JPEG = 8,
JPEG_2000 = 9,
JPEG_XL = 10,
NetPBM = 11, // NetPBM family
PIC = 12, // Softimage PIC
PNG = 13, // Portable Network Graphics
PSD = 14, // Photoshop PSD
QOI = 15, // Quite Okay Image
SGI_RGB = 16, // Silicon Graphics Image RGB file format
Sun_Rast = 17, // Sun Raster Graphic
TGA = 18, // Targa Truevision
TIFF = 19, // Tagged Image File Format
WebP = 20,
XBM = 21, // X BitMap
}SourceConstants
4MAX_DIMENSIONS
MAX_DIMENSIONS :: min(#config(MAX_DIMENSIONS, 8192 * 8192), 65535 * 65535)Source67_108_864 pixels max by default.
For QOI, the Worst case scenario means all pixels will be encoded as RGBA literals, costing 5 bytes each.
This caps memory usage at 320 MiB.
The tunable is limited to 4_294_836_225 pixels maximum, or 4 GiB per 8-bit channel.
It is not advised to tune it this large.
The 64 Megapixel default is considered to be a decent upper bound you won't run into in practice,
except in very specific circumstances.New_TGA_Signature
New_TGA_Signature :: "TRUEVISION-XFILE.\x00"SourcePNG_IHDR_SIZE
PNG_IHDR_SIZE :: size_of(PNG_IHDR)SourceQOI_Magic
QOI_Magic :: u32be = u32be(0x716f6966)Source"qoif"
Variables
4Exif_Magic
Exif_Magic :: [?]u8 = [?]byte{0x45, 0x78, 0x69, 0x66}Source"Exif"
JFIF_Magic
JFIF_Magic :: [?]u8 = [?]byte{0x4A, 0x46, 0x49, 0x46}SourceJPEG-specific
JFXX_Magic
JFXX_Magic :: [?]u8 = [?]byte{0x4A, 0x46, 0x58, 0x58}Source"JFXX"
_internal_destroyers
_internal_destroyers :: [22]Destroy_ProcSourceProcedures
24alpha_add_if_missing
alpha_add_if_missing :: proc(img: ^Image, alpha_key: Alpha_Key = Alpha_Key{}, allocator: mem.Allocator = context.allocator) -> (ok: bool)SourceAdd alpha channel if missing, in-place.
Expects 1..4 channels (Gray, Gray + Alpha, RGB, RGBA).
Any other number of channels will be considered an error, returning `false` without modifying the image.
If the input image already has an alpha channel, it'll return `true` early (without considering optional keyed alpha).
If an image doesn't already have an alpha channel:
If the optional `alpha_key` is provided, it will be resolved as follows:
- For RGB, if pix = key.rgb -> pix = {0, 0, 0, key.a}
- For Gray, if pix = key.r -> pix = {0, key.g}
Otherwise, an opaque alpha channel will be added.alpha_apply_keyed_alpha
alpha_apply_keyed_alpha :: proc(img: ^Image, alpha_key: Alpha_Key = Alpha_Key{}, allocator: mem.Allocator = context.allocator) -> (ok: bool)Sourcealpha_drop_if_present
alpha_drop_if_present :: proc(img: ^Image, options: Options = Options{}, alpha_key: Alpha_Key = Alpha_Key{}, allocator: mem.Allocator = context.allocator) -> (ok: bool)SourceDrop alpha channel if present, in-place.
Expects 1..4 channels (Gray, Gray + Alpha, RGB, RGBA).
Any other number of channels will be considered an error, returning `false` without modifying the image.
Of the `options`, the following are considered:
`.alpha_premultiply`
If the image has an alpha channel, returns image data as follows:
RGB *= A, Gray = Gray *= A
`.blend_background`
If `img.background` is set, it'll be blended in like this:
RGB = (1 - A) * Background + A * RGB
If an image has 1 (Gray) or 3 (RGB) channels, it'll return early without modifying the image,
with one exception: `alpha_key` and `img.background` are present, and `.blend_background` is set.
In this case a keyed alpha pixel will be replaced with the background color.apply_palette_rgb
apply_palette_rgb :: proc(img: ^Image, palette: [256]RGB_Pixel, allocator: mem.Allocator = context.allocator) -> (ok: bool)SourceApply palette to 8-bit single-channel image and return an 8-bit RGB image, in-place. If the image given is not a valid 8-bit single channel image, the procedure will return false early.
apply_palette_rgba
apply_palette_rgba :: proc(img: ^Image, palette: [256]RGBA_Pixel, allocator: mem.Allocator = context.allocator) -> (ok: bool)SourceApply palette to 8-bit single-channel image and return an 8-bit RGBA image, in-place. If the image given is not a valid 8-bit single channel image, the procedure will return false early.
blend_pixel
blend_pixel :: proc(fg: [$N]T, alpha: T, bg: [N]T) -> (res: [N]T)Sourceblend_single_channel
blend_single_channel :: proc(fg: T, alpha: T, bg: T) -> (res: T)Sourcecompute_buffer_size
compute_buffer_size :: proc(width: int, height: int, channels: int, depth: int, extra_row_bytes: int = int(0)) -> (size: int)SourceFunction to help with image buffer calculations
destroy
destroy :: proc(img: ^Image, allocator: mem.Allocator = context.allocator)Sourceexpand_grayscale
expand_grayscale :: proc(img: ^Image, allocator: mem.Allocator = context.allocator) -> (ok: bool)SourceReplicates grayscale values into RGB(A) 8- or 16-bit images as appropriate. Returns early with false if already an RGB(A) image.
is_valid_color_image
is_valid_color_image :: proc(img: ^Image) -> (ok: bool)SourceDoes the image have 3 or 4 channels, a valid bit depth (8 or 16), Is the pointer valid, are the dimensions valid?
is_valid_grayscale_image
is_valid_grayscale_image :: proc(img: ^Image) -> (ok: bool)SourceDoes the image have 1 or 2 channels, a valid bit depth (8 or 16), Is the pointer valid, are the dimensions valid?
is_valid_image
is_valid_image :: proc(img: ^Image) -> (ok: bool)SourceDoes the image have 1..4 channels, a valid bit depth (8 or 16), Is the pointer valid, are the dimensions valid?
load_from_bytes
load_from_bytes :: proc(data: []u8, options: Options = Options{}, allocator: mem.Allocator = context.allocator) -> (img: ^Image, err: Error)Sourceload_from_file
load_from_file :: proc(filename: string, options: Options = Options{}, allocator: mem.Allocator = context.allocator) -> (img: ^Image, err: Error)Sourcepixels_to_image
pixels_to_image :: proc(pixels: [][$N]E, width: int, height: int) -> (img: Image, ok: bool)SourceTake a slice of pixels ([]RGBA_Pixel, etc), and return an Image Don't call destroy on the resulting Image. Instead, delete the original pixels slice.
premultiply_alpha
premultiply_alpha :: proc(img: ^Image) -> (ok: bool)SourceFor all pixels of the image, multiplies R, G and B by Alpha. This is useful mainly for games rendering anti-aliased transparent sprites. Grayscale with alpha images are supported as well. Note that some image formats like QOI explicitly do NOT support premultiplied alpha, so you will end up with a non-standard file.
read_data
read_data :: proc(z: C, T: typeid) -> (res: T, err: compress.General_Error)SourceHelper functions to read and write data from/to a Context, etc.
read_u8
read_u8 :: proc(z: C) -> (res: u8, err: compress.General_Error)Sourceregister
register :: proc(kind: Which_File_Type, loader: Loader_Proc, destroyer: Destroy_Proc)Sourcereturn_single_channel
return_single_channel :: proc(img: ^Image, channel: Channel) -> (res: ^Image, ok: bool)SourceWhen you have an RGB(A) image, but want a particular channel.
which_bytes
which_bytes :: proc(data: []u8) -> (Which_File_Type)Sourcewhich_file
which_file :: proc(path: string) -> (Which_File_Type)Sourcewrite_bytes
write_bytes :: proc(buf: ^bytes.Buffer, data: []u8) -> (err: compress.General_Error)Source