Problem with PSD on big endian

Post any defects you find in the released or beta versions of the ImageMagick software here. Include the ImageMagick version, OS, and any command-line required to reproduce the problem. Got a patch for a bug? Post it here.
Post Reply
fabel
Posts: 2
Joined: 2019-04-07T16:10:07-07:00
Authentication code: 1152

Problem with PSD on big endian

Post by fabel »

I came across a problem with PSD on big endian systems (both armeb and ppc64) using the MagickCore API. It works like it should on little endian (amd64) and there is also no problem with any other format on big endian (I've tried ten or so). I can provide more information, but perhaps the cause is already obvious for someone who knows the internal workings.

Here is what the image looks like on ppc64:
Image

Here is what it should look like:
Image

And here is a link to the original PSD file: http://snisurset.net/tmp/abydos.psd
User avatar
fmw42
Posts: 25562
Joined: 2007-07-02T17:14:51-07:00
Authentication code: 1152
Location: Sunnyvale, California, USA

Re: Problem with PSD on big endian

Post by fmw42 »

This seems to work for me on IM 6.9.10.39 Q16 Mac OSX Sierra

Code: Select all

convert abydos.psd[1-3] -background none -flatten result.png
Please always provide your IM version and platform/OS when asking questions on this forum. Also show your exact command line.

If your version is older and this command does not work, then consider upgrading.

Note that layer [0] in a PSD is the flattened layer, but in this case seems to be flattened against some color (white?) rather than transparent.
fabel
Posts: 2
Joined: 2019-04-07T16:10:07-07:00
Authentication code: 1152

Re: Problem with PSD on big endian

Post by fabel »

Version 7.0.8-28 on Linux (for all three archs mentioned). I didn't use convert, but the magickcore api for reading the image (and cairo for writing if). Testing with "convert abydos.dsp[0] result.png" actually works, so the problem seems to be in my code. But it's still kind of weird that the same code works on little endian and with other formats. Perhaps still worth looking into why it's so? Here is the relevant code ripped from my application to reproduce the problem:

Code: Select all

#include <cairo.h>
#include <fcntl.h>
#include <MagickCore/MagickCore.h>
#include <stdint.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <unistd.h>

#define QUANTUM_MAX (0xffffffff>>(32-MAGICKCORE_QUANTUM_DEPTH))

static cairo_surface_t *
surface_from_image(Image *image,ExceptionInfo *exception)
{
    cairo_surface_t *surface;
    const Quantum *src;
    int channels;
    uint32_t *dst;
    int rowskip;
    int x;
    int y;

    src = GetVirtualPixels(image,0,0,image->columns,image->rows,exception);
    if(exception->severity){
        ClearMagickException(exception);
        return NULL;
    }

    channels = GetPixelChannels(image);

    if(GetImageAlphaChannel(image)){
        surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32,image->columns,image->rows);
    }else{
        surface = cairo_image_surface_create(CAIRO_FORMAT_RGB24,image->columns,image->rows);
    }

    dst = (uint32_t*)cairo_image_surface_get_data(surface);
    rowskip = cairo_image_surface_get_stride(surface)/sizeof(uint32_t) - image->columns;;

    for(y=0;y<image->rows;++y){
        for(x=0;x<image->columns;++x){
            int alpha = GetPixelAlpha(image,src);
            int r = alpha*GetPixelRed(image,src)/QUANTUM_MAX;
            int g = alpha*GetPixelGreen(image,src)/QUANTUM_MAX;
            int b = alpha*GetPixelBlue(image,src)/QUANTUM_MAX;
            *dst++ = (r>>(MAGICKCORE_QUANTUM_DEPTH-8))<<16|
                     (g>>(MAGICKCORE_QUANTUM_DEPTH-8))<< 8|
                     (b>>(MAGICKCORE_QUANTUM_DEPTH-8))<< 0|
                     (alpha>>(MAGICKCORE_QUANTUM_DEPTH-8))<<24;
            src += channels;
        }
        dst += rowskip;
    }
    cairo_surface_mark_dirty(surface);
    return surface;
}


static cairo_surface_t *
surface_from_data(const char *data,size_t len)
{
    cairo_surface_t *surface = NULL;
    ExceptionInfo *exception = AcquireExceptionInfo();
    ImageInfo *info = CloneImageInfo(NULL);
    Image *image = NULL;

    strcpy(info->magick,"PSD");
    image = BlobToImage(info,data,len,exception);
    if(exception->severity)
        goto out;
    DestroyImageInfo(info);
    surface = surface_from_image(GetImageFromList(image,0),exception);
out:
    if(image)
        DestroyImage(image);
    if(exception)
        DestroyExceptionInfo(exception);
    return surface;
}

static cairo_surface_t *
surface_from_file(const char *filename)
{
    cairo_surface_t *surface = NULL;
    struct stat st;
    int fd;
    void *data;

    if(stat(filename,&st)<0)
        return NULL;

    fd = open(filename,O_RDONLY);
    if(fd<0)
        return NULL;

    data = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE | MAP_POPULATE, fd, 0);
    if(data != MAP_FAILED){
        surface = surface_from_data(data, st.st_size);
        munmap(data, st.st_size);
    }
    close(fd);
    return surface;
}

int
main(int argc,char **argv)
{
    cairo_surface_t *surface;
    MagickCoreGenesis(NULL,0);

    surface = surface_from_file("abydos.psd");
    if(surface){
        cairo_surface_write_to_png(surface, "result.png");
        cairo_surface_destroy(surface);
    }

    MagickCoreTerminus();
    return 0;
}
Post Reply