1

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;
}

enter image description here

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.

2
  • For clarification, I'm only trying to load PNG and JPEG files for the purpose of debugging why ImageMagick is failing. My objective is still loading PSD files. Commented Aug 20 at 0:06
  • There is way too much here for a SO question, don't expect us to review a whole repo. Anyway have you tried the standalone ImageMagick app too and did it give the same error? Might well be some plugins are not installed. Commented Aug 20 at 6:44

1 Answer 1

4

After trying using even WinDbg, I got it working by recreating my Release profile and building it as Release. I don't know why Debug was not working, if it was a debug define that Visual Studio set, or one of the many different flags used between both profiles. An exact copy from the Debug profile didn't work, so I had to make an actual Release, including optimization flags, etc. Both the Dll and the Console App started working after compiling as Release.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.