magick.scm 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  1. ;;; guile-openai --- An OpenAI API client for Guile
  2. ;;; Copyright © 2023 Andrew Whatson <whatson@tailcall.au>
  3. ;;;
  4. ;;; This file is part of guile-openai.
  5. ;;;
  6. ;;; guile-openai is free software: you can redistribute it and/or modify
  7. ;;; it under the terms of the GNU Affero General Public License as
  8. ;;; published by the Free Software Foundation, either version 3 of the
  9. ;;; License, or (at your option) any later version.
  10. ;;;
  11. ;;; guile-openai is distributed in the hope that it will be useful, but
  12. ;;; WITHOUT ANY WARRANTY; without even the implied warranty of
  13. ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. ;;; Affero General Public License for more details.
  15. ;;;
  16. ;;; You should have received a copy of the GNU Affero General Public
  17. ;;; License along with guile-openai. If not, see
  18. ;;; <https://www.gnu.org/licenses/>.
  19. (define-module (openai utils magick)
  20. #:use-module (openai config)
  21. #:use-module (openai utils foreign)
  22. #:use-module (ice-9 match)
  23. #:use-module (rnrs bytevectors)
  24. #:use-module (srfi srfi-9)
  25. #:use-module ((system foreign) #:prefix ffi:)
  26. #:export (magick-alpha-channel-options
  27. magick-convert-image
  28. magick-create-image))
  29. (define-foreign-library libMagickWand %libmagickwand)
  30. (define-foreign-enum-type alpha-channel-enum int
  31. alpha-channel? alpha-channel-list
  32. int->alpha-channel alpha-channel->int
  33. (Undefined
  34. Activate
  35. Associate
  36. Background
  37. Copy
  38. Deactivate
  39. Discrete
  40. Disassociate
  41. Extract
  42. Off
  43. On
  44. Opaque
  45. Remove
  46. Set
  47. Shape
  48. Transparent))
  49. (define-foreign-enum-type exception-type-enum int
  50. exception-type? exception-type-list
  51. int->exception-type exception-type->int
  52. (UndefinedException
  53. WarningException => 300
  54. ResourceLimitWarning => 300
  55. TypeWarning => 305
  56. OptionWarning => 310
  57. DelegateWarning => 315
  58. MissingDelegateWarning => 320
  59. CorruptImageWarning => 325
  60. FileOpenWarning => 330
  61. BlobWarning => 335
  62. StreamWarning => 340
  63. CacheWarning => 345
  64. CoderWarning => 350
  65. FilterWarning => 352
  66. ModuleWarning => 355
  67. DrawWarning => 360
  68. ImageWarning => 365
  69. WandWarning => 370
  70. RandomWarning => 375
  71. XServerWarning => 380
  72. MonitorWarning => 385
  73. RegistryWarning => 390
  74. ConfigureWarning => 395
  75. PolicyWarning => 399
  76. ErrorException => 400
  77. ResourceLimitError => 400
  78. TypeError => 405
  79. OptionError => 410
  80. DelegateError => 415
  81. MissingDelegateError => 420
  82. CorruptImageError => 425
  83. FileOpenError => 430
  84. BlobError => 435
  85. StreamError => 440
  86. CacheError => 445
  87. CoderError => 450
  88. FilterError => 452
  89. ModuleError => 455
  90. DrawError => 460
  91. ImageError => 465
  92. WandError => 470
  93. RandomError => 475
  94. XServerError => 480
  95. MonitorError => 485
  96. RegistryError => 490
  97. ConfigureError => 495
  98. PolicyError => 499
  99. FatalErrorException => 700
  100. ResourceLimitFatalError => 700
  101. TypeFatalError => 705
  102. OptionFatalError => 710
  103. DelegateFatalError => 715
  104. MissingDelegateFatalError => 720
  105. CorruptImageFatalError => 725
  106. FileOpenFatalError => 730
  107. BlobFatalError => 735
  108. StreamFatalError => 740
  109. CacheFatalError => 745
  110. CoderFatalError => 750
  111. FilterFatalError => 752
  112. ModuleFatalError => 755
  113. DrawFatalError => 760
  114. ImageFatalError => 765
  115. WandFatalError => 770
  116. RandomFatalError => 775
  117. XServerFatalError => 780
  118. MonitorFatalError => 785
  119. RegistryFatalError => 790
  120. ConfigureFatalError => 795
  121. PolicyFatalError => 799))
  122. (define-foreign-pointer-type wand-ptr <wand>
  123. wand? pointer->wand wand->pointer)
  124. (define-foreign-return-type wand-error int
  125. (lambda (result wand . _)
  126. (when (zero? result)
  127. (apply error (MagickGetException wand)))))
  128. (define-foreign-pointer-type pixel-wand-ptr <pixel-wand>
  129. pixel-wand? pointer->pixel-wand pixel-wand->pointer)
  130. (define-foreign-return-type pixel-wand-error int
  131. (lambda (result pixel-wand . _)
  132. (when (zero? result)
  133. (apply error (PixelGetException pixel-wand)))))
  134. (define-foreign-functions libMagickWand
  135. (MagickWandGenesis -> void)
  136. (MagickWandTerminus -> void)
  137. (NewMagickWand -> wand-ptr)
  138. (DestroyMagickWand wand-ptr -> wand-ptr)
  139. (MagickRelinquishMemory pointer -> pointer)
  140. (MagickGetException wand-ptr pointer -> pointer)
  141. (MagickReadImage wand-ptr cstring -> wand-error)
  142. (MagickReadImageBlob wand-ptr pointer size_t -> wand-error)
  143. (MagickNewImage wand-ptr size_t size_t pixel-wand-ptr -> wand-error)
  144. (MagickWriteImage wand-ptr cstring -> bool)
  145. (MagickGetImageBlob wand-ptr pointer -> pointer)
  146. (MagickGetImageFormat wand-ptr -> cstring)
  147. (MagickSetImageFormat wand-ptr cstring -> wand-error)
  148. (MagickGetImageAlphaChannel wand-ptr -> alpha-channel-enum)
  149. (MagickSetImageAlphaChannel wand-ptr alpha-channel-enum -> wand-error)
  150. (NewPixelWand -> pixel-wand-ptr)
  151. (DestroyPixelWand pixel-wand-ptr -> pixel-wand-ptr)
  152. (PixelGetException pixel-wand-ptr pointer -> pointer)
  153. (PixelSetColor pixel-wand-ptr cstring -> pixel-wand-error)
  154. (PixelSetAlpha pixel-wand-ptr double -> void))
  155. (define %MagickGetException MagickGetException)
  156. (define (MagickGetException wand)
  157. (let* ((type-ptr (ffi:make-c-struct (list ffi:int) (list 0)))
  158. (message-ptr (%MagickGetException wand type-ptr))
  159. (message (ffi:pointer->string message-ptr))
  160. (type-int (car (ffi:parse-c-struct type-ptr (list ffi:int))))
  161. (type (int->exception-type type-int)))
  162. (MagickRelinquishMemory message-ptr)
  163. (list type message)))
  164. (define %MagickReadImageBlob MagickReadImageBlob)
  165. (define (MagickReadImageBlob wand bv)
  166. (let ((ptr (ffi:bytevector->pointer bv))
  167. (len (bytevector-length bv)))
  168. (%MagickReadImageBlob wand ptr len)))
  169. (define %MagickGetImageBlob MagickGetImageBlob)
  170. (define (MagickGetImageBlob wand)
  171. (let* ((len-ptr (ffi:make-c-struct (list ffi:size_t) (list 0)))
  172. (data-ptr (%MagickGetImageBlob wand len-ptr))
  173. (data-len (car (ffi:parse-c-struct len-ptr (list ffi:size_t)))))
  174. (ffi:pointer->bytevector data-ptr data-len)))
  175. (define %PixelGetException PixelGetException)
  176. (define (PixelGetException pixel-wand)
  177. (let* ((type-ptr (ffi:make-c-struct (list ffi:int) (list 0)))
  178. (message-ptr (%PixelGetException pixel-wand type-ptr))
  179. (message (ffi:pointer->string message-ptr))
  180. (type-int (car (ffi:parse-c-struct type-ptr (list ffi:int))))
  181. (type (int->exception-type type-int)))
  182. (MagickRelinquishMemory message-ptr)
  183. (list type message)))
  184. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  185. (define (call-with-pointer alloc free proc)
  186. (let ((ptr #f))
  187. (dynamic-wind
  188. (const #t)
  189. (lambda ()
  190. (set! ptr (alloc))
  191. (proc ptr))
  192. (lambda ()
  193. (when ptr
  194. (free ptr))))))
  195. (define (call-with-magick-wand proc)
  196. (call-with-pointer NewMagickWand DestroyMagickWand proc))
  197. (define (call-with-pixel-wand proc)
  198. (call-with-pointer NewPixelWand DestroyPixelWand proc))
  199. (define (magick-alpha-channel-options)
  200. (alpha-channel-list))
  201. (define* (magick-convert-image image-bytes #:key
  202. format
  203. alpha-channel)
  204. (call-with-magick-wand
  205. (lambda (wand)
  206. (MagickReadImageBlob wand image-bytes)
  207. (when format
  208. (MagickSetImageFormat wand format))
  209. (when alpha-channel
  210. (MagickSetImageAlphaChannel wand alpha-channel))
  211. (MagickGetImageBlob wand))))
  212. (define* (magick-create-image #:key width height
  213. format
  214. background-color
  215. background-alpha
  216. alpha-channel)
  217. (call-with-magick-wand
  218. (lambda (wand)
  219. (call-with-pixel-wand
  220. (lambda (background)
  221. (when background-color
  222. (PixelSetColor background background-color))
  223. (when background-alpha
  224. (PixelSetAlpha background background-alpha))
  225. (MagickNewImage wand width height background)))
  226. (when format
  227. (MagickSetImageFormat wand format))
  228. (when alpha-channel
  229. (MagickSetImageAlphaChannel wand alpha-channel))
  230. (MagickGetImageBlob wand))))
  231. (MagickWandGenesis)