Search code examples
phpimagick

Difference between Imagick::thumbnailImage() and Imagick::adaptiveResizeImage()


First off, I know Imagick::resizeImage gives me more options.

Could anyone tell me which filters the two methods use?

They seem to create almost identical images, except that (on my test image) the thumbnailImage() one is shifted one pixel top-left.

UPDATE

I have found that these two methods are ImageMagick's MagickThumbnailImage and MagickAdaptiveResizeImage. Their documentation does not specify which filters are used.


Solution

  • The chain of calls made to with thumbnailImage are MagickThumbnailImage -> ResizeImage where a filter type of LanczosFilter appears to be set as the default (unless somehow the image has a filter associated with it).

    The chain of calls for adaptiveResize image is MagickAdaptiveResizeImage -> AdaptiveResizeImage -> InterpolativeResizeImage(image,columns,rows,MeshInterpolatePixel) -> InterpolateMagickPixelPacket

    The code inside InterpolateMagickPixelPacket for the 'mesh interpolate pixel' type is below.

    case MeshInterpolatePixel:
    {
      PointInfo
        delta,
        luma;
    
      p=GetCacheViewVirtualPixels(image_view,x_offset,y_offset,2,2,
        exception);
      if (p == (const PixelPacket *) NULL)
        {
          status=MagickFalse;
          break;
        }
      indexes=GetCacheViewVirtualIndexQueue(image_view);
      for (i=0; i < 4L; i++)
      {
        GetMagickPixelPacket(image,pixels+i);
        AlphaBlendMagickPixelPacket(image,p+i,indexes+i,pixels+i,alpha+i);
      }
      delta.x=x-x_offset;
      delta.y=y-y_offset;
      luma.x=fabs(MagickPixelLuma(pixels+0)-MagickPixelLuma(pixels+3));
      luma.y=fabs(MagickPixelLuma(pixels+1)-MagickPixelLuma(pixels+2));
      if (luma.x < luma.y)
        {
          /*
            Diagonal 0-3 NW-SE.
          */
          if (delta.x <= delta.y)
            {
              /*
                Bottom-left triangle  (pixel:2, diagonal: 0-3).
              */
              delta.y=1.0-delta.y;
              gamma=MeshInterpolate(&delta,alpha[2],alpha[3],alpha[0]);
              gamma=PerceptibleReciprocal(gamma);
              pixel->red=gamma*MeshInterpolate(&delta,pixels[2].red,
                pixels[3].red,pixels[0].red);
              pixel->green=gamma*MeshInterpolate(&delta,pixels[2].green,
                pixels[3].green,pixels[0].green);
              pixel->blue=gamma*MeshInterpolate(&delta,pixels[2].blue,
                pixels[3].blue,pixels[0].blue);
              if (image->colorspace == CMYKColorspace)
                pixel->index=gamma*MeshInterpolate(&delta,pixels[2].index,
                  pixels[3].index,pixels[0].index);
              gamma=MeshInterpolate(&delta,1.0,1.0,1.0);
              pixel->opacity=gamma*MeshInterpolate(&delta,pixels[2].opacity,
                pixels[3].opacity,pixels[0].opacity);
            }
          else
            {
              /*
                Top-right triangle (pixel:1, diagonal: 0-3).
              */
              delta.x=1.0-delta.x;
              gamma=MeshInterpolate(&delta,alpha[1],alpha[0],alpha[3]);
              gamma=PerceptibleReciprocal(gamma);
              pixel->red=gamma*MeshInterpolate(&delta,pixels[1].red,
                pixels[0].red,pixels[3].red);
              pixel->green=gamma*MeshInterpolate(&delta,pixels[1].green,
                pixels[0].green,pixels[3].green);
              pixel->blue=gamma*MeshInterpolate(&delta,pixels[1].blue,
                pixels[0].blue,pixels[3].blue);
              if (image->colorspace == CMYKColorspace)
                pixel->index=gamma*MeshInterpolate(&delta,pixels[1].index,
                  pixels[0].index,pixels[3].index);
              gamma=MeshInterpolate(&delta,1.0,1.0,1.0);
              pixel->opacity=gamma*MeshInterpolate(&delta,pixels[1].opacity,
                pixels[0].opacity,pixels[3].opacity);
            }
        }
      else
        {
          /*
            Diagonal 1-2 NE-SW.
          */
          if (delta.x <= (1.0-delta.y))
            {
              /*
                Top-left triangle (pixel: 0, diagonal: 1-2).
              */
              gamma=MeshInterpolate(&delta,alpha[0],alpha[1],alpha[2]);
              gamma=PerceptibleReciprocal(gamma);
              pixel->red=gamma*MeshInterpolate(&delta,pixels[0].red,
                pixels[1].red,pixels[2].red);
              pixel->green=gamma*MeshInterpolate(&delta,pixels[0].green,
                pixels[1].green,pixels[2].green);
              pixel->blue=gamma*MeshInterpolate(&delta,pixels[0].blue,
                pixels[1].blue,pixels[2].blue);
              if (image->colorspace == CMYKColorspace)
                pixel->index=gamma*MeshInterpolate(&delta,pixels[0].index,
                  pixels[1].index,pixels[2].index);
              gamma=MeshInterpolate(&delta,1.0,1.0,1.0);
              pixel->opacity=gamma*MeshInterpolate(&delta,pixels[0].opacity,
                pixels[1].opacity,pixels[2].opacity);
            }
          else
            {
              /*
                Bottom-right triangle (pixel: 3, diagonal: 1-2).
              */
              delta.x=1.0-delta.x;
              delta.y=1.0-delta.y;
              gamma=MeshInterpolate(&delta,alpha[3],alpha[2],alpha[1]);
              gamma=PerceptibleReciprocal(gamma);
              pixel->red=gamma*MeshInterpolate(&delta,pixels[3].red,
                pixels[2].red,pixels[1].red);
              pixel->green=gamma*MeshInterpolate(&delta,pixels[3].green,
                pixels[2].green,pixels[1].green);
              pixel->blue=gamma*MeshInterpolate(&delta,pixels[3].blue,
                pixels[2].blue,pixels[1].blue);
              if (image->colorspace == CMYKColorspace)
                pixel->index=gamma*MeshInterpolate(&delta,pixels[3].index,
                  pixels[2].index,pixels[1].index);
              gamma=MeshInterpolate(&delta,1.0,1.0,1.0);
              pixel->opacity=gamma*MeshInterpolate(&delta,pixels[3].opacity,
                pixels[2].opacity,pixels[1].opacity);
            }
        }
      break;
    }
    

    So it's not using one of the defined filters.