I'm currently trying to implement an IThumbnailProvider to render a thumbnail for PSD files on the explorer. I plan to use ImageMagick and it's C++ API (Magick++) to do so, as I've used this lib before. All is good, until ImageMagick has to load files: It raises an exception with a message no decode delegate for this image format `' @ error/constitute.c/ReadImage/746.
This exception is raised with any kind of image file: PSD, PNG, JPEGs, either loading from file paths or from Blobs, so my guess is that ImageMagick is having trouble identifying file formats, as it can't even give it's name on the exception message.
PSDThumbnailProvider.cpp where I call Magick::InitializeMagick()
#include "pch.h"
#include "PSDThumbnailProvider.h"
#include "PSDReader.h"
#include <Magick++.h>
...
bool g_magickInitialized = false;
PSDThumbnailProvider::PSDThumbnailProvider() {
...
if (!g_magickInitialized) {
char dllPath[MAX_PATH];
GetModuleFileNameA(g_hModule, dllPath, MAX_PATH);
// I'm not sure this is right, but it makes the exception popup have my dll's name
// on it, instead of "DllHost.exe"
Magick::InitializeMagick(dllPath);
g_magickInitialized = true;
}
}
...
PSDReader.cpp
#include "pch.h"
#include "PSDReader.h"
#include <Magick++.h>
HRESULT getStreamLength(IStream* pstream, size_t* pLength) {
STATSTG stat;
HRESULT hr = pstream->Stat(&stat, STATFLAG_DEFAULT);
*pLength = stat.cbSize.QuadPart;
return hr;
}
HRESULT PSDReader::CreateThumbnailBitmap(
IStream* pstream,
UINT maxWidth, UINT maxHeigth,
HBITMAP* phbmp, WTS_ALPHATYPE* pdwAlpha)
{
// Get stream length
size_t streamLength;
HRESULT hr = getStreamLength(pstream, &streamLength);
if (FAILED(hr)) return hr;
// Read from stream until end
std::vector<unsigned char> buffer(streamLength);
ULONG bytesRead = 0;
while (bytesRead < streamLength) {
ULONG chunk = 0;
HRESULT hr = pstream->Read(
buffer.data() + bytesRead,
streamLength - bytesRead,
&chunk);
if (FAILED(hr) || chunk == 0) break;
bytesRead += chunk;
}
if (bytesRead != streamLength) {
return E_FAIL; // Truncated is bad
}
// Load ImageMagick's Image from the buffer
Magick::Image magickImage;
Magick::Blob blob = Magick::Blob(buffer.data(), bytesRead);
try {
magickImage.read(blob);
// This does not throw an exception, but `magickImage.format()` doesn't work.
// `magickImage.columns()`, `magickImage.rows()` and `magickImage.thumbnail()` seem to work.
}
catch (Magick::Exception&) {
return E_FAIL;
}
{ // Debugging image loading
try {
Magick::Image magickImage;
magickImage.read("G:\\test\\test.jpeg");
MessageBoxA(NULL, "It works!", "Debug", MB_OK);
}
catch (Magick::Exception& ex) {
MessageBoxA(NULL, ex.what(), "Debug", MB_OK | MB_ICONERROR);
}
}
return S_OK;
}
On a similar note, ImageMagick also fails here, with a similar error PSDThumbnailProvider.dll: unrecognized pixel map `æÉ'º @ error/pixel.c/ExportImagePixels/2086, when loading from a Magick::Blob:
const size_t actualWidth = magickImage.columns();
const size_t actualHeight = magickImage.rows();
std::vector<unsigned char> pixels(actualWidth * actualHeight * 4);
try {
magickImage.write(0, 0, actualWidth, actualHeight, "BGRA", Magick::CharPixel, pixels.data());
MessageBoxW(NULL, L"It works!", L"Debug", MB_OK);
}
catch (Magick::Exception& ex) {
MessageBoxA(NULL, ex.what(), "Debug", MB_OK | MB_ICONERROR);
// Is throwing "unrecognized pixel map" and sometimes "memory allocation failed" or something like that
return E_FAIL;
}
I created a C++ Console App to debug better, and it gets stuck on the read() call, but throws nothing, and the output console on Visual Studio shows no error. If I use a random path of a file that does not exist, same thing happens.
#include <Windows.h>
#include <Magick++.h>
int main(int argc, char** argv)
{
Magick::InitializeMagick(*argv);
Magick::Image magickImage;
try {
magickImage.read("G:\\test\\test.jpg");
}
catch (std::exception &ex){
return E_FAIL;
}
return S_OK;
}
Running magick identify -list format lists many things, including PSD and the common PNG, JPEG, etc, formats.
Running magick -list configure outputs:
Path: [built-in]
Name Value
-------------------------------------------------------------------------------
DELEGATES bzlib cairo freetype gslib heic jng jp2 jpeg jxl lcms lqr lzma openexr pangocairo png ps raqm raw rsvg tiff webp xml zip zlib
FEATURES Channel-masks(64-bit) Cipher DPC Modules OpenCL OpenMP(2.0)
MAGICK_TEMPORARY_PATH C:/Users/UCQ/AppData/Local/Temp
NAME ImageMagick
QuantumDepth Q8
Path: C:\Program Files\ImageMagick-7.1.2-Q8\configure.xml
Name Value
-------------------------------------------------------------------------------
CC VS2022
CHANNEL_MASK_DEPTH 64
COPYRIGHT Copyright (C) 1999 ImageMagick Studio LLC
CXX VS2022
DOCUMENTATION_PATH unavailable
GIT_REVISION 83b6fc3:20250811
LIB_VERSION 0x712
LIB_VERSION_NUMBER 7,1,2,1
NAME ImageMagick
QuantumDepth 8
RELEASE_DATE 2025-08-12
TARGET_CPU x64
TARGET_OS Windows
VERSION 7.1.2
WEBSITE https://imagemagick.org
Dependencies.exe claims that my dll is correctly loading CORE_RL_Magick++_.dll from ImageMagick's installation path, but I see no other dll related to ImageMagick.
I'm using ImageMagick 7.1.2-1 Q8 x64, but also tried with Q16. I tried building from source but I was not able to build it. I also tried copying the dll files from ImageMagick's installation folder to my .dll's and hoping for the best. I'm using Visual Studio 2022, which magick -version claims to also have been compiled with.
The entire repo is here, but you'll have to configure the path for ImageMagick's libs and includes for your own environment before building it.
EDIT: Magick's cmd tools work just fine, both the installed and the portable versions. I know this question is way too big, but to be fair I don't know what's relevant to solve this issue. The repository is there for if someone finds it useful to the issue, I don't expect anyone to actually clone it.
