Page 1 of 1

MagickSetExtract() segfaults

Posted: 2014-07-19T23:25:33-07:00
by Greg Minshall
hi.

i'm running the following on macosx 10.9.3, using Fink:
----
Version: ImageMagick 6.8.8-10 Q16 x86_64 2014-04-24 http://www.imagemagick.org
----

i'm trying to use MagickSetExtract() to specify which bits of a large image i want to read. the MagickWand web page says
----
MagickSetExtract() sets the extract geometry before you read or write an image file. Use it for inline cropping (e.g. 200x200+0+0) or resizing (e.g.200x200).
----
which leads me to believe i should call it before calling, e.g., MagickReadImage(). however, i get a segfault when i run the simple program below.

any help would be appreciated.

cheers, Greg Minshall

----
running the following code on my system gives me:
----
bash greg-minshalls-mbp: {1361} ./test 200x200+0+0 ../tests/c-L1001745.png
got image_wand
about to call magicksetextract with 200x200+0+0
Segmentation fault: 11
----

the code:
-----
#include <stdio.h>
#include <wand/MagickWand.h>

int main(int argc, char *argv[]) {
MagickBooleanType status;
MagickWand *image_wand;
char *file, *geometry;

file = "../tests/foo.png"; /* doesn't matter -- doesn't get that far! */
geometry = "200x200+0+0"; /* anything (apparently) will do */

/* Read an image. */
MagickWandGenesis();
image_wand = NewMagickWand();
fprintf(stderr, "got image_wand\n");
if (geometry) {
fprintf(stderr, "about to call magicksetextract with %s\n", geometry);
status = MagickSetExtract(image_wand, geometry);
fprintf(stderr, "return from magicksetextract, status %d\n", status);
if (status == MagickFalse) {
fprintf(stderr, "error from MagickSetExtract\n");
exit(1);
/*NOTREACHED*/
}
}
fprintf(stderr, "about to call magickreadimage\n");
status = MagickReadImage(image_wand, file);
fprintf(stderr, "return from magickreadimage\n");
if (status == MagickFalse) {
fprintf(stderr, "error from MagickReadImage\n");
exit(2);
/*NOTREACHED*/
}

}

Re: MagickSetExtract() segfaults

Posted: 2014-07-20T02:34:22-07:00
by Greg Minshall
to semi-answer my own question, it *appears* as if MagickSetExtract() believes that image_info->extract is set, when it isn't. a simple fix (using some code found elsewhere in the ImageMagick source tree for setting image_info->extract) seems to fix this, and, indeed, reading a small bit of a large image is nicely sped up.

but, i still have a question about the output side. i am able to use (the new) MagickSetExtract() to set the extract for the write, but this appears to be ignored. *should* this work? i'm happy to provide my test.c code for this (but don't want to overwhelm people's patience).

below are diffs for MagickSetExtract(). (NB: i didn't actually re-build MagickWand; rather, i copied and pasted this code into my test.c program and compiled it there; so, while my mods are simple, they haven't *actually* be compiled in the actual file.)

Code: Select all

----
--- magick-property.c   2014-01-14 23:51:05.000000000 +0200
+++ n.magick-property.c 2014-07-20 12:31:39.000000000 +0300
@@ -2042,8 +2042,10 @@
   assert(wand->signature == WandSignature);
   if (wand->debug != MagickFalse)
     (void) LogMagickEvent(WandEvent,GetMagickModule(),"%s",wand->name);
+  if (wand->image_info->extract != (char *) NULL)
+    wand->image_info->extract=DestroyString(wand->image_info->extract);
   if (geometry != (const char *) NULL)
-    (void) CopyMagickString(wand->image_info->extract,geometry,MaxTextExtent);
+    (void) CloneString(&wand->image_info->extract,geometry);
   return(MagickTrue);
 }

Re: MagickSetExtract() segfaults

Posted: 2014-07-20T04:44:17-07:00
by magick
We can reproduce the problem you posted and have a patch in ImageMagick 6.8.9-6 Beta, available by sometime tomorrow. Thanks.

Re: MagickSetExtract() segfaults

Posted: 2014-07-27T06:12:59-07:00
by Greg Minshall
hi. thanks very much for the fix, which prevents the segfault, and allows MagickSetExtract to work for reading image files.

however, MagickSetExtract still does *not* work (at least as i am led to believe it should) for writing files. to be somewhat repetitive, from the documentation:
----
MagickSetExtract() sets the extract geometry before you read or write an image file. Use it for inline cropping (e.g. 200x200+0+0) or resizing (e.g.200x200).
----

if the below program is built and run to extract on read, one gets a nice, small, extract of the image (and it runs very quickly). however, if one reads the original (large) size file and then attempts to write an extract, the extract is the same size as the original (large) size file (and it runs very slowly):

Code: Select all

bash greg-minshalls-mbp: {1435} gcc -g3 -I /tmp/imagemagick/include/ImageMagick-6/  -DMAGICKCORE_HDRI_ENABLE=1 -DMAGICKCORE_QUANTUM_DEPTH=16 -L /tmp/imagemagick/lib test.c -lMagickWand-6.Q16 -lMagickCore-6.Q16 -lm -o test
bash greg-minshalls-mbp: {1436} rm x.png; ./test L1001745.tif 26x47+1022+3826 x.png ""; identify x.png
x.png PNG 26x47 5976x3992+1022+3826 16-bit sRGB 19KB 0.000u 0:00.000
bash greg-minshalls-mbp: {1437} rm x.png; ./test L1001745.tif "" x.png 26x47+1022+3826; identify x.png
x.png PNG 5976x3992 5976x3992+0+0 16-bit sRGB 118.8MB 0.000u 0:00.000
cheers, Greg Minshall
----

Code: Select all

#include <stdio.h>

#include <sys/errno.h>
#include <sys/stat.h>

#include <wand/MagickWand.h>

static int debug=0;

int main(int argc, char *argv[]) {
    MagickBooleanType status;
    MagickWand *image_wand;
    char *infile, *ingeometry;
    char *outfile, *outgeometry;
    struct stat statbuf;

    if (argc != 5) {
        fprintf(stderr,
                "usage: %s infile ingeometry outfile outgeometry\n", argv[0]);
        exit(1);
    }
    infile = argv[1];
    ingeometry = argv[2];
    outfile = argv[3];
    outgeometry = argv[4];

    if ((stat(outfile, &statbuf) != -1) || (errno != ENOENT)) {
        fprintf(stderr, "file \"%s\" exists, not overwritten\n", outfile);
        exit(1);
    }

    
    /* Read an image. */
    MagickWandGenesis();
    image_wand = NewMagickWand();
    if (debug) {
        fprintf(stderr, "got image_wand\n");
    }
    if (ingeometry && ingeometry[0]) {
        if (debug) {
            fprintf(stderr, "about to call magicksetextract with %s\n", ingeometry);
        }
        status = MagickSetExtract(image_wand, ingeometry);
        if (debug) {
            fprintf(stderr, "return from magicksetextract, status %d\n", status);
        }
        if (status == MagickFalse) {
            fprintf(stderr, "error from MagickSetExtract\n");
            exit(1);
            /*NOTREACHED*/
        }
    }
    if (debug) {
        fprintf(stderr, "about to call magickreadimage\n");
    }
    status = MagickReadImage(image_wand, infile);
    if (debug) {
        fprintf(stderr, "return from magickreadimage\n");
    }
    if (status == MagickFalse) {
        fprintf(stderr, "error from MagickReadImage\n");
        exit(2);
        /*NOTREACHED*/
    }

    if (outgeometry) {
        if (debug) {
            fprintf(stderr, "about to call magicksetextract with %s\n", outgeometry);
        }
        if (!MagickSetExtract(image_wand, outgeometry)) {
            fprintf(stderr, "error from MagickSetExtract\n");
            exit(3);
            /*NOTREACHED*/
        }
        if (debug) {
            fprintf(stderr, "return from magicksetextract\n");
        }
    }
    if (debug) {
        fprintf(stderr, "about to call magickwriteimage\n");
    }
    if (!MagickWriteImage(image_wand, outfile)) {
        fprintf(stderr, "error from MagickWriteImage\n");
        exit(4);
        /*NOTREACHED*/
    }
    if (debug) {
        fprintf(stderr, "return from magickwriteimage\n");
    }
    DestroyMagickWand(image_wand);
    MagickWandTerminus();
}