123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155 |
- /*
- * 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.posix;
- version(PD_USE_MAGICK):
- import core.stdc.errno;
- import core.stdc.stdio;
- import core.stdc.string;
- import std.file;
- import std.experimental.logger;
- import std.string;
- import std.path;
- import pd.gif_writer.common;
- import pd.imaging.magick;
- import pd.image_reader;
- public class GIFWriter
- {
- /**
- * Create a GIFWriter.
- * 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)
- {
- fHandle = null;
- fDestinationPath = path;
- fTemporaryPath = path ~ ".part";
- infof("GIF temporary path = %s", fTemporaryPath);
- // Check that we can write to the provided path
- FILE *file = fopen(toStringz(fTemporaryPath), "wb");
- if (null is file) {
- throw new FileException(fTemporaryPath, errno);
- }
- fclose(file);
- }
- ~this()
- {
- dispose(false);
- }
- void addImage(ImageReader reader, size_t index, GIFFrameProperties properties)
- {
- if (fDisposed || fFinalised) {
- return;
- }
- /*
- * GraphicsMagick will prepend an image if there is no previous
- * image in the list when calling 'MagickAddImage', so we keep
- * a reference to the first frame so that we can add it after
- * the second frame has been added.
- */
- if (null is fFirstFrame) {
- MagickSetImageIndex(reader.getSystemRef(), index);
- fFirstFrame = CloneMagickWand(reader.getSystemRef());
- return;
- }
- if (null is fHandle) {
- assert(fFirstFrame !is null, "Setting fHandle while fFirstFrame is null");
- MagickSetImageIndex(reader.getSystemRef(), index);
- fHandle = CloneMagickWand(reader.getSystemRef());
- MagickResetIterator(fHandle);
- MagickAddImage(fHandle, fFirstFrame);
- return;
- }
- // NOTE: We make a copy here so we don't have to worry about the
- // call to ImageReader.dispose in createGIF. This copy is
- // destroyed by the call to DestroyMagickWand() in dispose().
- MagickWand* otherHandle = CloneMagickWand(reader.getSystemRef());
- MagickSetImageIndex(otherHandle, index);
- MagickSetImageDelay(otherHandle, properties.delay / 10);
- int res = MagickAddImage(fHandle, otherHandle);
- if (res == 0) {
- // TODO: catch exception. The ExceptionInfo struct needs creating,
- // however, we need to check what ImageMagick's version looks like.
- errorf("Error adding frame: %s", fromStringz(MagickGetImageFilename(otherHandle)));
- }
- }
- void dispose()
- {
- dispose(true);
- }
- bool finalise()
- {
- if (fFinalised) {
- return true;
- }
- if (fDisposed && !fFinalised) {
- errorf("attempting to finalise and already disposed GIFWriter");
- return false;
- }
- // Go back to the start of the list so we correctly write the first frame.
- MagickResetIterator(fHandle);
- MagickSetImageIterations(fHandle, 0);
- MagickSetImageFormat(fHandle, "GIF");
- MagickWriteImages(fHandle, toStringz(fTemporaryPath), 1);
- // TODO: Error handling. The ExceptionInfo struct needs creating,
- // however, we need to check what ImageMagick's version looks like.
- rename(fTemporaryPath, fDestinationPath);
- fFinalised = true;
- return true;
- }
- private:
- MagickWand* fHandle;
- MagickWand* fFirstFrame;
- bool fDisposed = false;
- bool fFinalised = false;
- string fDestinationPath;
- string fTemporaryPath;
- void dispose(bool disposing)
- {
- if (fDisposed) {
- return;
- }
- if (null !is fHandle) {
- DestroyMagickWand(fHandle);
- }
- fDisposed = true;
- }
- }
|