skip to Main Content

I discovered via my previous question that depth appears to work differently when I use it in ImageMagick’s convert vs Magick++.

CLI version and result

Using:

$ convert /foo/bar.ppm -depth 1 /foo/out.ppm

I get an output image which, upon inspection, shows a 1-bit color depth:

$ identify /foo/out.ppm

out.ppm PPM (blah blah) 1-bit sRGB (blah blah)

C++ version and result

Using the code:

#include <Magick++.h>

int main(int argc, char **argv) {
    Magick::InitializeMagick(*argv);
    Magick::Image img;
    img.read("/foo/bar.ppm");
    Magick::Image temp_img(img);
    temp_img.depth(1);
    temp_img.write("/foo/out.ppm");
    return 0;
}

Compiled using the command:

g++ -std=c++17 test.cpp -o test `Magick++-config --cppflags --cxxflags --ldflags --libs`

Produces the output:

$ identify /foo/out.ppm

out.ppm PPM (blah blah) 8-bit sRGB (blah blah)

Hardware

I have run this with the same result on on:

  • Raspberry Pi – Raspbian 10 (buster)
  • Laptop – Ubuntu 18.04 (bionic beaver)

Software (on the RPi)

$ apt list --installed | grep magick

WARNING: apt does not have a stable CLI interface. Use with caution in scripts.

graphicsmagick-libmagick-dev-compat/stable,now 1.4+really1.3.35-1~deb10u1 all [installed]
imagemagick-6-common/stable,now 8:6.9.10.23+dfsg-2.1+deb10u1 all [installed,automatic]
imagemagick-6.q16/now 8:6.9.10.23+dfsg-2.1 armhf [installed,upgradable to: 8:6.9.10.23+dfsg-2.1+deb10u1]
imagemagick/now 8:6.9.10.23+dfsg-2.1 armhf [installed,upgradable to: 8:6.9.10.23+dfsg-2.1+deb10u1]
libgraphics-magick-perl/stable,now 1.4+really1.3.35-1~deb10u1 armhf [installed,automatic]
libgraphicsmagick++-q16-12/stable,now 1.4+really1.3.35-1~deb10u1 armhf [installed,automatic]
libgraphicsmagick++1-dev/stable,now 1.4+really1.3.35-1~deb10u1 armhf [installed,automatic]
libgraphicsmagick-q16-3/stable,now 1.4+really1.3.35-1~deb10u1 armhf [installed,automatic]
libgraphicsmagick1-dev/stable,now 1.4+really1.3.35-1~deb10u1 armhf [installed,automatic]
libmagick++-6-headers/stable,now 8:6.9.10.23+dfsg-2.1+deb10u1 all [installed,auto-removable]
libmagick++-6.q16-8/stable,now 8:6.9.10.23+dfsg-2.1+deb10u1 armhf [installed,auto-removable]
libmagickcore-6-arch-config/stable,now 8:6.9.10.23+dfsg-2.1+deb10u1 armhf [installed,auto-removable]
libmagickcore-6-headers/stable,now 8:6.9.10.23+dfsg-2.1+deb10u1 all [installed,auto-removable]
libmagickcore-6.q16-6-extra/stable,now 8:6.9.10.23+dfsg-2.1+deb10u1 armhf [installed,automatic]
libmagickcore-6.q16-6/stable,now 8:6.9.10.23+dfsg-2.1+deb10u1 armhf [installed,automatic]
libmagickwand-6-headers/stable,now 8:6.9.10.23+dfsg-2.1+deb10u1 all [installed,auto-removable]
libmagickwand-6.q16-6/stable,now 8:6.9.10.23+dfsg-2.1+deb10u1 armhf [installed,automatic]

The Picture

I’ve tested with multiple input files with sRGB type. I convert everything to NetBPM format before starting my test e.g.:

convert yourimage.jpg /foo/bar.ppm

The Question

Why is the C++ different from the Bash version? They should be linking to the exact same code in the background. The input value for depth does not need to be a special type (Magick::Image.depth takes size_t). Is there something in my installation which is messing this up? I know most of it is based on ImageMagick v6 because debian repos are notoriously slow, but nothing has changed (to my knowledge) in the source code which should effect the depth.

What else doesn’t work?

Quantization

Adding:

temp_img.quantizeColorSpace(Magick::GRAYColorspace);
temp_img.quantizeColors(1);
temp_img.quantize( );

to the code should also be a method which reduces the color depth. Again, this results in an 8-bit image in C++.

Monochrome

This results in an 8-bit image in both CLI and C++

2

Answers


  1. Chosen as BEST ANSWER

    Solution

    It appears that this problem was solved by removing problem packages previously downloaded from the Debian apt repository. It is difficult to nail down which was the offending part, but I removed:

    sudo apt remove graphicsmagick-libmagick-dev-compat imagemagick-6-common imagemagick-6.q16 imagemagick
    

    Next, I built ImageMagick from source, following the directions here.

    Explanation

    The solution was not simply a version change, which would be an understandable confusion since during the source build, I upgraded from v6 of ImageMagick still in the Debian repository to v7. However, tests by @emcconville were performed on both v6 and v7 without reproducing the errors I experienced. Presumably, since he is involved with ImageMagick development, he uses a copy built from source rather than what is available from apt-get. Therefore, we can safely assume that the problem is either in one of the Debian packages or caused by some incorrect combination of packages on the affected machine.


  2. Closest solution I can think of is to user the "PBM" format.

    Generating a test image with the following.

    convert -size 10x10 plasma: input.jpg && convert input.jpg input.ppm
    

    Just using the Magick::Image.magick method.

    #include <Magick++.h>
    
    int main(int argc, char **argv) {
        Magick::InitializeMagick(*argv);
        Magick::Image img;
        img.read("input.ppm");
        Magick::Image temp_img(img);
        temp_img.magick("PBM");
        temp_img.depth(1);
        temp_img.write("output.ppm");
        return 0;
    }
    

    We get the following file structure…

    $ hexdump -C output.ppm 
    00000000  50 34 0a 31 30 20 31 30  0a 00 00 00 00 00 00 06  |P4.10 10........|
    00000010  00 ff 80 ff c0 ff c0 ff  c0 ff c0 ff c0           |.............|
    0000001d
    

    If we want the ASCII representation of the binary data, just disable the compression.

        Magick::Image temp_img(img);
        temp_img.compressType(Magick::NoCompression);
        temp_img.magick("PBM");
        temp_img.depth(1);
        temp_img.write("output.ppm");
    

    Which would yield the following…

    $ hexdump -C output2.ppm 
    00000000  50 31 0a 31 30 20 31 30  0a 30 20 30 20 30 20 30  |P1.10 10.0 0 0 0|
    00000010  20 30 20 30 20 30 20 30  20 30 20 30 20 0a 30 20  | 0 0 0 0 0 0 .0 |
    00000020  30 20 30 20 30 20 30 20  30 20 30 20 30 20 30 20  |0 0 0 0 0 0 0 0 |
    00000030  30 20 0a 30 20 30 20 30  20 30 20 30 20 30 20 30  |0 .0 0 0 0 0 0 0|
    00000040  20 30 20 30 20 30 20 0a  30 20 30 20 30 20 30 20  | 0 0 0 .0 0 0 0 |
    00000050  30 20 31 20 31 20 30 20  30 20 30 20 0a 31 20 31  |0 1 1 0 0 0 .1 1|
    00000060  20 31 20 31 20 31 20 31  20 31 20 31 20 31 20 30  | 1 1 1 1 1 1 1 0|
    00000070  20 0a 31 20 31 20 31 20  31 20 31 20 31 20 31 20  | .1 1 1 1 1 1 1 |
    00000080  31 20 31 20 31 20 0a 31  20 31 20 31 20 31 20 31  |1 1 1 .1 1 1 1 1|
    00000090  20 31 20 31 20 31 20 31  20 31 20 0a 31 20 31 20  | 1 1 1 1 1 .1 1 |
    000000a0  31 20 31 20 31 20 31 20  31 20 31 20 31 20 31 20  |1 1 1 1 1 1 1 1 |
    000000b0  0a 31 20 31 20 31 20 31  20 31 20 31 20 31 20 31  |.1 1 1 1 1 1 1 1|
    000000c0  20 31 20 31 20 0a 31 20  31 20 31 20 31 20 31 20  | 1 1 .1 1 1 1 1 |
    000000d0  31 20 31 20 31 20 31 20  31 20 0a                 |1 1 1 1 1 .|
    000000db
    

    Don’t know if that’s exactly which you need, but should get you on track. Also might be worth reviewing WritePNMImage method in coders/pnm.c file (same file for ImageMagick-6).

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search