{.compile("oiio.cpp","-std=c++14").} {.passL: "-lOpenImageIO -lOpenImageIO_Util".} type OiioImageFormat* {.size: 4.} = enum FORMAT_UNKNOWN = 0 FORMAT_BYTE # 8-bit unsigned FORMAT_SHORT # 16-bit unsigned FORMAT_HALF # 16-bit float FORMAT_FLOAT # 32-bit float template size*(format: OiioImageFormat): int = case format: of FORMAT_BYTE: 1 of FORMAT_SHORT: 2 of FORMAT_HALF: 2 of FORMAT_FLOAT: 4 else: 0 proc decode(input: pointer, input_len: int, output: pointer, output_len: int, desired_channels: int32, format: OiioImageFormat, is_BGR: var byte, file_name: cstring): int32 {.importc:"oiio_image_decode", cdecl.} proc get_attributes(input: pointer, input_len: int, width: var int32, height: var int32, channels: var int32, format: var OiioImageFormat, file_name: cstring): int32 {.importc:"oiio_image_get_attributes", cdecl.} template has_bytes(p: pointer, bytes: string): bool = cmpMem(p, bytes.cstring, bytes.len) == 0 proc file_name_from_magic(input: openArray[byte]): string = if input.len < 10: return "image" var p = input[0].addr # OpenImageIO usually has no trouble detecting the most common formats, # however it seems we need to give it a file name for some, like EXR. if p.has_bytes "\x89PNG": return "image.png" if p.has_bytes "\xFF\xD8\xFF": return "image.jpg" if p.has_bytes "v/1\x01": return "image.exr" if p.has_bytes "#?RADIANCE": return "image.hdr" return "image" proc oiioImageGetAttributes*(input: openArray[byte]): (int, int, int, OiioImageFormat) = # returns: width, height, channels, format doAssert input.len != 0, "input is empty" let file_name = file_name_from_magic(input) var w,h,c: int32 var f: OiioImageFormat var res = get_attributes(input[0].addr, input.len, w,h,c,f, file_name.cstring) doAssert res != 0, "error getting image attibutes" doAssert f != FORMAT_UNKNOWN, "unknown image format" return (w.int, h.int, c.int, f) proc oiioImageDecode*[T](input: openArray[byte], min_channels = 0): seq[T] = doAssert input.len != 0, "input is empty" let file_name = file_name_from_magic(input) var w,h,c: int32 var f: OiioImageFormat var res = get_attributes(input[0].addr, input.len, w,h,c,f, file_name.cstring) doAssert res != 0, "error getting image attibutes" doAssert w != 0 and h != 0 and c != 0, "invalid image" let channels = max(min_channels.int32, c) # let size_in = w * h * c let size_out = w * h * channels result.setLen size_out * f.size var is_BGR: byte res = decode(input[0].addr, input.len, result[0].addr, size_out * f.size, channels, f, is_BGR, file_name.cstring) doAssert res != 0, "error decoding image"