preface

I decided to use GraphicsMagick and MagickWand as a struct for convenience.

Basically some common image processing functions are no problem, but translucent image watermarking this function is stuck. This function is very common and important, but I can’t find any clue about how to deal with the struct MagickWand either in Chinese or In English, which makes me confused for a few days. Finally, at some point this afternoon, I tried to solve the problem.

The solution

Here’s the solution:

  1. First of all, through the search engine, the command line processing translucent image watermark method:

    /usr/bin/gm composite -geometry +500+450 -dissolve 30 watermark.png input.jpg output.jpg
    Copy the code
  2. Since the command line can, it shows that this function can be done, by looking at the command processing source code, found the key processing code:

    Hg.code.sf.net/p/graphicsm…

    static MagickPassFail CompositeImageList(ImageInfo *image_info,Image **image,
    Image *composite_image,Image *mask_image,CompositeOptions *option_info,
    ExceptionInfo *exception)
    {
    // ...
              if (option_info->compose == DissolveCompositeOp)
              {
                  register PixelPacket
                  *q;
    
                  /* Create mattes for dissolve. */
                  if(! composite_image->matte) SetImageOpacity(composite_image,OpaqueOpacity);for (y=0; y < (long) composite_image->rows; y++)
                  {
                    q=GetImagePixels(composite_image,0,y,composite_image->columns,1);
                    if (q == (PixelPacket *) NULL)
                        break;
                    for (x=0; x < (long) composite_image->columns; x++)
                    {
                        q->opacity=(Quantum)
                        ((((unsigned long) MaxRGB-q->opacity)*option_info->dissolve)/100.0);
                        q++;
                    }
                    if(! SyncImagePixels(composite_image))break; }}// ...
               status&=CompositeImage(*image,option_info->compose,
                 composite_image,geometry.x,geometry.y);
    }
    Copy the code

    The idea is to first set the watermark image as translucent according to the set transparency parameter, and note that the step of SetImageOpacity should not be less. The CompositeImage method and the DissolveCompositeOp method are then used to overlay the watermarked image over the original image.

  3. The struct applied to these methods is an Image instead of MagickWand, which is a user-friendly wrapper for Image. MagickWand also provides the MagickCompositeImage method, This is similar to CompositeImage. I don’t know how to set transparency, so I abandoned setting transparency through MagickWand.

  4. The MagickWand documentation does not find the method to obtain the Image, but the Image field is found by looking at the MagickWand definition.

    Hg.code.sf.net/p/graphicsm…

    /* Typedef declarations. */
    struct _MagickWand
    {
      char
        id[MaxTextExtent];
    
      ExceptionInfo
        exception;
    
      ImageInfo
        *image_info;
    
      QuantizeInfo
        *quantize_info;
    
      Image
        *image,             /* Current working image */
        *images;            /* Whole image list */
    
      unsigned int
        iterator;
    
      unsigned long
        signature;
    };
    Copy the code

    Unfortunately, the definition is in the.c file instead of the.h file, or the author does not want to expose the fields in the file to the user, but to solve the need, can only break the encapsulation.

  5. Struct _MagickWand (struct _MagickWand, struct _MagickWand, struct _MagickWand, struct _MagickWand (), struct _MagickWand (), struct _MagickWand (), struct _MagickWand (), struct _MagickWand (), struct _MagickWand (), struct _MagickWand (), struct _MagickWand (), struct _MagickWand () The MagickCompositeImage method of MagickWand can then be used to overlay the watermark image to the original image.

    Complete code reference below:

    MagickWand *input;
    MagickWand *watermark;
    
    / /...
    
    Image *composite_image = watermark->image;
    
    register PixelPacket *q;
    
    /*
    Create mattes for dissolve.
    */
    if(! composite_image->matte) SetImageOpacity(composite_image,OpaqueOpacity);for (y=0; y < (long) composite_image->rows; y++)
    {
      q=GetImagePixels(composite_image,0,y,composite_image->columns,1);
      if (q == (PixelPacket *) NULL)
          break;
      for (x=0; x < (long) composite_image->columns; x++)
      {
          q->opacity=(Quantum)
          ((((unsigned long) MaxRGB-q->opacity)*option_info->dissolve)/100.0);
          q++;
      }
      if(! SyncImagePixels(composite_image))break;
    }
    
    MagickCompositeImage(input, watermark, DissolveCompositeOp, 500.450);
    
    Copy the code

The latter

In fact, I used Rust ffI to call GraphicsMagick’s C function to handle this function. Currently, THERE is no perfect GraphicsMagick binding library, so I had to make it myself.