osx.d 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. /*
  2. * pixiv_down - CLI-based downloading tool for https://www.pixiv.net.
  3. * Copyright (C) 2024 Mio
  4. *
  5. * This program is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation, version 3 of the License.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  16. */
  17. module pd.gif_writer.osx;
  18. version(OSX):
  19. import pd.image_reader;
  20. import pd.gif_writer.common;
  21. import std.string;
  22. // Modelled after the CGImageDestinationRef -- the API is subject to change as other
  23. // operating systems implement the interface.
  24. public class GIFWriter
  25. {
  26. /**
  27. * Create an image destination
  28. * Params:
  29. * path = The path at which to write the image data. This object overwrites any data at the specified path.
  30. * count = The number of images you want to include in the image file.
  31. */
  32. this(string path, size_t count)
  33. {
  34. CFStringRef cfPath = CFStringCreateWithCString(kCFAllocatorDefault, toStringz(path), kCFStringEncodingUTF8);
  35. scope(exit) CFRelease(cfPath);
  36. CFURLRef url = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, cfPath, kCFURLPOSIXPathStyle, false);
  37. scope(exit) CFRelease(url);
  38. CFStringRef identifier = CFStringCreateWithCString(kCFAllocatorDefault, "com.compuserve.gif", kCFStringEncodingUTF8);
  39. scope(exit) CFRelease(identifier);
  40. this.systemRef = CGImageDestinationCreateWithURL(url, identifier, count, null);
  41. if (null is this.systemRef) {
  42. // TODO: Check if errno is set and call strerror.
  43. throw new Exception("Could not create an image at destination '" ~ path ~ "'");
  44. }
  45. const zero = 0;
  46. CFNumberRef cfZero = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &zero);
  47. scope(exit) CFRelease(cfZero);
  48. CFMutableDictionaryRef options = CFDictionaryCreateMutable(kCFAllocatorDefault, 1, null, null);
  49. if (null is options) {
  50. throw new Exception("Failed to create options");
  51. }
  52. CFDictionaryAddValue(options, kCGImagePropertyGIFLoopCount, cfZero);
  53. CFMutableDictionaryRef imageProperties = CFDictionaryCreateMutable(kCFAllocatorDefault, 1, null, null);
  54. if (null is imageProperties) {
  55. throw new Exception("Failed to create imageProperties");
  56. }
  57. CFDictionaryAddValue(imageProperties, kCGImagePropertyGIFDictionary, options);
  58. CGImageDestinationSetProperties(systemRef, imageProperties);
  59. CFRelease(options);
  60. CFRelease(imageProperties);
  61. }
  62. void addImage(ImageReader reader, size_t index, GIFFrameProperties properties)
  63. {
  64. if (disposed || finalised) {
  65. return;
  66. }
  67. float adjustedDelay = properties.delay / 1000.0;
  68. CFNumberRef delay = CFNumberCreate(kCFAllocatorDefault, kCFNumberFloatType, &adjustedDelay);
  69. scope(exit) CFRelease(delay);
  70. CFMutableDictionaryRef frameProperties = CFDictionaryCreateMutable(kCFAllocatorDefault, 1, null, null);
  71. scope(exit) CFRelease(frameProperties);
  72. CFDictionaryAddValue(frameProperties, kCGImagePropertyGIFUnclampedDelayTime, delay);
  73. CFMutableDictionaryRef gifDictionary = CFDictionaryCreateMutable(kCFAllocatorDefault, 1, null, null);
  74. scope(exit) CFRelease(gifDictionary);
  75. CFDictionaryAddValue(gifDictionary, kCGImagePropertyGIFDictionary, frameProperties);
  76. CGImageSourceRef sourceRef = reader.getSystemRef();
  77. CGImageDestinationAddImageFromSource(this.systemRef, sourceRef, index, gifDictionary);
  78. }
  79. void dispose()
  80. {
  81. if (disposed) {
  82. return;
  83. }
  84. CFRelease(systemRef);
  85. this.disposed = true;
  86. }
  87. bool finalise()
  88. {
  89. if (finalised) {
  90. return true;
  91. }
  92. if (disposed && !finalised) {
  93. // TODO: log error: already disposed.
  94. return false;
  95. }
  96. finalised = true;
  97. return CGImageDestinationFinalize(systemRef);
  98. }
  99. private:
  100. CGImageDestinationRef systemRef;
  101. bool disposed = false;
  102. bool finalised = false;
  103. }
  104. private:
  105. import core.stdc.config : c_long;
  106. @nogc:
  107. nothrow:
  108. extern(C):
  109. alias CFTypeRef = void*;
  110. alias CFAllocatorRef = CFTypeRef;
  111. alias CFDictionaryRef = CFTypeRef;
  112. alias CFIndex = c_long;
  113. alias CFMutableDictionaryRef = CFTypeRef;
  114. alias CFNumberRef = CFTypeRef;
  115. alias CFNumberType = int;
  116. alias CFStringRef = CFTypeRef;
  117. alias CFStringEncoding = int;
  118. alias CFURLRef = CFTypeRef;
  119. alias CFURLPathStyle = int;
  120. alias CGImageDestinationRef = CFTypeRef;
  121. alias CGImageSourceRef = CFTypeRef;
  122. enum kCFAllocatorDefault = null;
  123. enum : CFNumberType
  124. {
  125. kCFNumberIntType = 9,
  126. kCFNumberFloatType = 12
  127. }
  128. enum : CFStringEncoding
  129. {
  130. kCFStringEncodingUTF8 = 0x08000100,
  131. }
  132. enum : CFURLPathStyle
  133. {
  134. kCFURLPOSIXPathStyle = 0,
  135. }
  136. extern __gshared CFStringRef kCGImagePropertyGIFDictionary;
  137. extern __gshared CFStringRef kCGImagePropertyGIFUnclampedDelayTime;
  138. extern __gshared CFStringRef kCGImagePropertyGIFLoopCount;
  139. void CFRelease(void*);
  140. CFMutableDictionaryRef CFDictionaryCreateMutable(CFAllocatorRef allocator, CFIndex capacity, void* keyCallBacks, void* valueCallBacks);
  141. void CFDictionaryAddValue(CFMutableDictionaryRef theDict, const void* key, const void* value);
  142. CFNumberRef CFNumberCreate(CFAllocatorRef allocator, CFNumberType theType, const void* value);
  143. CFStringRef CFStringCreateWithCString(CFAllocatorRef allocator, const char *cStr, CFStringEncoding encoding);
  144. CFURLRef CFURLCreateWithFileSystemPath(CFAllocatorRef allocator, CFStringRef filePath, CFURLPathStyle pathStyle, bool isDirectory);
  145. CGImageDestinationRef CGImageDestinationCreateWithURL(CFURLRef url, CFStringRef type, size_t count, CFDictionaryRef options);
  146. void CGImageDestinationSetProperties(CGImageDestinationRef idst, CFDictionaryRef properties);
  147. void CGImageDestinationAddImageFromSource(CGImageDestinationRef idst, CGImageSourceRef isrc, size_t index, CFDictionaryRef properties);
  148. bool CGImageDestinationFinalize(CGImageDestinationRef idst);