gographics / imagick

Go binding to ImageMagick's MagickWand C API
https://godoc.org/github.com/gographics/imagick/imagick
Other
1.77k stars 184 forks source link

imagick.ConvertImageCommand() prints some geometry strings to stdout unexpectedly #318

Closed teerapap closed 5 months ago

teerapap commented 5 months ago

Problem Statement

My code calls function imagick.ConvertImageCommand(....) in a loop for a couple of times, it prints some geometry strings unexpectedly to stdout.

I'm not sure if this is a bug of this go bindings or the MagickWand C library.

How to Reproduce

This is the code that I can reproduce the problem.

    for i := 0; i < 100; i++ {
        ret, err := imagick.ConvertImageCommand([]string{
            "convert",
            "image.png",
            "-bordercolor", "white", // guiding border so that it trims only specified background color
            "-border", "1",
            "-fuzz", "10%",
            "-format", "%@",
            "info:",
        })
        if err != nil {
            return fmt.Errorf("finding trim box: %w", err)
        }
        ret.Info.Destroy()
    }

Around the 70th to 80th round, it will print strings like this to stdout (or stderr I'm not sure). This geometry 1420x2083+1+1 looks like the input image.png geometry with border.

1420x2083+1+11420x2083+1+11420x2083+1+11420x2083+1+11420x2083+1+11420x2083+1+11420x2083+1+11420x2083+1+11420x2083+1+11420x2083+1+11420x2083+1+11420x2083+1+11420x2083+1+11420x2083+1+11420x2083+1+11420x2083+1+11420x2083+1+11420x2083+1+11420x2083+1+11420x2083+1+11420x2083+1+11420x2083+1+11420x2083+1+11420x2083+1+11420x2083+1+11420x2083+1+11420x2083+1+11420x2083+1+11420x2083+1+11420x2083+1+11420x2083+1+11420x2083+1+11420x2083+1+11420x2083+1+11420x2083+1+11420x2083+1+11420x2083+1+11420x2083+1+11420x2083+1+11420x2083+1+11420x2083+1+11420x2083+1+11420x2083+1+11420x2083+1+11420x2083+1+11420x2083+1+11420x2083+1+11420x2083+1+11420x2083+1+11420x2083+1+11420x2083+1+11420x2083+1+11420x2083+1+11420x2083+1+11420x2083+1+11420x2083+1+11420x2083+1+11420x2083+1+11420x2083+1+11420x2083+1+11420x2083+1+11420x2083+1+11420x2083+1+11420x2083+1+11420x2083+1+11420x2083+1+11420x2083+1+11420x2083+1+11420x2083+1+11420x2083+1+11420x2083+1+11420x2083+1+11420x2083+1+11420x2083+1+11420x2083+1+11420x2083+1+11420x2083+1+11420x2083+1+11420x2083+   

Versions

Notes

I use this command function because I cannot find the MagickWand raw function to calculate the trim box (need offset and size). Please let me know if there is another way to do this.

BTW, Thanks for this nice library.

justinfx commented 5 months ago

I can confirm this same behaviour from your repo, using ImageMagick7 as well. The Go source code doesn't seem to have anything to do with this, otherwise it would happen every time. There is something in the ImageMagick C source that must be trying to capture from a filedescriptor and occasionally leaks to stdout. I will try and have a play to see if it can be fixed from the Go side.

I'm not an ImageMagick expert, so I am not sure what the equivalent API is to your convert example. It must exist somewhere in the current API bindings.

justinfx commented 5 months ago

FWIW, based on the examples in the documentation, I was able to fix your code to not encounter the problem: https://www.imagemagick.org/Usage/basics/#identify_alt

        ret, err := imagick.ConvertImageCommand([]string{
            "convert",
            "image.png",
            "-bordercolor", "white", // guiding border so that it trims only specified background color
            "-border", "1",
            "-fuzz", "10%",
            "-format", "%@",
            //"info:",
            "-identify", "null:",
        })
teerapap commented 5 months ago

@justinfx Thanks for the alternative solution! I try with -identify null: but the problem still occurs in my test. However, I try only null: and it works somehow. :neutral_face:

I'll close this issue and report this bug to the MagickWand C project. Thanks for the help.

teerapap commented 5 months ago

@justinfx FYI,

I've just tried to reproduce the problem directly with the C code below.

Example code in C

void main() {
        MagickWandGenesis();

        for (int i=0;i<100;i++) {

            printf("Round %d\n", i);

            char *cmd[] = {
                "convert",
                "logo:",
                "-bordercolor", "white",
                "-border", "1",
                "-fuzz", "10%",
                "-format", "%@",
                "info:"
            };

            ImageInfo *info = AcquireImageInfo();
            ExceptionInfo *exc = AcquireExceptionInfo();

            char *output = NULL;
            MagickBooleanType success = ConvertImageCommand(info, 11, cmd, &output, exc);
            DestroyImageInfo(info);
            DestroyExceptionInfo(exc);

            if (success == MagickFalse) {
                printf("Error at round %d\n", i);
                return;
            }
            printf("Output: %s\n", output);
        }

        MagickWandTerminus();
}

Result

Round 0
457x472+93+1Output: 457x472+93+1
Round 1
457x472+93+1Output: 457x472+93+1
Round 2
457x472+93+1Output: 457x472+93+1
Round 3
457x472+93+1Output: 457x472+93+1
Round 4
457x472+93+1Output: 457x472+93+1
Round 5
457x472+93+1Output: 457x472+93+1
Round 6
457x472+93+1Output: 457x472+93+1
Round 7
457x472+93+1Output: 457x472+93+1
.....

I found that if I use the info: as the last argument, it will print the result (457x472+93+1) to stdout in addition to setting the result to output variable. I guess it is the expected behavior (not confirmed yet).

I guess the problem goes back to GoMagick that it probably buffers this unexpected stdout output somewhere and flush them to stdout at certain time. In C version, it prints to stdout immediately so it does not look strange.

Anyway, my problem is solved using null: so this is just to keep you updated. Thanks

justinfx commented 5 months ago

Thanks for confirming that! Great work on doing the C repo.