123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192 |
- /*
- * pixiv_down - CLI-based downloading tool for https://www.pixiv.net.
- * Copyright (C) 2024 Mio
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, version 3 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <https://www.gnu.org/licenses/>.
- */
- module pd.gif_writer.osx;
- version(OSX):
- import pd.image_reader;
- import pd.gif_writer.common;
- import std.string;
- // Modelled after the CGImageDestinationRef -- the API is subject to change as other
- // operating systems implement the interface.
- public class GIFWriter
- {
- /**
- * Create an image destination
- * Params:
- * path = The path at which to write the image data. This object overwrites any data at the specified path.
- * count = The number of images you want to include in the image file.
- */
- this(string path, size_t count)
- {
- CFStringRef cfPath = CFStringCreateWithCString(kCFAllocatorDefault, toStringz(path), kCFStringEncodingUTF8);
- scope(exit) CFRelease(cfPath);
- CFURLRef url = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, cfPath, kCFURLPOSIXPathStyle, false);
- scope(exit) CFRelease(url);
- CFStringRef identifier = CFStringCreateWithCString(kCFAllocatorDefault, "com.compuserve.gif", kCFStringEncodingUTF8);
- scope(exit) CFRelease(identifier);
- this.systemRef = CGImageDestinationCreateWithURL(url, identifier, count, null);
- if (null is this.systemRef) {
- // TODO: Check if errno is set and call strerror.
- throw new Exception("Could not create an image at destination '" ~ path ~ "'");
- }
- const zero = 0;
- CFNumberRef cfZero = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &zero);
- scope(exit) CFRelease(cfZero);
- CFMutableDictionaryRef options = CFDictionaryCreateMutable(kCFAllocatorDefault, 1, null, null);
- if (null is options) {
- throw new Exception("Failed to create options");
- }
- CFDictionaryAddValue(options, kCGImagePropertyGIFLoopCount, cfZero);
- CFMutableDictionaryRef imageProperties = CFDictionaryCreateMutable(kCFAllocatorDefault, 1, null, null);
- if (null is imageProperties) {
- throw new Exception("Failed to create imageProperties");
- }
- CFDictionaryAddValue(imageProperties, kCGImagePropertyGIFDictionary, options);
- CGImageDestinationSetProperties(systemRef, imageProperties);
- CFRelease(options);
- CFRelease(imageProperties);
- }
- void addImage(ImageReader reader, size_t index, GIFFrameProperties properties)
- {
- if (disposed || finalised) {
- return;
- }
- float adjustedDelay = properties.delay / 1000.0;
- CFNumberRef delay = CFNumberCreate(kCFAllocatorDefault, kCFNumberFloatType, &adjustedDelay);
- scope(exit) CFRelease(delay);
- CFMutableDictionaryRef frameProperties = CFDictionaryCreateMutable(kCFAllocatorDefault, 1, null, null);
- scope(exit) CFRelease(frameProperties);
- CFDictionaryAddValue(frameProperties, kCGImagePropertyGIFUnclampedDelayTime, delay);
- CFMutableDictionaryRef gifDictionary = CFDictionaryCreateMutable(kCFAllocatorDefault, 1, null, null);
- scope(exit) CFRelease(gifDictionary);
- CFDictionaryAddValue(gifDictionary, kCGImagePropertyGIFDictionary, frameProperties);
- CGImageSourceRef sourceRef = reader.getSystemRef();
- CGImageDestinationAddImageFromSource(this.systemRef, sourceRef, index, gifDictionary);
- }
- void dispose()
- {
- if (disposed) {
- return;
- }
- CFRelease(systemRef);
- this.disposed = true;
- }
- bool finalise()
- {
- if (finalised) {
- return true;
- }
- if (disposed && !finalised) {
- // TODO: log error: already disposed.
- return false;
- }
- finalised = true;
- return CGImageDestinationFinalize(systemRef);
- }
- private:
- CGImageDestinationRef systemRef;
- bool disposed = false;
- bool finalised = false;
- }
- private:
- import core.stdc.config : c_long;
- @nogc:
- nothrow:
- extern(C):
- alias CFTypeRef = void*;
- alias CFAllocatorRef = CFTypeRef;
- alias CFDictionaryRef = CFTypeRef;
- alias CFIndex = c_long;
- alias CFMutableDictionaryRef = CFTypeRef;
- alias CFNumberRef = CFTypeRef;
- alias CFNumberType = int;
- alias CFStringRef = CFTypeRef;
- alias CFStringEncoding = int;
- alias CFURLRef = CFTypeRef;
- alias CFURLPathStyle = int;
- alias CGImageDestinationRef = CFTypeRef;
- alias CGImageSourceRef = CFTypeRef;
- enum kCFAllocatorDefault = null;
- enum : CFNumberType
- {
- kCFNumberIntType = 9,
- kCFNumberFloatType = 12
- }
- enum : CFStringEncoding
- {
- kCFStringEncodingUTF8 = 0x08000100,
- }
- enum : CFURLPathStyle
- {
- kCFURLPOSIXPathStyle = 0,
- }
- extern __gshared CFStringRef kCGImagePropertyGIFDictionary;
- extern __gshared CFStringRef kCGImagePropertyGIFUnclampedDelayTime;
- extern __gshared CFStringRef kCGImagePropertyGIFLoopCount;
- void CFRelease(void*);
- CFMutableDictionaryRef CFDictionaryCreateMutable(CFAllocatorRef allocator, CFIndex capacity, void* keyCallBacks, void* valueCallBacks);
- void CFDictionaryAddValue(CFMutableDictionaryRef theDict, const void* key, const void* value);
- CFNumberRef CFNumberCreate(CFAllocatorRef allocator, CFNumberType theType, const void* value);
- CFStringRef CFStringCreateWithCString(CFAllocatorRef allocator, const char *cStr, CFStringEncoding encoding);
- CFURLRef CFURLCreateWithFileSystemPath(CFAllocatorRef allocator, CFStringRef filePath, CFURLPathStyle pathStyle, bool isDirectory);
- CGImageDestinationRef CGImageDestinationCreateWithURL(CFURLRef url, CFStringRef type, size_t count, CFDictionaryRef options);
- void CGImageDestinationSetProperties(CGImageDestinationRef idst, CFDictionaryRef properties);
- void CGImageDestinationAddImageFromSource(CGImageDestinationRef idst, CGImageSourceRef isrc, size_t index, CFDictionaryRef properties);
- bool CGImageDestinationFinalize(CGImageDestinationRef idst);
|