general.odin 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. package image
  2. import "core:mem"
  3. import "core:bytes"
  4. Loader_Proc :: #type proc(data: []byte, options: Options, allocator: mem.Allocator) -> (img: ^Image, err: Error)
  5. Destroy_Proc :: #type proc(img: ^Image)
  6. @(private)
  7. _internal_loaders: [Which_File_Type]Loader_Proc
  8. _internal_destroyers: [Which_File_Type]Destroy_Proc
  9. register :: proc(kind: Which_File_Type, loader: Loader_Proc, destroyer: Destroy_Proc) {
  10. assert(loader != nil)
  11. assert(destroyer != nil)
  12. assert(_internal_loaders[kind] == nil)
  13. _internal_loaders[kind] = loader
  14. assert(_internal_destroyers[kind] == nil)
  15. _internal_destroyers[kind] = destroyer
  16. }
  17. load_from_bytes :: proc(data: []byte, options := Options{}, allocator := context.allocator) -> (img: ^Image, err: Error) {
  18. loader := _internal_loaders[which(data)]
  19. if loader == nil {
  20. return nil, .Unsupported_Format
  21. }
  22. return loader(data, options, allocator)
  23. }
  24. destroy :: proc(img: ^Image, allocator := context.allocator) {
  25. if img == nil {
  26. return
  27. }
  28. context.allocator = allocator
  29. destroyer := _internal_destroyers[img.which]
  30. if destroyer != nil {
  31. destroyer(img)
  32. } else {
  33. assert(img.metadata == nil)
  34. bytes.buffer_destroy(&img.pixels)
  35. free(img)
  36. }
  37. }
  38. Which_File_Type :: enum {
  39. Unknown,
  40. BMP,
  41. DjVu, // AT&T DjVu file format
  42. EXR,
  43. FLIF,
  44. GIF,
  45. HDR, // Radiance RGBE HDR
  46. ICNS, // Apple Icon Image
  47. JPEG,
  48. JPEG_2000,
  49. JPEG_XL,
  50. NetPBM, // NetPBM family
  51. PIC, // Softimage PIC
  52. PNG, // Portable Network Graphics
  53. PSD, // Photoshop PSD
  54. QOI, // Quite Okay Image
  55. SGI_RGB, // Silicon Graphics Image RGB file format
  56. Sun_Rast, // Sun Raster Graphic
  57. TGA, // Targa Truevision
  58. TIFF, // Tagged Image File Format
  59. WebP,
  60. XBM, // X BitMap
  61. }
  62. which_bytes :: proc(data: []byte) -> Which_File_Type {
  63. test_tga :: proc(s: string) -> bool {
  64. get8 :: #force_inline proc(s: ^string) -> u8 {
  65. v := s[0]
  66. s^ = s[1:]
  67. return v
  68. }
  69. get16le :: #force_inline proc(s: ^string) -> u16 {
  70. v := u16(s[0]) | u16(s[1])<<16
  71. s^ = s[2:]
  72. return v
  73. }
  74. s := s
  75. s = s[1:] // skip offset
  76. color_type := get8(&s)
  77. if color_type > 1 {
  78. return false
  79. }
  80. image_type := get8(&s) // image type
  81. if color_type == 1 { // Colormap (Paletted) Image
  82. if image_type != 1 && image_type != 9 { // color type requires 1 or 9
  83. return false
  84. }
  85. s = s[4:] // skip index of first colormap
  86. bpcme := get8(&s) // check bits per colormap entry
  87. if bpcme != 8 && bpcme != 15 && bpcme != 16 && bpcme != 24 && bpcme != 32 {
  88. return false
  89. }
  90. s = s[4:] // skip image origin (x, y)
  91. } else { // Normal image without colormap
  92. if image_type != 2 && image_type != 3 && image_type != 10 && image_type != 11 {
  93. return false
  94. }
  95. s = s[9:] // skip colormap specification
  96. }
  97. if get16le(&s) < 1 || get16le(&s) < 1 { // test width and height
  98. return false
  99. }
  100. bpp := get8(&s) // bits per pixel
  101. if color_type == 1 && bpp != 8 && bpp != 16 {
  102. return false
  103. }
  104. if bpp != 8 && bpp != 15 && bpp != 16 && bpp != 24 && bpp != 32 {
  105. return false
  106. }
  107. return true
  108. }
  109. header: [128]byte
  110. copy(header[:], data)
  111. s := string(header[:])
  112. switch {
  113. case s[:2] == "BM":
  114. return .BMP
  115. case s[:8] == "AT&TFORM":
  116. switch s[12:16] {
  117. case "DJVU", "DJVM":
  118. return .DjVu
  119. }
  120. case s[:4] == "\x76\x2f\x31\x01":
  121. return .EXR
  122. case s[:6] == "GIF87a", s[:6] == "GIF89a":
  123. return .GIF
  124. case s[6:10] == "JFIF", s[6:10] == "Exif":
  125. return .JPEG
  126. case s[:3] == "\xff\xd8\xff":
  127. switch s[4] {
  128. case 0xdb, 0xee, 0xe1, 0xe0:
  129. return .JPEG
  130. }
  131. switch {
  132. case s[:12] == "\xff\xd8\xff\xe0\x00\x10\x4a\x46\x49\x46\x00\x01":
  133. return .JPEG
  134. }
  135. case s[:4] == "\xff\x4f\xff\x51", s[:12] == "\x00\x00\x00\x0c\x6a\x50\x20\x20\x0d\x0a\x87\x0a":
  136. return .JPEG_2000
  137. case s[:12] == "\x00\x00\x00\x0c\x4a\x58\x4c\x20\x0d\x0a\x87\x0a":
  138. return .JPEG_XL
  139. case s[0] == 'P':
  140. switch s[2] {
  141. case '\t', '\n', '\r':
  142. switch s[1] {
  143. case '1', '4': // PBM
  144. return .NetPBM
  145. case '2', '5': // PGM
  146. return .NetPBM
  147. case '3', '6': // PPM
  148. return .NetPBM
  149. case '7': // PAM
  150. return .NetPBM
  151. case 'F', 'f': // PFM
  152. return .NetPBM
  153. }
  154. }
  155. case s[:8] == "\x89PNG\r\n\x1a\n":
  156. return .PNG
  157. case s[:4] == "qoif":
  158. return .QOI
  159. case s[:2] == "\x01\xda":
  160. return .SGI_RGB
  161. case s[:4] == "\x59\xA6\x6A\x95":
  162. return .Sun_Rast
  163. case s[:4] == "MM\x2a\x00", s[:4] == "II\x00\x2A":
  164. return .TIFF
  165. case s[:4] == "RIFF" && s[8:12] == "WEBP":
  166. return .WebP
  167. case s[:8] == "#define ":
  168. return .XBM
  169. case s[:11] == "#?RADIANCE\n", s[:7] == "#?RGBE\n":
  170. return .HDR
  171. case s[:4] == "\x38\x42\x50\x53":
  172. return .PSD
  173. case s[:4] != "\x53\x80\xF6\x34" && s[88:92] == "PICT":
  174. return .PIC
  175. case s[:4] == "\x69\x63\x6e\x73":
  176. return .ICNS
  177. case s[:4] == "\x46\x4c\x49\x46":
  178. return .FLIF
  179. case:
  180. // More complex formats
  181. if test_tga(s) {
  182. return .TGA
  183. }
  184. }
  185. return .Unknown
  186. }