ImageUtilitiesCG.cpp [plain text]
#include "config.h"
#include "ImageUtilities.h"
#include "Logging.h"
#include "MIMETypeRegistry.h"
#include <ImageIO/ImageIO.h>
#include <wtf/FileSystem.h>
#include <wtf/text/CString.h>
namespace WebCore {
WorkQueue& sharedImageTranscodingQueue()
{
static NeverDestroyed<Ref<WorkQueue>> queue(WorkQueue::create("com.apple.WebKit.ImageTranscoding"));
return queue.get();
}
static String transcodeImage(const String& path, const String& destinationUTI, const String& destinationExtension)
{
auto sourceURL = adoptCF(CFURLCreateWithFileSystemPath(kCFAllocatorDefault, path.createCFString().get(), kCFURLPOSIXPathStyle, false));
auto source = adoptCF(CGImageSourceCreateWithURL(sourceURL.get(), nullptr));
if (!source)
return nullString();
auto sourceUTI = String(CGImageSourceGetType(source.get()));
if (sourceUTI == destinationUTI)
return nullString();
auto suffix = makeString('.', destinationExtension);
FileSystem::PlatformFileHandle destinationFileHandle;
String destinationPath = FileSystem::openTemporaryFile("tempImage"_s, destinationFileHandle, suffix);
if (destinationFileHandle == FileSystem::invalidPlatformFileHandle) {
RELEASE_LOG_ERROR(Images, "transcodeImage: Destination image could not be created: %s %s\n", path.utf8().data(), destinationUTI.utf8().data());
return nullString();
}
CGDataConsumerCallbacks callbacks = {
[](void* info, const void* buffer, size_t count) -> size_t {
auto handle = *static_cast<FileSystem::PlatformFileHandle*>(info);
return FileSystem::writeToFile(handle, static_cast<const char*>(buffer), count);
},
nullptr
};
auto consumer = adoptCF(CGDataConsumerCreate(&destinationFileHandle, &callbacks));
auto destination = adoptCF(CGImageDestinationCreateWithDataConsumer(consumer.get(), destinationUTI.createCFString().get(), 1, nullptr));
CGImageDestinationAddImageFromSource(destination.get(), source.get(), 0, nullptr);
if (!CGImageDestinationFinalize(destination.get())) {
RELEASE_LOG_ERROR(Images, "transcodeImage: Image transcoding fails: %s %s\n", path.utf8().data(), destinationUTI.utf8().data());
FileSystem::closeFile(destinationFileHandle);
FileSystem::deleteFile(destinationPath);
return nullString();
}
FileSystem::closeFile(destinationFileHandle);
return destinationPath;
}
Vector<String> findImagesForTranscoding(const Vector<String>& paths, const Vector<String>& allowedMIMETypes)
{
Vector<String> transcodingPaths;
transcodingPaths.reserveInitialCapacity(paths.size());
bool needsTranscoding = false;
for (auto& path : paths) {
if (!allowedMIMETypes.contains(WebCore::MIMETypeRegistry::mimeTypeForPath(path))) {
transcodingPaths.uncheckedAppend(path);
needsTranscoding = true;
} else
transcodingPaths.uncheckedAppend(nullString());
}
return needsTranscoding ? transcodingPaths : Vector<String>();
}
Vector<String> transcodeImages(const Vector<String>& paths, const String& destinationUTI, const String& destinationExtension)
{
ASSERT(!destinationUTI.isNull());
ASSERT(!destinationExtension.isNull());
Vector<String> transcodedPaths;
transcodedPaths.reserveInitialCapacity(paths.size());
for (auto& path : paths) {
if (!path.isNull())
transcodedPaths.uncheckedAppend(transcodeImage(path, destinationUTI, destinationExtension));
else
transcodedPaths.uncheckedAppend(nullString());
}
return transcodedPaths;
}
}