Exemple #1
0
static MagickRealType GetAbsoluteError(const Image *image,
  const Image *reconstruct_image,ExceptionInfo *exception)
{
  long
    y;

  MagickPixelPacket
    image_pixel,
    reconstruct_pixel;

  MagickRealType
    distortion;

  register const IndexPacket
    *indexes,
    *reconstruct_indexes;

  register const PixelPacket
    *p,
    *q;

  register long
    x;

  ViewInfo
    *image_view,
    *reconstruct_view;

  /*
    Compute the absolute difference in pixels between two images.
  */
  GetMagickPixelPacket(image,&image_pixel);
  GetMagickPixelPacket(reconstruct_image,&reconstruct_pixel);
  distortion=0.0;
  image_view=OpenCacheView(image);
  reconstruct_view=OpenCacheView(reconstruct_image);
  for (y=0; y < (long) image->rows; y++)
  {
    p=AcquireCacheViewPixels(image_view,0,y,image->columns,1,exception);
    q=AcquireCacheViewPixels(reconstruct_view,0,y,reconstruct_image->columns,1,
      exception);
    if ((p == (const PixelPacket *) NULL) || (q == (const PixelPacket *) NULL))
      break;
    indexes=AcquireCacheViewIndexes(image_view);
    reconstruct_indexes=AcquireCacheViewIndexes(reconstruct_view);
    for (x=0; x < (long) image->columns; x++)
    {
      SetMagickPixelPacket(image,p,indexes+x,&image_pixel);
      SetMagickPixelPacket(reconstruct_image,q,reconstruct_indexes+x,
        &reconstruct_pixel);
      if (IsMagickColorSimilar(&image_pixel,&reconstruct_pixel) == MagickFalse)
        distortion++;
      p++;
      q++;
    }
  }
  reconstruct_view=CloseCacheView(reconstruct_view);
  image_view=CloseCacheView(image_view);
  return(distortion);
}
Exemple #2
0
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   R e a d N U L L I m a g e                                                 %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  ReadNULLImage creates a constant image and initializes it to the
%  X server color as specified by the filename.  It allocates the memory
%  necessary for the new Image structure and returns a pointer to the new
%  image.
%
%  The format of the ReadNULLImage method is:
%
%      Image *ReadNULLImage(const ImageInfo *image_info,
%        ExceptionInfo *exception)
%
%  A description of each parameter follows:
%
%    o image_info: the image info.
%
%    o exception: return any errors or warnings in this structure.
%
*/
static Image *ReadNULLImage(const ImageInfo *image_info,
  ExceptionInfo *exception)
{
  Image
    *image;

  ssize_t
    y;

  MagickPixelPacket
    background;

  register IndexPacket
    *indexes;

  register ssize_t
    x;

  register PixelPacket
    *q;

  /*
    Initialize Image structure.
  */
  assert(image_info != (const ImageInfo *) NULL);
  assert(image_info->signature == MagickSignature);
  if (image_info->debug != MagickFalse)
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
      image_info->filename);
  assert(exception != (ExceptionInfo *) NULL);
  assert(exception->signature == MagickSignature);
  image=AcquireImage(image_info);
  if (image->columns == 0)
    image->columns=1;
  if (image->rows == 0)
    image->rows=1;
  image->matte=MagickTrue;
  GetMagickPixelPacket(image,&background);
  background.opacity=(MagickRealType) TransparentOpacity;
  if (image->colorspace == CMYKColorspace)
    ConvertRGBToCMYK(&background);
  for (y=0; y < (ssize_t) image->rows; y++)
  {
    q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
    if (q == (PixelPacket *) NULL)
      break;
    indexes=GetAuthenticIndexQueue(image);
    for (x=0; x < (ssize_t) image->columns; x++)
    {
      SetPixelPacket(image,&background,q,indexes);
      q++;
      indexes++;
    }
    if (SyncAuthenticPixels(image,exception) == MagickFalse)
      break;
  }
  return(GetFirstImageInList(image));
}
Exemple #3
0
static char *pixel_packet_to_hexname(PixelPacket *pp, char *name)
{
    MagickPixelPacket mpp;

    GetMagickPixelPacket(NULL, &mpp);
    rm_set_magick_pixel_packet(pp, &mpp);
    (void) GetColorTuple(&mpp, MagickTrue, name);
    return name;
}
MagickExport MagickBooleanType PaintOpaqueImageChannel(Image *image,
  const ChannelType channel,const MagickPixelPacket *target,
  const MagickPixelPacket *fill)
{
#define PaintOpaqueImageTag  "Opaque/Image"

  long
    y;

  MagickBooleanType
    status;

  MagickPixelPacket
    pixel;

  register IndexPacket
    *indexes;

  register long
    x;

  register PixelPacket
    *q;

  /*
    Make image color opaque.
  */
  assert(image != (Image *) NULL);
  assert(image->signature == MagickSignature);
  assert(target != (MagickPixelPacket *) NULL);
  assert(fill != (MagickPixelPacket *) NULL);
  if (image->debug != MagickFalse)
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
  if (SetImageStorageClass(image,DirectClass) == MagickFalse)
    return(MagickFalse);
  GetMagickPixelPacket(image,&pixel);
  for (y=0; y < (long) image->rows; y++)
  {
    q=GetImagePixels(image,0,y,image->columns,1);
    if (q == (PixelPacket *) NULL)
      break;
    indexes=GetIndexes(image);
    for (x=0; x < (long) image->columns; x++)
    {
      SetMagickPixelPacket(image,q,indexes+x,&pixel);
      if (IsMagickColorSimilar(&pixel,target) != MagickFalse)
        {
          if ((channel & RedChannel) != 0)
            q->red=RoundToQuantum(fill->red);
          if ((channel & GreenChannel) != 0)
            q->green=RoundToQuantum(fill->green);
          if ((channel & BlueChannel) != 0)
            q->blue=RoundToQuantum(fill->blue);
          if ((channel & OpacityChannel) != 0)
            q->opacity=RoundToQuantum(fill->opacity);
          if (((channel & IndexChannel) != 0) &&
              (image->colorspace == CMYKColorspace))
            indexes[x]=RoundToQuantum(fill->index);
        }
      q++;
    }
    if (SyncImagePixels(image) == MagickFalse)
      break;
    if ((image->progress_monitor != (MagickProgressMonitor) NULL) &&
        (QuantumTick(y,image->rows) != MagickFalse))
      {
        status=image->progress_monitor(PaintOpaqueImageTag,y,image->rows,
          image->client_data);
        if (status == MagickFalse)
          break;
      }
  }
  return(MagickTrue);
}
Exemple #5
0
MagickExport MagickPixelPacket IInterpolateColor(const Image *image,
  const double x_offset,const double y_offset,ExceptionInfo *exception)
{
  MagickPixelPacket
    pixel,
    pixels[4];

  MagickRealType
    alpha[4],
    gamma;

  PointInfo
    delta;

  register const PixelPacket
    *p;

  register IndexPacket
    *indexes;

  register long
    i;

  assert(image != (Image *) NULL);
  assert(image->signature == MagickSignature);
  GetMagickPixelPacket(image,&pixel);
  p=AcquireImagePixels(image,(long) x_offset,(long) y_offset,2,2,exception);
  if (p == (const PixelPacket *) NULL)
    return(pixel);
  indexes=GetIndexes(image);
  for (i=0; i < 4L; i++)
  {
    alpha[i]=1.0;
    if (image->matte != MagickFalse)
      alpha[i]=((MagickRealType) QuantumRange-p->opacity)/QuantumRange;
    GetMagickPixelPacket(image,pixels+i);
    SetMagickPixelPacket(p,indexes+i,pixels+i);
    pixels[i].red*=alpha[i];
    pixels[i].green*=alpha[i];
    pixels[i].blue*=alpha[i];
    if (image->colorspace == CMYKColorspace)
      pixels[i].index*=alpha[i];
    p++;
  }
  delta.x=x_offset-(long) x_offset;
  delta.y=y_offset-(long) y_offset;
  gamma=(alpha[0]+(alpha[2]-alpha[0])*delta.y+(alpha[1]-alpha[0])*delta.x+
    (alpha[0]+alpha[3]-alpha[2]-alpha[1])*delta.x*delta.y);
  gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
  pixel.red=gamma*(pixels[0].red+(pixels[2].red-pixels[0].red)*delta.y+
    (pixels[1].red-pixels[0].red)*delta.x+(pixels[0].red+pixels[3].red-
    pixels[2].red-pixels[1].red)*delta.x*delta.y);
  pixel.green=gamma*(pixels[0].green+(pixels[2].green-pixels[0].green)*
    delta.y+(pixels[1].green-pixels[0].green)*delta.x+(pixels[0].green+
    pixels[3].green-pixels[2].green-pixels[1].green)*delta.x*delta.y);
  pixel.blue=gamma*(pixels[0].blue+(pixels[2].blue-pixels[0].blue)*delta.y+
    (pixels[1].blue-pixels[0].blue)*delta.x+(pixels[0].blue+pixels[3].blue-
    pixels[2].blue-pixels[1].blue)*delta.x*delta.y);
  if (image->matte != MagickFalse)
    pixel.opacity=(pixels[0].opacity+(pixels[2].opacity-pixels[0].opacity)*
      delta.y+(pixels[1].opacity-pixels[0].opacity)*delta.x+(pixels[0].opacity+
      pixels[3].opacity-pixels[2].opacity-pixels[1].opacity)*delta.x*delta.y);
  if (image->colorspace == CMYKColorspace)
    pixel.index=gamma*(pixels[0].index+(pixels[2].index-pixels[0].index)*
      delta.y+(pixels[1].index-pixels[0].index)*delta.x+(pixels[0].index+
      pixels[3].index-pixels[2].index-pixels[1].index)*delta.x*delta.y);
  return(pixel);
}
Exemple #6
0
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   W r i t e P I C O N I m a g e                                             %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  WritePICONImage() writes an image to a file in the Personal Icon format.
%
%  The format of the WritePICONImage method is:
%
%      MagickBooleanType WritePICONImage(const ImageInfo *image_info,
%        Image *image)
%
%  A description of each parameter follows.
%
%    o image_info: the image info.
%
%    o image:  The image.
%
*/
static MagickBooleanType WritePICONImage(const ImageInfo *image_info,
  Image *image)
{
#define ColormapExtent  155
#define GraymapExtent  95
#define PiconGeometry  "48x48>"

  static unsigned char
    Colormap[]=
    {
      0x47, 0x49, 0x46, 0x38, 0x37, 0x61, 0x06, 0x00, 0x05, 0x00, 0xf4, 0x05,
      0x00, 0x00, 0x00, 0x00, 0x2f, 0x4f, 0x4f, 0x70, 0x80, 0x90, 0x7e, 0x7e,
      0x7e, 0xdc, 0xdc, 0xdc, 0xff, 0xff, 0xff, 0x00, 0x00, 0x80, 0x00, 0x00,
      0xff, 0x1e, 0x90, 0xff, 0x87, 0xce, 0xeb, 0xe6, 0xe6, 0xfa, 0x00, 0xff,
      0xff, 0x80, 0x00, 0x80, 0xb2, 0x22, 0x22, 0x2e, 0x8b, 0x57, 0x32, 0xcd,
      0x32, 0x00, 0xff, 0x00, 0x98, 0xfb, 0x98, 0xff, 0x00, 0xff, 0xff, 0x00,
      0x00, 0xff, 0x63, 0x47, 0xff, 0xa5, 0x00, 0xff, 0xd7, 0x00, 0xff, 0xff,
      0x00, 0xee, 0x82, 0xee, 0xa0, 0x52, 0x2d, 0xcd, 0x85, 0x3f, 0xd2, 0xb4,
      0x8c, 0xf5, 0xde, 0xb3, 0xff, 0xfa, 0xcd, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x00, 0x21, 0xf9, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00,
      0x00, 0x00, 0x06, 0x00, 0x05, 0x00, 0x00, 0x05, 0x18, 0x20, 0x10, 0x08,
      0x03, 0x51, 0x18, 0x07, 0x92, 0x28, 0x0b, 0xd3, 0x38, 0x0f, 0x14, 0x49,
      0x13, 0x55, 0x59, 0x17, 0x96, 0x69, 0x1b, 0xd7, 0x85, 0x00, 0x3b,
    },
    Graymap[]=
    {
      0x47, 0x49, 0x46, 0x38, 0x37, 0x61, 0x04, 0x00, 0x04, 0x00, 0xf3, 0x0f,
      0x00, 0x00, 0x00, 0x00, 0x12, 0x12, 0x12, 0x21, 0x21, 0x21, 0x33, 0x33,
      0x33, 0x45, 0x45, 0x45, 0x54, 0x54, 0x54, 0x66, 0x66, 0x66, 0x78, 0x78,
      0x78, 0x87, 0x87, 0x87, 0x99, 0x99, 0x99, 0xab, 0xab, 0xab, 0xba, 0xba,
      0xba, 0xcc, 0xcc, 0xcc, 0xde, 0xde, 0xde, 0xed, 0xed, 0xed, 0xff, 0xff,
      0xff, 0x21, 0xf9, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00,
      0x00, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x04, 0x0c, 0x10, 0x04, 0x31,
      0x48, 0x31, 0x07, 0x25, 0xb5, 0x58, 0x73, 0x4f, 0x04, 0x00, 0x3b,
    };

#define MaxCixels  92

  static const char
    Cixel[MaxCixels+1] = " .XoO+@#$%&*=-;:>,<1234567890qwertyuipasdfghjk"
                         "lzxcvbnmMNBVCZASDFGHJKLPIUYTREWQ!~^/()_`'][{}|";

  char
    buffer[MaxTextExtent],
    basename[MaxTextExtent],
    name[MaxTextExtent],
    symbol[MaxTextExtent];

  ExceptionInfo
    *exception;

  Image
    *affinity_image,
    *picon;

  ImageInfo
    *blob_info;

  MagickBooleanType
    status,
    transparent;

  MagickPixelPacket
    pixel;

  QuantizeInfo
    *quantize_info;

  RectangleInfo
    geometry;

  register const IndexPacket
    *indexes;

  register const PixelPacket
    *p;

  register ssize_t
    i,
    x;

  register PixelPacket
    *q;

  size_t
    characters_per_pixel,
    colors;

  ssize_t
    j,
    k,
    y;

  /*
    Open output image file.
  */
  assert(image_info != (const ImageInfo *) NULL);
  assert(image_info->signature == MagickSignature);
  assert(image != (Image *) NULL);
  assert(image->signature == MagickSignature);
  if (image->debug != MagickFalse)
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
  status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
  if (status == MagickFalse)
    return(status);
  (void) TransformImageColorspace(image,sRGBColorspace);
  SetGeometry(image,&geometry);
  (void) ParseMetaGeometry(PiconGeometry,&geometry.x,&geometry.y,
    &geometry.width,&geometry.height);
  picon=ResizeImage(image,geometry.width,geometry.height,TriangleFilter,1.0,
    &image->exception);
  blob_info=CloneImageInfo(image_info);
  (void) AcquireUniqueFilename(blob_info->filename);
  if ((image_info->type != TrueColorType) &&
      (SetImageGray(image,&image->exception) != MagickFalse))
    affinity_image=BlobToImage(blob_info,Graymap,GraymapExtent,
      &image->exception);
  else
    affinity_image=BlobToImage(blob_info,Colormap,ColormapExtent,
      &image->exception);
  (void) RelinquishUniqueFileResource(blob_info->filename);
  blob_info=DestroyImageInfo(blob_info);
  if ((picon == (Image *) NULL) || (affinity_image == (Image *) NULL))
    return(MagickFalse);
  quantize_info=AcquireQuantizeInfo(image_info);
  status=RemapImage(quantize_info,picon,affinity_image);
  quantize_info=DestroyQuantizeInfo(quantize_info);
  affinity_image=DestroyImage(affinity_image);
  transparent=MagickFalse;
  exception=(&image->exception);
  if (picon->storage_class == PseudoClass)
    {
      (void) CompressImageColormap(picon);
      if (picon->matte != MagickFalse)
        transparent=MagickTrue;
    }
  else
    {
      /*
        Convert DirectClass to PseudoClass picon.
      */
      if (picon->matte != MagickFalse)
        {
          /*
            Map all the transparent pixels.
          */
          for (y=0; y < (ssize_t) picon->rows; y++)
          {
            q=GetAuthenticPixels(picon,0,y,picon->columns,1,exception);
            if (q == (PixelPacket *) NULL)
              break;
            for (x=0; x < (ssize_t) picon->columns; x++)
            {
              if (q->opacity == (Quantum) TransparentOpacity)
                transparent=MagickTrue;
              else
                SetPixelOpacity(q,OpaqueOpacity);
              q++;
            }
            if (SyncAuthenticPixels(picon,exception) == MagickFalse)
              break;
          }
        }
      (void) SetImageType(picon,PaletteType);
    }
  colors=picon->colors;
  if (transparent != MagickFalse)
    {
      register IndexPacket
        *indexes;

      colors++;
      picon->colormap=(PixelPacket *) ResizeQuantumMemory((void **)
        picon->colormap,(size_t) colors,sizeof(*picon->colormap));
      if (picon->colormap == (PixelPacket *) NULL)
        ThrowWriterException(ResourceLimitError,"MemoryAllocationError");
      for (y=0; y < (ssize_t) picon->rows; y++)
      {
        q=GetAuthenticPixels(picon,0,y,picon->columns,1,exception);
        if (q == (PixelPacket *) NULL)
          break;
        indexes=GetAuthenticIndexQueue(picon);
        for (x=0; x < (ssize_t) picon->columns; x++)
        {
          if (q->opacity == (Quantum) TransparentOpacity)
            SetPixelIndex(indexes+x,picon->colors);
          q++;
        }
        if (SyncAuthenticPixels(picon,exception) == MagickFalse)
          break;
      }
    }
  /*
    Compute the character per pixel.
  */
  characters_per_pixel=1;
  for (k=MaxCixels; (ssize_t) colors > k; k*=MaxCixels)
    characters_per_pixel++;
  /*
    XPM header.
  */
  (void) WriteBlobString(image,"/* XPM */\n");
  GetPathComponent(picon->filename,BasePath,basename);
  (void) FormatLocaleString(buffer,MaxTextExtent,
    "static char *%s[] = {\n",basename);
  (void) WriteBlobString(image,buffer);
  (void) WriteBlobString(image,"/* columns rows colors chars-per-pixel */\n");
  (void) FormatLocaleString(buffer,MaxTextExtent,
    "\"%.20g %.20g %.20g %.20g\",\n",(double) picon->columns,(double)
    picon->rows,(double) colors,(double) characters_per_pixel);
  (void) WriteBlobString(image,buffer);
  GetMagickPixelPacket(image,&pixel);
  for (i=0; i < (ssize_t) colors; i++)
  {
    /*
      Define XPM color.
    */
    SetMagickPixelPacket(image,picon->colormap+i,(IndexPacket *) NULL,&pixel);
    pixel.colorspace=sRGBColorspace;
    pixel.depth=8;
    pixel.opacity=(MagickRealType) OpaqueOpacity;
    (void) QueryMagickColorname(image,&pixel,XPMCompliance,name,
      &image->exception);
    if (transparent != MagickFalse)
      {
        if (i == (ssize_t) (colors-1))
          (void) CopyMagickString(name,"grey75",MaxTextExtent);
      }
    /*
      Write XPM color.
    */
    k=i % MaxCixels;
    symbol[0]=Cixel[k];
    for (j=1; j < (ssize_t) characters_per_pixel; j++)
    {
      k=((i-k)/MaxCixels) % MaxCixels;
      symbol[j]=Cixel[k];
    }
    symbol[j]='\0';
    (void) FormatLocaleString(buffer,MaxTextExtent,"\"%s c %s\",\n",
       symbol,name);
    (void) WriteBlobString(image,buffer);
  }
  /*
    Define XPM pixels.
  */
  (void) WriteBlobString(image,"/* pixels */\n");
  for (y=0; y < (ssize_t) picon->rows; y++)
  {
    p=GetVirtualPixels(picon,0,y,picon->columns,1,&picon->exception);
    if (p == (const PixelPacket *) NULL)
      break;
    indexes=GetVirtualIndexQueue(picon);
    (void) WriteBlobString(image,"\"");
    for (x=0; x < (ssize_t) picon->columns; x++)
    {
      k=((ssize_t) GetPixelIndex(indexes+x) % MaxCixels);
      symbol[0]=Cixel[k];
      for (j=1; j < (ssize_t) characters_per_pixel; j++)
      {
        k=(((int) GetPixelIndex(indexes+x)-k)/MaxCixels) % MaxCixels;
        symbol[j]=Cixel[k];
      }
      symbol[j]='\0';
      (void) CopyMagickString(buffer,symbol,MaxTextExtent);
      (void) WriteBlobString(image,buffer);
    }
    (void) FormatLocaleString(buffer,MaxTextExtent,"\"%s\n",
      y == (ssize_t) (picon->rows-1) ? "" : ",");
    (void) WriteBlobString(image,buffer);
    status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
      picon->rows);
    if (status == MagickFalse)
      break;
  }
  picon=DestroyImage(picon);
  (void) WriteBlobString(image,"};\n");
  (void) CloseBlob(image);
  return(MagickTrue);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   W r i t e D E B U G I m a g e                                             %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  WriteDEBUGImage writes the image pixel values with 20 places of precision.
%
%  The format of the WriteDEBUGImage method is:
%
%      MagickBooleanType WriteDEBUGImage(const ImageInfo *image_info,
%        Image *image)
%
%  A description of each parameter follows.
%
%    o image_info: the image info.
%
%    o image:  The image.
%
*/
static MagickBooleanType WriteDEBUGImage(const ImageInfo *image_info,
  Image *image)
{
  char
    buffer[MaxTextExtent],
    colorspace[MaxTextExtent],
    tuple[MaxTextExtent];

  ssize_t
    y;

  MagickBooleanType
    status;

  MagickOffsetType
    scene;

  MagickPixelPacket
    pixel;

  register const IndexPacket
    *indexes;

  register const PixelPacket
    *p;

  register ssize_t
    x;

  /*
    Open output image file.
  */
  assert(image_info != (const ImageInfo *) NULL);
  assert(image_info->signature == MagickSignature);
  assert(image != (Image *) NULL);
  assert(image->signature == MagickSignature);
  if (image->debug != MagickFalse)
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
  status=OpenBlob(image_info,image,WriteBlobMode,&image->exception);
  if (status == MagickFalse)
    return(status);
  scene=0;
  do
  {
    (void) CopyMagickString(colorspace,CommandOptionToMnemonic(
      MagickColorspaceOptions,(ssize_t) image->colorspace),MaxTextExtent);
    LocaleLower(colorspace);
    image->depth=GetImageQuantumDepth(image,MagickTrue);
    if (image->matte != MagickFalse)
      (void) ConcatenateMagickString(colorspace,"a",MaxTextExtent);
    (void) FormatLocaleString(buffer,MaxTextExtent,
      "# ImageMagick pixel debugging: %.20g,%.20g,%.20g,%s\n",(double)
      image->columns,(double) image->rows,(double) ((MagickOffsetType)
      GetQuantumRange(image->depth)),colorspace);
    (void) WriteBlobString(image,buffer);
    GetMagickPixelPacket(image,&pixel);
    for (y=0; y < (ssize_t) image->rows; y++)
    {
      p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
      if (p == (const PixelPacket *) NULL)
        break;
      indexes=GetVirtualIndexQueue(image);
      for (x=0; x < (ssize_t) image->columns; x++)
      {
        (void) FormatLocaleString(buffer,MaxTextExtent,"%.20g,%.20g: ",(double)
          x,(double) y);
        (void) WriteBlobString(image,buffer);
        SetMagickPixelPacket(image,p,indexes+x,&pixel);
        (void) FormatLocaleString(tuple,MaxTextExtent,"%.20g,%.20g,%.20g ",
          (double) pixel.red,(double) pixel.green,(double) pixel.blue);
        if (pixel.colorspace == CMYKColorspace)
          {
            char
              black[MaxTextExtent];

            (void) FormatLocaleString(black,MaxTextExtent,",%.20g ",
              (double) pixel.index);
            (void) ConcatenateMagickString(tuple,black,MaxTextExtent);
          }
        if (pixel.matte != MagickFalse)
          {
            char
              alpha[MaxTextExtent];

            (void) FormatLocaleString(alpha,MaxTextExtent,",%.20g ",
              (double) (QuantumRange-pixel.opacity));
            (void) ConcatenateMagickString(tuple,alpha,MaxTextExtent);
          }
        (void) WriteBlobString(image,tuple);
        (void) WriteBlobString(image,"\n");
        p++;
      }
      status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
        image->rows);
      if (status == MagickFalse)
        break;
    }
    if (GetNextImageInList(image) == (Image *) NULL)
      break;
    image=SyncNextImageInList(image);
    status=SetImageProgress(image,SaveImagesTag,scene++,
      GetImageListLength(image));
    if (status == MagickFalse)
      break;
  } while (image_info->adjoin != MagickFalse);
  (void) CloseBlob(image);
  return(MagickTrue);
}
Exemple #8
0
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   F r a m e I m a g e                                                       %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  FrameImage() adds a simulated three-dimensional border around the image.
%  The color of the border is defined by the matte_color member of image.
%  Members width and height of frame_info specify the border width of the
%  vertical and horizontal sides of the frame.  Members inner and outer
%  indicate the width of the inner and outer shadows of the frame.
%
%  The format of the FrameImage method is:
%
%      Image *FrameImage(const Image *image,const FrameInfo *frame_info,
%        ExceptionInfo *exception)
%
%  A description of each parameter follows:
%
%    o image: the image.
%
%    o frame_info: Define the width and height of the frame and its bevels.
%
%    o exception: return any errors or warnings in this structure.
%
*/
MagickExport Image *FrameImage(const Image *image,const FrameInfo *frame_info,
  ExceptionInfo *exception)
{
#define FrameImageTag  "Frame/Image"

  CacheView
    *image_view,
    *frame_view;

  Image
    *frame_image;

  MagickBooleanType
    status;

  MagickOffsetType
    progress;

  MagickPixelPacket
    accentuate,
    border,
    highlight,
    interior,
    matte,
    shadow,
    trough;

  register ssize_t
    x;

  size_t
    bevel_width,
    height,
    width;

  ssize_t
    y;

  /*
    Check frame geometry.
  */
  assert(image != (Image *) NULL);
  assert(image->signature == MagickSignature);
  if (image->debug != MagickFalse)
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
  assert(frame_info != (FrameInfo *) NULL);
  if ((frame_info->outer_bevel < 0) || (frame_info->inner_bevel < 0))
    ThrowImageException(OptionError,"FrameIsLessThanImageSize");
  bevel_width=(size_t) (frame_info->outer_bevel+frame_info->inner_bevel);
  width=frame_info->width-frame_info->x-bevel_width;
  height=frame_info->height-frame_info->y-bevel_width;
  if ((width < image->columns) || (height < image->rows))
    ThrowImageException(OptionError,"FrameIsLessThanImageSize");
  /*
    Initialize framed image attributes.
  */
  frame_image=CloneImage(image,frame_info->width,frame_info->height,MagickTrue,
    exception);
  if (frame_image == (Image *) NULL)
    return((Image *) NULL);
  if (SetImageStorageClass(frame_image,DirectClass) == MagickFalse)
    {
      InheritException(exception,&frame_image->exception);
      frame_image=DestroyImage(frame_image);
      return((Image *) NULL);
    }
  if (frame_image->matte_color.opacity != OpaqueOpacity)
    frame_image->matte=MagickTrue;
  frame_image->page=image->page;
  if ((image->page.width != 0) && (image->page.height != 0))
    {
      frame_image->page.width+=frame_image->columns-image->columns;
      frame_image->page.height+=frame_image->rows-image->rows;
    }
  /*
    Initialize 3D effects color.
  */
  GetMagickPixelPacket(frame_image,&interior);
  SetMagickPixelPacket(frame_image,&image->border_color,(IndexPacket *) NULL,
    &interior);
  GetMagickPixelPacket(frame_image,&matte);
  matte.colorspace=RGBColorspace;
  SetMagickPixelPacket(frame_image,&image->matte_color,(IndexPacket *) NULL,
    &matte);
  GetMagickPixelPacket(frame_image,&border);
  border.colorspace=RGBColorspace;
  SetMagickPixelPacket(frame_image,&image->border_color,(IndexPacket *) NULL,
    &border);
  GetMagickPixelPacket(frame_image,&accentuate);
  accentuate.red=(MagickRealType) (QuantumScale*((QuantumRange-
    AccentuateModulate)*matte.red+(QuantumRange*AccentuateModulate)));
  accentuate.green=(MagickRealType) (QuantumScale*((QuantumRange-
    AccentuateModulate)*matte.green+(QuantumRange*AccentuateModulate)));
  accentuate.blue=(MagickRealType) (QuantumScale*((QuantumRange-
    AccentuateModulate)*matte.blue+(QuantumRange*AccentuateModulate)));
  accentuate.opacity=matte.opacity;
  GetMagickPixelPacket(frame_image,&highlight);
  highlight.red=(MagickRealType) (QuantumScale*((QuantumRange-
    HighlightModulate)*matte.red+(QuantumRange*HighlightModulate)));
  highlight.green=(MagickRealType) (QuantumScale*((QuantumRange-
    HighlightModulate)*matte.green+(QuantumRange*HighlightModulate)));
  highlight.blue=(MagickRealType) (QuantumScale*((QuantumRange-
    HighlightModulate)*matte.blue+(QuantumRange*HighlightModulate)));
  highlight.opacity=matte.opacity;
  GetMagickPixelPacket(frame_image,&shadow);
  shadow.red=QuantumScale*matte.red*ShadowModulate;
  shadow.green=QuantumScale*matte.green*ShadowModulate;
  shadow.blue=QuantumScale*matte.blue*ShadowModulate;
  shadow.opacity=matte.opacity;
  GetMagickPixelPacket(frame_image,&trough);
  trough.red=QuantumScale*matte.red*TroughModulate;
  trough.green=QuantumScale*matte.green*TroughModulate;
  trough.blue=QuantumScale*matte.blue*TroughModulate;
  trough.opacity=matte.opacity;
  if (image->colorspace == CMYKColorspace)
    {
      ConvertRGBToCMYK(&interior);
      ConvertRGBToCMYK(&matte);
      ConvertRGBToCMYK(&border);
      ConvertRGBToCMYK(&accentuate);
      ConvertRGBToCMYK(&highlight);
      ConvertRGBToCMYK(&shadow);
      ConvertRGBToCMYK(&trough);
    }
  status=MagickTrue;
  progress=0;
  image_view=AcquireCacheView(image);
  frame_view=AcquireCacheView(frame_image);
  height=(size_t) (frame_info->outer_bevel+(frame_info->y-bevel_width)+
    frame_info->inner_bevel);
  if (height != 0)
    {
      register IndexPacket
        *restrict frame_indexes;

      register ssize_t
        x;

      register PixelPacket
        *restrict q;

      /*
        Draw top of ornamental border.
      */
      q=QueueCacheViewAuthenticPixels(frame_view,0,0,frame_image->columns,
        height,exception);
      frame_indexes=GetCacheViewAuthenticIndexQueue(frame_view);
      if (q != (PixelPacket *) NULL)
        {
          /*
            Draw top of ornamental border.
          */
          for (y=0; y < (ssize_t) frame_info->outer_bevel; y++)
          {
            for (x=0; x < (ssize_t) (frame_image->columns-y); x++)
            {
              if (x < y)
                SetPixelPacket(frame_image,&highlight,q,frame_indexes);
              else
                SetPixelPacket(frame_image,&accentuate,q,frame_indexes);
              q++;
              frame_indexes++;
            }
            for ( ; x < (ssize_t) frame_image->columns; x++)
            {
              SetPixelPacket(frame_image,&shadow,q,frame_indexes);
              q++;
              frame_indexes++;
            }
          }
          for (y=0; y < (ssize_t) (frame_info->y-bevel_width); y++)
          {
            for (x=0; x < (ssize_t) frame_info->outer_bevel; x++)
            {
              SetPixelPacket(frame_image,&highlight,q,frame_indexes);
              q++;
              frame_indexes++;
            }
            width=frame_image->columns-2*frame_info->outer_bevel;
            for (x=0; x < (ssize_t) width; x++)
            {
              SetPixelPacket(frame_image,&matte,q,frame_indexes);
              q++;
              frame_indexes++;
            }
            for (x=0; x < (ssize_t) frame_info->outer_bevel; x++)
            {
              SetPixelPacket(frame_image,&shadow,q,frame_indexes);
              q++;
              frame_indexes++;
            }
          }
          for (y=0; y < (ssize_t) frame_info->inner_bevel; y++)
          {
            for (x=0; x < (ssize_t) frame_info->outer_bevel; x++)
            {
              SetPixelPacket(frame_image,&highlight,q,frame_indexes);
              q++;
              frame_indexes++;
            }
            for (x=0; x < (ssize_t) (frame_info->x-bevel_width); x++)
            {
              SetPixelPacket(frame_image,&matte,q,frame_indexes);
              q++;
              frame_indexes++;
            }
            width=image->columns+((size_t) frame_info->inner_bevel << 1)-
              y;
            for (x=0; x < (ssize_t) width; x++)
            {
              if (x < y)
                SetPixelPacket(frame_image,&shadow,q,frame_indexes);
              else
                SetPixelPacket(frame_image,&trough,q,frame_indexes);
              q++;
              frame_indexes++;
            }
            for ( ; x < (ssize_t) (image->columns+2*frame_info->inner_bevel); x++)
            {
              SetPixelPacket(frame_image,&highlight,q,frame_indexes);
              q++;
              frame_indexes++;
            }
            width=frame_info->width-frame_info->x-image->columns-bevel_width;
            for (x=0; x < (ssize_t) width; x++)
            {
              SetPixelPacket(frame_image,&matte,q,frame_indexes);
              q++;
              frame_indexes++;
            }
            for (x=0; x < (ssize_t) frame_info->outer_bevel; x++)
            {
              SetPixelPacket(frame_image,&shadow,q,frame_indexes);
              q++;
              frame_indexes++;
            }
          }
          (void) SyncCacheViewAuthenticPixels(frame_view,exception);
        }
    }
  /*
    Draw sides of ornamental border.
  */
#if defined(MAGICKCORE_OPENMP_SUPPORT) 
  #pragma omp parallel for schedule(dynamic,4) shared(progress,status) omp_throttle(1)
#endif
  for (y=0; y < (ssize_t) image->rows; y++)
  {
    register IndexPacket
      *restrict frame_indexes;

    register ssize_t
      x;

    register PixelPacket
      *restrict q;

    /*
      Initialize scanline with matte color.
    */
    if (status == MagickFalse)
      continue;
    q=QueueCacheViewAuthenticPixels(frame_view,0,frame_info->y+y,
      frame_image->columns,1,exception);
    if (q == (PixelPacket *) NULL)
      {
        status=MagickFalse;
        continue;
      }
    frame_indexes=GetCacheViewAuthenticIndexQueue(frame_view);
    for (x=0; x < (ssize_t) frame_info->outer_bevel; x++)
    {
      SetPixelPacket(frame_image,&highlight,q,frame_indexes);
      q++;
      frame_indexes++;
    }
    for (x=0; x < (ssize_t) (frame_info->x-bevel_width); x++)
    {
      SetPixelPacket(frame_image,&matte,q,frame_indexes);
      q++;
      frame_indexes++;
    }
    for (x=0; x < (ssize_t) frame_info->inner_bevel; x++)
    {
      SetPixelPacket(frame_image,&shadow,q,frame_indexes);
      q++;
      frame_indexes++;
    }
    /*
      Set frame interior to interior color.
    */
    if ((image->compose != CopyCompositeOp) &&
        ((image->compose != OverCompositeOp) || (image->matte != MagickFalse)))
      for (x=0; x < (ssize_t) image->columns; x++)
      {
        SetPixelPacket(frame_image,&interior,q,frame_indexes);
        q++;
        frame_indexes++;
      }
    else
      {
        register const IndexPacket
          *indexes;

        register const PixelPacket
          *p;

        p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
        if (p == (const PixelPacket *) NULL)
          {
            status=MagickFalse;
            continue;
          }
        indexes=GetCacheViewVirtualIndexQueue(image_view);
        (void) CopyMagickMemory(q,p,image->columns*sizeof(*p));
        if ((image->colorspace == CMYKColorspace) &&
            (frame_image->colorspace == CMYKColorspace))
          {
            (void) CopyMagickMemory(frame_indexes,indexes,image->columns*
              sizeof(*indexes));
            frame_indexes+=image->columns;
          }
        q+=image->columns;
      }
    for (x=0; x < (ssize_t) frame_info->inner_bevel; x++)
    {
      SetPixelPacket(frame_image,&highlight,q,frame_indexes);
      q++;
      frame_indexes++;
    }
    width=frame_info->width-frame_info->x-image->columns-bevel_width;
    for (x=0; x < (ssize_t) width; x++)
    {
      SetPixelPacket(frame_image,&matte,q,frame_indexes);
      q++;
      frame_indexes++;
    }
    for (x=0; x < (ssize_t) frame_info->outer_bevel; x++)
    {
      SetPixelPacket(frame_image,&shadow,q,frame_indexes);
      q++;
      frame_indexes++;
    }
    if (SyncCacheViewAuthenticPixels(frame_view,exception) == MagickFalse)
      status=MagickFalse;
    if (image->progress_monitor != (MagickProgressMonitor) NULL)
      {
        MagickBooleanType
          proceed;

#if defined(MAGICKCORE_OPENMP_SUPPORT) 
  #pragma omp critical (MagickCore_FrameImage)
#endif
        proceed=SetImageProgress(image,FrameImageTag,progress++,image->rows);
        if (proceed == MagickFalse)
          status=MagickFalse;
      }
  }
  height=(size_t) (frame_info->inner_bevel+frame_info->height-
    frame_info->y-image->rows-bevel_width+frame_info->outer_bevel);
  if (height != 0)
    {
      register IndexPacket
        *restrict frame_indexes;

      register ssize_t
        x;

      register PixelPacket
        *restrict q;

      /*
        Draw bottom of ornamental border.
      */
      q=QueueCacheViewAuthenticPixels(frame_view,0,(ssize_t) (frame_image->rows-
        height),frame_image->columns,height,exception);
      if (q != (PixelPacket *) NULL)
        {
          /*
            Draw bottom of ornamental border.
          */
          frame_indexes=GetCacheViewAuthenticIndexQueue(frame_view);
          for (y=frame_info->inner_bevel-1; y >= 0; y--)
          {
            for (x=0; x < (ssize_t) frame_info->outer_bevel; x++)
            {
              SetPixelPacket(frame_image,&highlight,q,frame_indexes);
              q++;
              frame_indexes++;
            }
            for (x=0; x < (ssize_t) (frame_info->x-bevel_width); x++)
            {
              SetPixelPacket(frame_image,&matte,q,frame_indexes);
              q++;
              frame_indexes++;
            }
            for (x=0; x < y; x++)
            {
              SetPixelPacket(frame_image,&shadow,q,frame_indexes);
              q++;
              frame_indexes++;
            }
            for ( ; x < (ssize_t) (image->columns+2*frame_info->inner_bevel); x++)
            {
              if (x >= (ssize_t) (image->columns+2*frame_info->inner_bevel-y))
                SetPixelPacket(frame_image,&highlight,q,frame_indexes);
              else
                SetPixelPacket(frame_image,&accentuate,q,frame_indexes);
              q++;
              frame_indexes++;
            }
            width=frame_info->width-frame_info->x-image->columns-bevel_width;
            for (x=0; x < (ssize_t) width; x++)
            {
              SetPixelPacket(frame_image,&matte,q,frame_indexes);
              q++;
              frame_indexes++;
            }
            for (x=0; x < (ssize_t) frame_info->outer_bevel; x++)
            {
              SetPixelPacket(frame_image,&shadow,q,frame_indexes);
              q++;
              frame_indexes++;
            }
          }
          height=frame_info->height-frame_info->y-image->rows-bevel_width;
          for (y=0; y < (ssize_t) height; y++)
          {
            for (x=0; x < (ssize_t) frame_info->outer_bevel; x++)
            {
              SetPixelPacket(frame_image,&highlight,q,frame_indexes);
              q++;
              frame_indexes++;
            }
            width=frame_image->columns-2*frame_info->outer_bevel;
            for (x=0; x < (ssize_t) width; x++)
            {
              SetPixelPacket(frame_image,&matte,q,frame_indexes);
              q++;
              frame_indexes++;
            }
            for (x=0; x < (ssize_t) frame_info->outer_bevel; x++)
            {
              SetPixelPacket(frame_image,&shadow,q,frame_indexes);
              q++;
              frame_indexes++;
            }
          }
          for (y=frame_info->outer_bevel-1; y >= 0; y--)
          {
            for (x=0; x < y; x++)
            {
              SetPixelPacket(frame_image,&highlight,q,frame_indexes);
              q++;
              frame_indexes++;
            }
            for ( ; x < (ssize_t) frame_image->columns; x++)
            {
              if (x >= (ssize_t) (frame_image->columns-y))
                SetPixelPacket(frame_image,&shadow,q,frame_indexes);
              else
                SetPixelPacket(frame_image,&trough,q,frame_indexes);
              q++;
              frame_indexes++;
            }
          }
          (void) SyncCacheViewAuthenticPixels(frame_view,exception);
        }
    }
  frame_view=DestroyCacheView(frame_view);
  image_view=DestroyCacheView(image_view);
  if ((image->compose != CopyCompositeOp) &&
      ((image->compose != OverCompositeOp) || (image->matte != MagickFalse)))
    {
      x=(ssize_t) (frame_info->outer_bevel+(frame_info->x-bevel_width)+
        frame_info->inner_bevel);
      y=(ssize_t) (frame_info->outer_bevel+(frame_info->y-bevel_width)+
        frame_info->inner_bevel);
      (void) CompositeImage(frame_image,image->compose,image,x,y);
    }
  return(frame_image);
}
Exemple #9
0
static void XShearImage(Image *image,const MagickRealType degrees,
  const unsigned long width,const unsigned long height,const long x_offset,
  long y_offset)
{
#define XShearImageTag  "XShear/Image"

  enum {LEFT, RIGHT}
    direction;

  IndexPacket
    *indexes,
    *shear_indexes;

  long
    step,
    y;

  MagickBooleanType
    status;

  MagickPixelPacket
    background,
    pixel,
    source,
    destination;

  MagickRealType
    area,
    displacement;

  register long
    i;

  register PixelPacket
    *p,
    *q;

  assert(image != (Image *) NULL);
  assert(image->signature == MagickSignature);
  if (image->debug != MagickFalse)
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
  y_offset--;
  for (y=0; y < (long) height; y++)
  {
    y_offset++;
    displacement=degrees*(MagickRealType) (y-height/2.0);
    if (displacement == 0.0)
      continue;
    if (displacement > 0.0)
      direction=RIGHT;
    else
      {
        displacement*=(-1.0);
        direction=LEFT;
      }
    step=(long) floor((double) displacement);
    area=(MagickRealType) (displacement-step);
    step++;
    GetMagickPixelPacket(image,&background);
    SetMagickPixelPacket(image,&image->background_color,(IndexPacket *) NULL,
      &background);
    if (image->colorspace == CMYKColorspace)
      ConvertRGBToCMYK(&background);
    pixel=background;
    GetMagickPixelPacket(image,&source);
    GetMagickPixelPacket(image,&destination);
    switch (direction)
    {
      case LEFT:
      {
        /*
          Transfer pixels left-to-right.
        */
        if (step > x_offset)
          break;
        p=GetImagePixels(image,0,y_offset,image->columns,1);
        if (p == (PixelPacket *) NULL)
          break;
        p+=x_offset;
        indexes=GetIndexes(image);
        indexes+=x_offset;
        q=p-step;
        shear_indexes=indexes-step;
        for (i=0; i < (long) width; i++)
        {
          if ((x_offset+i) < step)
            {
              SetMagickPixelPacket(image,++p,++indexes,&pixel);
              q++;
              shear_indexes++;
              continue;
            }
          SetMagickPixelPacket(image,p,indexes,&source);
          MagickCompositeBlend(&pixel,(MagickRealType) pixel.opacity,&source,
            (MagickRealType) p->opacity,area,&destination);
          SetPixelPacket(image,&destination,q++,shear_indexes++);
          SetMagickPixelPacket(image,p++,indexes++,&pixel);
        }
        MagickCompositeBlend(&pixel,(MagickRealType) pixel.opacity,&background,
          (MagickRealType) background.opacity,area,&destination);
        SetPixelPacket(image,&destination,q++,shear_indexes++);
        for (i=0; i < (step-1); i++)
          SetPixelPacket(image,&background,q++,shear_indexes++);
        break;
      }
      case RIGHT:
      {
        /*
          Transfer pixels right-to-left.
        */
        p=GetImagePixels(image,0,y_offset,image->columns,1);
        if (p == (PixelPacket *) NULL)
          break;
        p+=x_offset+width;
        indexes=GetIndexes(image);
        indexes+=x_offset+width;
        q=p+step;
        shear_indexes=indexes+step;
        for (i=0; i < (long) width; i++)
        {
          p--;
          indexes--;
          q--;
          shear_indexes--;
          if ((unsigned long) (x_offset+width+step-i) >= image->columns)
            continue;
          SetMagickPixelPacket(image,p,indexes,&source);
          MagickCompositeBlend(&pixel,(MagickRealType) pixel.opacity,&source,
            (MagickRealType) p->opacity,area,&destination);
          SetPixelPacket(image,&destination,q,shear_indexes);
          SetMagickPixelPacket(image,p,indexes,&pixel);
        }
        MagickCompositeBlend(&pixel,(MagickRealType) pixel.opacity,&background,
          (MagickRealType) background.opacity,area,&destination);
        SetPixelPacket(image,&destination,--q,--shear_indexes);
        for (i=0; i < (step-1); i++)
          SetPixelPacket(image,&background,--q,--shear_indexes);
        break;
      }
    }
    if (SyncImagePixels(image) == MagickFalse)
      break;
    if ((image->progress_monitor != (MagickProgressMonitor) NULL) &&
        (QuantumTick(y,height) != MagickFalse))
      {
        status=image->progress_monitor(XShearImageTag,y,height,
          image->client_data);
        if (status == MagickFalse)
          break;
      }
  }
}
Exemple #10
0
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   W r i t e T X T I m a g e                                                 %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  WriteTXTImage writes the pixel values as text numbers.
%
%  The format of the WriteTXTImage method is:
%
%      MagickBooleanType WriteTXTImage(const ImageInfo *image_info,Image *image)
%
%  A description of each parameter follows.
%
%    o image_info: the image info.
%
%    o image:  The image.
%
*/
static MagickBooleanType WriteTXTImage(const ImageInfo *image_info,Image *image)
{
  char
    buffer[MaxTextExtent],
    colorspace[MaxTextExtent],
    tuple[MaxTextExtent];

  long
    y;

  MagickBooleanType
    status;

  MagickPixelPacket
    pixel;

  register const IndexPacket
    *indexes;

  register const PixelPacket
    *p;

  register long
    x;

  /*
    Open output image file.
  */
  assert(image_info != (const ImageInfo *) NULL);
  assert(image_info->signature == MagickSignature);
  assert(image != (Image *) NULL);
  assert(image->signature == MagickSignature);
  if (image->debug != MagickFalse)
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
  status=OpenBlob(image_info,image,WriteBlobMode,&image->exception);
  if (status == MagickFalse)
    return(status);
  (void) CopyMagickString(colorspace,MagickOptionToMnemonic(
    MagickColorspaceOptions,(long) image->colorspace),MaxTextExtent);
  LocaleLower(colorspace);
  image->depth=GetImageQuantumDepth(image,MagickTrue);
  if (image->matte != MagickFalse)
    (void) ConcatenateMagickString(colorspace,"a",MaxTextExtent);
  (void) FormatMagickString(buffer,MaxTextExtent,
    "# ImageMagick pixel enumeration: %lu,%lu,%lu,%s\n",image->columns,
    image->rows,(unsigned long) GetQuantumRange(image->depth),colorspace);
  (void) WriteBlobString(image,buffer);
  GetMagickPixelPacket(image,&pixel);
  for (y=0; y < (long) image->rows; y++)
  {
    p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
    if (p == (const PixelPacket *) NULL)
      break;
    indexes=GetVirtualIndexQueue(image);
    for (x=0; x < (long) image->columns; x++)
    {
      (void) FormatMagickString(buffer,MaxTextExtent,"%ld,%ld: ",x,y);
      (void) WriteBlobString(image,buffer);
      SetMagickPixelPacket(image,p,indexes+x,&pixel);
      (void) CopyMagickString(tuple,"(",MaxTextExtent);
      ConcatenateColorComponent(&pixel,RedChannel,X11Compliance,tuple);
      (void) ConcatenateMagickString(tuple,",",MaxTextExtent);
      ConcatenateColorComponent(&pixel,GreenChannel,X11Compliance,tuple);
      (void) ConcatenateMagickString(tuple,",",MaxTextExtent);
      ConcatenateColorComponent(&pixel,BlueChannel,X11Compliance,tuple);
      if (pixel.colorspace == CMYKColorspace)
        {
          (void) ConcatenateMagickString(tuple,",",MaxTextExtent);
          ConcatenateColorComponent(&pixel,IndexChannel,X11Compliance,tuple);
        }
      if (pixel.matte != MagickFalse)
        {
          (void) ConcatenateMagickString(tuple,",",MaxTextExtent);
          ConcatenateColorComponent(&pixel,AlphaChannel,X11Compliance,tuple);
        }
      (void) ConcatenateMagickString(tuple,")",MaxTextExtent);
      (void) WriteBlobString(image,tuple);
      (void) WriteBlobString(image,"  ");
      GetColorTuple(&pixel,MagickTrue,tuple);
      (void) FormatMagickString(buffer,MaxTextExtent,"%s",tuple);
      (void) WriteBlobString(image,buffer);
      (void) WriteBlobString(image,"  ");
      (void) QueryMagickColorname(image,&pixel,SVGCompliance,tuple,
        &image->exception);
      (void) WriteBlobString(image,tuple);
      (void) WriteBlobString(image,"\n");
      p++;
    }
    status=SetImageProgress(image,SaveImageTag,y,image->rows);
    if (status == MagickFalse)
      break;
  }
  (void) CloseBlob(image);
  return(MagickTrue);
}
Exemple #11
0
MagickExport MagickBooleanType OpaquePaintImageChannel(Image *image,
  const ChannelType channel,const MagickPixelPacket *target,
  const MagickPixelPacket *fill,const MagickBooleanType invert)
{
#define OpaquePaintImageTag  "Opaque/Image"

  ExceptionInfo
    *exception;

  long
    progress,
    y;

  MagickBooleanType
    status;

  MagickPixelPacket
    zero;

  CacheView
    *image_view;

  assert(image != (Image *) NULL);
  assert(image->signature == MagickSignature);
  assert(target != (MagickPixelPacket *) NULL);
  assert(fill != (MagickPixelPacket *) NULL);
  if (image->debug != MagickFalse)
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
  if (SetImageStorageClass(image,DirectClass) == MagickFalse)
    return(MagickFalse);
  /*
    Make image color opaque.
  */
  status=MagickTrue;
  progress=0;
  exception=(&image->exception);
  GetMagickPixelPacket(image,&zero);
  image_view=AcquireCacheView(image);
#if defined(MAGICKCORE_OPENMP_SUPPORT)
  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
#endif
  for (y=0; y < (long) image->rows; y++)
  {
    MagickPixelPacket
      pixel;

    register IndexPacket
      *__restrict indexes;

    register long
      x;

    register PixelPacket
      *__restrict q;

    if (status == MagickFalse)
      continue;
    q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
    if (q == (PixelPacket *) NULL)
      {
        status=MagickFalse;
        continue;
      }
    indexes=GetCacheViewAuthenticIndexQueue(image_view);
    pixel=zero;
    for (x=0; x < (long) image->columns; x++)
    {
      SetMagickPixelPacket(image,q,indexes+x,&pixel);
      if (IsMagickColorSimilar(&pixel,target) != invert)
        {
          if ((channel & RedChannel) != 0)
            q->red=RoundToQuantum(fill->red);
          if ((channel & GreenChannel) != 0)
            q->green=RoundToQuantum(fill->green);
          if ((channel & BlueChannel) != 0)
            q->blue=RoundToQuantum(fill->blue);
          if ((channel & OpacityChannel) != 0)
            q->opacity=RoundToQuantum(fill->opacity);
          if (((channel & IndexChannel) != 0) &&
              (image->colorspace == CMYKColorspace))
            indexes[x]=RoundToQuantum(fill->index);
        }
      q++;
    }
    if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
      status=MagickFalse;
    if (image->progress_monitor != (MagickProgressMonitor) NULL)
      {
        MagickBooleanType
          proceed;

#if defined(MAGICKCORE_OPENMP_SUPPORT)
  #pragma omp critical (MagickCore_OpaquePaintImageChannel)
#endif
        proceed=SetImageProgress(image,OpaquePaintImageTag,progress++,
          image->rows);
        if (proceed == MagickFalse)
          status=MagickFalse;
      }
  }
  image_view=DestroyCacheView(image_view);
  return(status);
}
Exemple #12
0
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   W r i t e U I L I m a g e                                                 %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  Procedure WriteUILImage() writes an image to a file in the X-Motif UIL table
%  format.
%
%  The format of the WriteUILImage method is:
%
%      MagickBooleanType WriteUILImage(const ImageInfo *image_info,Image *image)
%
%  A description of each parameter follows.
%
%    o image_info: the image info.
%
%    o image:  The image.
%
*/
static MagickBooleanType WriteUILImage(const ImageInfo *image_info,Image *image)
{
#define MaxCixels  92

  char
    basename[MaxTextExtent],
    buffer[MaxTextExtent],
    name[MaxTextExtent],
    *symbol;

  ExceptionInfo
    *exception;

  int
    j;

  MagickBooleanType
    status,
    transparent;

  MagickPixelPacket
    pixel;

  MagickSizeType
    number_pixels;

  register const IndexPacket
    *indexes;

  register const PixelPacket
    *p;

  register ssize_t
    i,
    x;

  size_t
    characters_per_pixel,
    colors;

  ssize_t
    k,
    y;

  static const char
    Cixel[MaxCixels+1] = " .XoO+@#$%&*=-;:>,<1234567890qwertyuipasdfghjk"
                         "lzxcvbnmMNBVCZASDFGHJKLPIUYTREWQ!~^/()_`'][{}|";

  /*
    Open output image file.
  */
  assert(image_info != (const ImageInfo *) NULL);
  assert(image_info->signature == MagickSignature);
  assert(image != (Image *) NULL);
  assert(image->signature == MagickSignature);
  if (image->debug != MagickFalse)
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
  status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
  if (status == MagickFalse)
    return(status);
  if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
    (void) TransformImageColorspace(image,sRGBColorspace);
  exception=(&image->exception);
  transparent=MagickFalse;
  i=0;
  p=(const PixelPacket *) NULL;
  if (image->storage_class == PseudoClass)
    colors=image->colors;
  else
    {
      unsigned char
        *matte_image;

      /*
        Convert DirectClass to PseudoClass image.
      */
      matte_image=(unsigned char *) NULL;
      if (image->matte != MagickFalse)
        {
          /*
            Map all the transparent pixels.
          */
          number_pixels=(MagickSizeType) image->columns*image->rows;
          if (number_pixels != ((MagickSizeType) (size_t) number_pixels))
            ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
          matte_image=(unsigned char *) AcquireQuantumMemory(image->columns,
            image->rows*sizeof(*matte_image));
          if (matte_image == (unsigned char *) NULL)
            ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
          for (y=0; y < (ssize_t) image->rows; y++)
          {
            p=GetVirtualPixels(image,0,y,image->columns,1,exception);
            if (p == (const PixelPacket *) NULL)
              break;
            for (x=0; x < (ssize_t) image->columns; x++)
            {
              matte_image[i]=(unsigned char) (GetPixelOpacity(p) ==
                (Quantum) TransparentOpacity ? 1 : 0);
              if (matte_image[i] != 0)
                transparent=MagickTrue;
              i++;
              p++;
            }
          }
        }
      (void) SetImageType(image,PaletteType);
      colors=image->colors;
      if (transparent != MagickFalse)
        {
          register IndexPacket
            *indexes;

          register PixelPacket
            *q;

          colors++;
          for (y=0; y < (ssize_t) image->rows; y++)
          {
            q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
            if (q == (PixelPacket *) NULL)
              break;
            indexes=GetAuthenticIndexQueue(image);
            for (x=0; x < (ssize_t) image->columns; x++)
            {
              if (matte_image[i] != 0)
                SetPixelIndex(indexes+x,image->colors);
              p++;
            }
          }
        }
      if (matte_image != (unsigned char *) NULL)
        matte_image=(unsigned char *) RelinquishMagickMemory(matte_image);
    }
  /*
    Compute the character per pixel.
  */
  characters_per_pixel=1;
  for (k=MaxCixels; (ssize_t) colors > k; k*=MaxCixels)
    characters_per_pixel++;
  /*
    UIL header.
  */
  symbol=AcquireString("");
  (void) WriteBlobString(image,"/* UIL */\n");
  GetPathComponent(image->filename,BasePath,basename);
  (void) FormatLocaleString(buffer,MaxTextExtent,
    "value\n  %s_ct : color_table(\n",basename);
  (void) WriteBlobString(image,buffer);
  GetMagickPixelPacket(image,&pixel);
  for (i=0; i < (ssize_t) colors; i++)
  {
    /*
      Define UIL color.
    */
    SetMagickPixelPacket(image,image->colormap+i,(IndexPacket *) NULL,&pixel);
    pixel.colorspace=sRGBColorspace;
    pixel.depth=8;
    pixel.opacity=(MagickRealType) OpaqueOpacity;
    GetColorTuple(&pixel,MagickTrue,name);
    if (transparent != MagickFalse)
      if (i == (ssize_t) (colors-1))
        (void) CopyMagickString(name,"None",MaxTextExtent);
    /*
      Write UIL color.
    */
    k=i % MaxCixels;
    symbol[0]=Cixel[k];
    for (j=1; j < (int) characters_per_pixel; j++)
    {
      k=((i-k)/MaxCixels) % MaxCixels;
      symbol[j]=Cixel[k];
    }
    symbol[j]='\0';
    (void) SubstituteString(&symbol,"'","''");
    if (LocaleCompare(name,"None") == 0)
      (void) FormatLocaleString(buffer,MaxTextExtent,
        "    background color = '%s'",symbol);
    else
      (void) FormatLocaleString(buffer,MaxTextExtent,
        "    color('%s',%s) = '%s'",name,
        GetPixelLuma(image,image->colormap+i) < (QuantumRange/2) ?
        "background" : "foreground",symbol);
    (void) WriteBlobString(image,buffer);
    (void) FormatLocaleString(buffer,MaxTextExtent,"%s",
      (i == (ssize_t) (colors-1) ? ");\n" : ",\n"));
    (void) WriteBlobString(image,buffer);
  }
  /*
    Define UIL pixels.
  */
  GetPathComponent(image->filename,BasePath,basename);
  (void) FormatLocaleString(buffer,MaxTextExtent,
    "  %s_icon : icon(color_table = %s_ct,\n",basename,basename);
  (void) WriteBlobString(image,buffer);
  for (y=0; y < (ssize_t) image->rows; y++)
  {
    p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
    if (p == (const PixelPacket *) NULL)
      break;
    indexes=GetVirtualIndexQueue(image);
    (void) WriteBlobString(image,"    \"");
    for (x=0; x < (ssize_t) image->columns; x++)
    {
      k=((ssize_t) GetPixelIndex(indexes+x) % MaxCixels);
      symbol[0]=Cixel[k];
      for (j=1; j < (int) characters_per_pixel; j++)
      {
        k=(((int) GetPixelIndex(indexes+x)-k)/MaxCixels) % MaxCixels;
        symbol[j]=Cixel[k];
      }
      symbol[j]='\0';
      (void) CopyMagickString(buffer,symbol,MaxTextExtent);
      (void) WriteBlobString(image,buffer);
      p++;
    }
    (void) FormatLocaleString(buffer,MaxTextExtent,"\"%s\n",
      (y == (ssize_t) (image->rows-1) ? ");" : ","));
    (void) WriteBlobString(image,buffer);
    status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
      image->rows);
    if (status == MagickFalse)
      break;
  }
  symbol=DestroyString(symbol);
  (void) CloseBlob(image);
  return(MagickTrue);
}
Exemple #13
0
MagickExport Image *CompareImageChannels(Image *image,
  const Image *reconstruct_image,const ChannelType channel,
  const MetricType metric,double *distortion,ExceptionInfo *exception)
{
  Image
    *difference_image;

  long
    y;

  MagickPixelPacket
    composite,
    red,
    source,
    white;

  MagickStatusType
    difference;

  register const IndexPacket
    *indexes,
    *reconstruct_indexes;

  register const PixelPacket
    *p,
    *q;

  register IndexPacket
    *difference_indexes;

  register long
    x;

  register PixelPacket
    *r;

  ViewInfo
    *difference_view,
    *image_view,
    *reconstruct_view;

  assert(image != (Image *) NULL);
  assert(image->signature == MagickSignature);
  if (image->debug != MagickFalse)
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
  assert(reconstruct_image != (const Image *) NULL);
  assert(reconstruct_image->signature == MagickSignature);
  assert(distortion != (double *) NULL);
  *distortion=0.0;
  if (image->debug != MagickFalse)
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
  if ((reconstruct_image->columns != image->columns) ||
      (reconstruct_image->rows != image->rows))
    ThrowImageException(ImageError,"ImageSizeDiffers");
  difference_image=CloneImage(image,image->columns,image->rows,MagickTrue,
    exception);
  if (difference_image == (Image *) NULL)
    return((Image *) NULL);
  if (SetImageStorageClass(difference_image,DirectClass) == MagickFalse)
    {
      InheritException(exception,&difference_image->exception);
      difference_image=DestroyImage(difference_image);
      return((Image *) NULL);
    }
  (void) QueryMagickColor("#f1001e",&red,exception);
  (void) QueryMagickColor("#ffffff",&white,exception);
  if (difference_image->colorspace == CMYKColorspace)
    {
      ConvertRGBToCMYK(&red);
      ConvertRGBToCMYK(&white);
    }
  /*
    Generate difference image.
  */
  GetMagickPixelPacket(reconstruct_image,&source);
  GetMagickPixelPacket(difference_image,&composite);
  image_view=OpenCacheView(image);
  reconstruct_view=OpenCacheView(reconstruct_image);
  difference_view=OpenCacheView(difference_image);
  for (y=0; y < (long) image->rows; y++)
  {
    p=AcquireCacheViewPixels(image_view,0,y,image->columns,1,exception);
    q=AcquireCacheViewPixels(reconstruct_view,0,y,reconstruct_image->columns,1,
      exception);
    r=SetCacheView(difference_view,0,y,difference_image->columns,1);
    if ((p == (const PixelPacket *) NULL) ||
        (q == (const PixelPacket *) NULL) || (r == (PixelPacket *) NULL))
      break;
    indexes=AcquireCacheViewIndexes(image_view);
    reconstruct_indexes=AcquireCacheViewIndexes(reconstruct_view);
    difference_indexes=GetCacheViewIndexes(difference_view);
    for (x=0; x < (long) image->columns; x++)
    {
      difference=MagickFalse;
      if ((channel & RedChannel) != 0)
        if (p->red != q->red)
          difference=MagickTrue;
      if ((channel & GreenChannel) != 0)
        if (p->green != q->green)
          difference=MagickTrue;
      if ((channel & BlueChannel) != 0)
        if (p->blue != q->blue)
          difference=MagickTrue;
      if ((channel & OpacityChannel) != 0)
        if (p->opacity != q->opacity)
          difference=MagickTrue;
      if (((channel & IndexChannel) != 0) &&
          (image->colorspace == CMYKColorspace) &&
          (reconstruct_image->colorspace == CMYKColorspace))
        if (indexes[x] != reconstruct_indexes[x])
          difference=MagickTrue;
      SetMagickPixelPacket(reconstruct_image,q,reconstruct_indexes+x,&source);
      if (difference != MagickFalse)
        MagickPixelCompositeOver(&source,7.5*QuantumRange/10.0,&red,
          (MagickRealType) red.opacity,&composite);
      else
        MagickPixelCompositeOver(&source,7.5*QuantumRange/10.0,&white,
          (MagickRealType) white.opacity,&composite);
      SetPixelPacket(difference_image,&composite,r,difference_indexes+x);
      p++;
      q++;
      r++;
    }
    if (SyncCacheView(difference_view) == MagickFalse)
      break;
  }
  difference_view=CloseCacheView(difference_view);
  reconstruct_view=CloseCacheView(reconstruct_view);
  image_view=CloseCacheView(image_view);
  (void) GetImageChannelDistortion(image,reconstruct_image,channel,metric,
    distortion,exception);
  return(difference_image);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%     P a i n t T r a n s p a r e n t I m a g e                               %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  PaintTransparentImage() changes the opacity value associated with any pixel
%  that matches color to the value defined by opacity.
%
%  By default color must match a particular pixel color exactly.  However,
%  in many cases two colors may differ by a small amount.  Fuzz defines
%  how much tolerance is acceptable to consider two colors as the same.
%  For example, set fuzz to 10 and the color red at intensities of 100 and
%  102 respectively are now interpreted as the same color.
%
%  The format of the PaintTransparentImage method is:
%
%      MagickBooleanType PaintTransparentImage(Image *image,
%        const MagickPixelPacket *target,const Quantum opacity)
%
%  A description of each parameter follows:
%
%    o image: The image.
%
%    o target: The RGB value of the target color.
%
%    o opacity: The replacement opacity value.
%
*/
MagickExport MagickBooleanType PaintTransparentImage(Image *image,
  const MagickPixelPacket *target,const Quantum opacity)
{
#define PaintTransparentImageTag  "Transparent/Image"

  long
    y;

  MagickBooleanType
    status;

  MagickPixelPacket
    pixel;

  register IndexPacket
    *indexes;

  register long
    x;

  register PixelPacket
    *q;

  /*
    Make image color transparent.
  */
  assert(image != (Image *) NULL);
  assert(image->signature == MagickSignature);
  assert(target != (MagickPixelPacket *) NULL);
  if (image->debug != MagickFalse)
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
  if (SetImageStorageClass(image,DirectClass) == MagickFalse)
    return(MagickFalse);
  if (image->matte == MagickFalse)
    (void) SetImageOpacity(image,OpaqueOpacity);
  GetMagickPixelPacket(image,&pixel);
  for (y=0; y < (long) image->rows; y++)
  {
    q=GetImagePixels(image,0,y,image->columns,1);
    if (q == (PixelPacket *) NULL)
      break;
    indexes=GetIndexes(image);
    for (x=0; x < (long) image->columns; x++)
    {
      SetMagickPixelPacket(image,q,indexes+x,&pixel);
      if (IsMagickColorSimilar(&pixel,target) != MagickFalse)
        q->opacity=opacity;
      q++;
    }
    if (SyncImagePixels(image) == MagickFalse)
      break;
    if ((image->progress_monitor != (MagickProgressMonitor) NULL) &&
        (QuantumTick(y,image->rows) != MagickFalse))
      {
        status=image->progress_monitor(PaintTransparentImageTag,y,image->rows,
          image->client_data);
        if (status == MagickFalse)
          break;
      }
  }
  return(MagickTrue);
}
Exemple #15
0
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%     T r a n s p a r e n t P a i n t I m a g e                               %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  TransparentPaintImage() changes the opacity value associated with any pixel
%  that matches color to the value defined by opacity.
%
%  By default color must match a particular pixel color exactly.  However,
%  in many cases two colors may differ by a small amount.  Fuzz defines
%  how much tolerance is acceptable to consider two colors as the same.
%  For example, set fuzz to 10 and the color red at intensities of 100 and
%  102 respectively are now interpreted as the same color.
%
%  The format of the TransparentPaintImage method is:
%
%      MagickBooleanType TransparentPaintImage(Image *image,
%        const MagickPixelPacket *target,const Quantum opacity,
%        const MagickBooleanType invert)
%
%  A description of each parameter follows:
%
%    o image: the image.
%
%    o target: the target color.
%
%    o opacity: the replacement opacity value.
%
%    o invert: paint any pixel that does not match the target color.
%
*/
MagickExport MagickBooleanType TransparentPaintImage(Image *image,
  const MagickPixelPacket *target,const Quantum opacity,
  const MagickBooleanType invert)
{
#define TransparentPaintImageTag  "Transparent/Image"

  CacheView
    *image_view;

  ExceptionInfo
    *exception;

  MagickBooleanType
    status;

  MagickOffsetType
    progress;

  MagickPixelPacket
    zero;

  ssize_t
    y;

  assert(image != (Image *) NULL);
  assert(image->signature == MagickSignature);
  assert(target != (MagickPixelPacket *) NULL);
  if (image->debug != MagickFalse)
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
  if (SetImageStorageClass(image,DirectClass) == MagickFalse)
    return(MagickFalse);
  if (image->matte == MagickFalse)
    (void) SetImageAlphaChannel(image,OpaqueAlphaChannel);
  /*
    Make image color transparent.
  */
  status=MagickTrue;
  progress=0;
  exception=(&image->exception);
  GetMagickPixelPacket(image,&zero);
  image_view=AcquireAuthenticCacheView(image,exception);
#if defined(MAGICKCORE_OPENMP_SUPPORT)
  #pragma omp parallel for schedule(static,4) shared(progress,status) \
    IsConcurrentDos(image->columns,image->rows,64)
#endif
  for (y=0; y < (ssize_t) image->rows; y++)
  {
    MagickPixelPacket
      pixel;

    register IndexPacket
      *restrict indexes;

    register ssize_t
      x;

    register PixelPacket
      *restrict q;

    if (status == MagickFalse)
      continue;
    q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
    if (q == (PixelPacket *) NULL)
      {
        status=MagickFalse;
        continue;
      }
    indexes=GetCacheViewAuthenticIndexQueue(image_view);
    pixel=zero;
    for (x=0; x < (ssize_t) image->columns; x++)
    {
      SetMagickPixelPacket(image,q,indexes+x,&pixel);
      if (IsMagickColorSimilar(&pixel,target) != invert)
        q->opacity=opacity;
      q++;
    }
    if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
      status=MagickFalse;
    if (image->progress_monitor != (MagickProgressMonitor) NULL)
      {
        MagickBooleanType
          proceed;

#if defined(MAGICKCORE_OPENMP_SUPPORT)
        #pragma omp critical (MagickCore_TransparentPaintImage)
#endif
        proceed=SetImageProgress(image,TransparentPaintImageTag,progress++,
          image->rows);
        if (proceed == MagickFalse)
          status=MagickFalse;
      }
  }
  image_view=DestroyCacheView(image_view);
  return(status);
}
Exemple #16
0
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
+   I n t e g r a l R o t a t e I m a g e                                     %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  IntegralRotateImage()  rotates the image an integral of 90 degrees.  It
%  allocates the memory necessary for the new Image structure and returns a
%  pointer to the rotated image.
%
%  The format of the IntegralRotateImage method is:
%
%      Image *IntegralRotateImage(const Image *image,unsigned long rotations,
%        ExceptionInfo *exception)
%
%  A description of each parameter follows.
%
%    o image: the image.
%
%    o rotations: Specifies the number of 90 degree rotations.
%
%
*/
static Image *IntegralRotateImage(const Image *image,unsigned long rotations,
  ExceptionInfo *exception)
{
#define TileHeight  128
#define TileWidth  128
#define RotateImageTag  "Rotate/Image"

  Image
    *rotate_image;

  long
    tile_x,
    tile_y,
    y;

  MagickBooleanType
    status;

  MagickPixelPacket
    pixel;

  RectangleInfo
    page;

  register IndexPacket
    *indexes,
    *rotate_indexes;

  register const PixelPacket
    *p,
    *tile_pixels;

  register long
    x;

  register PixelPacket
    *q;

  unsigned long
    tile_width,
    tile_height;

  /*
    Initialize rotated image attributes.
  */
  assert(image != (Image *) NULL);
  page=image->page;
  rotations%=4;
  if ((rotations == 1) || (rotations == 3))
    rotate_image=CloneImage(image,image->rows,image->columns,MagickTrue,
      exception);
  else
    rotate_image=CloneImage(image,image->columns,image->rows,MagickTrue,
      exception);
  if (rotate_image == (Image *) NULL)
    return((Image *) NULL);
  /*
    Integral rotate the image.
  */
  GetMagickPixelPacket(image,&pixel);
  switch (rotations)
  {
    case 0:
    {
      /*
        Rotate 0 degrees.
      */
      for (y=0; y < (long) image->rows; y++)
      {
        p=AcquireImagePixels(image,0,y,image->columns,1,exception);
        q=SetImagePixels(rotate_image,0,y,rotate_image->columns,1);
        if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
          break;
        indexes=GetIndexes(image);
        rotate_indexes=GetIndexes(rotate_image);
        for (x=0; x < (long) image->columns; x++)
        {
          SetMagickPixelPacket(image,p,indexes+x,&pixel);
          SetPixelPacket(rotate_image,&pixel,q,rotate_indexes+x);
          p++;
          q++;
        }
        if (SyncImagePixels(rotate_image) == MagickFalse)
          break;
        if ((image->progress_monitor != (MagickProgressMonitor) NULL) &&
            (QuantumTick(y,image->rows) != MagickFalse))
          {
            status=image->progress_monitor(RotateImageTag,y,image->rows,
              image->client_data);
            if (status == MagickFalse)
              break;
          }
      }
      break;
    }
    case 1:
    {
      /*
        Rotate 90 degrees.
      */
      for (tile_y=0; tile_y < (long) image->rows; tile_y+=TileHeight)
      {
        for (tile_x=0; tile_x < (long) image->columns; tile_x+=TileWidth)
        {
          tile_width=TileWidth;
          if ((tile_x+TileWidth) > (long) image->columns)
            tile_width=1UL*(TileWidth-(tile_x+TileWidth-image->columns));
          tile_height=TileHeight;
          if ((tile_y+TileHeight) > (long) image->rows)
            tile_height=1UL*(TileHeight-(tile_y+TileHeight-image->rows));
          tile_pixels=AcquireImagePixels(image,tile_x,tile_y,tile_width,
            tile_height,exception);
          if (tile_pixels == (const PixelPacket *) NULL)
            break;
          for (y=0; y < (long) tile_width; y++)
          {
            q=SetImagePixels(rotate_image,(long) rotate_image->columns-(tile_y+
              tile_height),tile_x+y,tile_height,1);
            if (q == (PixelPacket *) NULL)
              break;
            rotate_indexes=GetIndexes(rotate_image);
            p=tile_pixels+(tile_height-1)*tile_width+y;
            indexes=GetIndexes(image)+(tile_height-1)*tile_width+y;
            for (x=0; x < (long) tile_height; x++)
            {
              SetMagickPixelPacket(image,p,indexes,&pixel);
              SetPixelPacket(rotate_image,&pixel,q,rotate_indexes+x);
              p-=tile_width;
              indexes-=tile_width;
              q++;
            }
            if (SyncImagePixels(rotate_image) == MagickFalse)
              break;
          }
        }
        if ((image->progress_monitor != (MagickProgressMonitor) NULL) &&
            (QuantumTick(tile_y,image->rows) != MagickFalse))
          {
            status=image->progress_monitor(RotateImageTag,tile_y,image->rows,
              image->client_data);
            if (status == MagickFalse)
              break;
          }
      }
      Swap(page.width,page.height);
      Swap(page.x,page.y);
      if (page.width != 0)
        page.x=(long) (page.width-rotate_image->columns-page.x);
      break;
    }
    case 2:
    {
      /*
        Rotate 180 degrees.
      */
      for (y=0; y < (long) image->rows; y++)
      {
        p=AcquireImagePixels(image,0,y,image->columns,1,exception);
        q=SetImagePixels(rotate_image,0,(long) (image->rows-y-1),
          image->columns,1);
        if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
          break;
        q+=image->columns;
        indexes=GetIndexes(image);
        rotate_indexes=GetIndexes(rotate_image);
        for (x=0; x < (long) image->columns; x++)
        {
          q--;
          SetMagickPixelPacket(image,p,indexes+x,&pixel);
          SetPixelPacket(rotate_image,&pixel,q,rotate_indexes+(image->columns-
            x-1));
          p++;
        }
        if (SyncImagePixels(rotate_image) == MagickFalse)
          break;
        if ((image->progress_monitor != (MagickProgressMonitor) NULL) &&
            (QuantumTick(y,image->rows) != MagickFalse))
          {
            status=image->progress_monitor(RotateImageTag,y,image->rows,
              image->client_data);
            if (status == MagickFalse)
              break;
          }
      }
      if (page.width != 0)
        page.x=(long) (page.width-rotate_image->columns-page.x);
      if (page.height != 0)
        page.y=(long) (page.height-rotate_image->rows-page.y);
      break;
    }
    case 3:
    {
      /*
        Rotate 270 degrees.
      */
      for (tile_y=0; tile_y < (long) image->rows; tile_y+=TileHeight)
      {
        for (tile_x=0; tile_x < (long) image->columns; tile_x+=TileWidth)
        {
          tile_width=TileWidth;
          if ((tile_x+TileWidth) > (long) image->columns)
            tile_width=1UL*(TileWidth-(tile_x+TileWidth-image->columns));
          tile_height=TileHeight;
          if ((tile_y+TileHeight) > (long) image->rows)
            tile_height=1UL*(TileHeight-(tile_y+TileHeight-image->rows));
          tile_pixels=AcquireImagePixels(image,tile_x,tile_y,tile_width,
            tile_height,exception);
          if (tile_pixels == (const PixelPacket *) NULL)
            break;
          for (y=0; y < (long) tile_width; y++)
          {
            q=SetImagePixels(rotate_image,tile_y,(long) rotate_image->rows-
              (tile_x+tile_width)+y,tile_height,1);
            if (q == (PixelPacket *) NULL)
              break;
            rotate_indexes=GetIndexes(rotate_image);
            p=tile_pixels+(tile_width-1)-y;
            indexes=GetIndexes(image)+(tile_width-1)-y;
            for (x=0; x < (long) tile_height; x++)
            {
              SetMagickPixelPacket(image,p,indexes,&pixel);
              SetPixelPacket(rotate_image,&pixel,q,rotate_indexes+x);
              p+=tile_width;
              indexes+=tile_width;
              q++;
            }
            if (SyncImagePixels(rotate_image) == MagickFalse)
              break;
          }
        }
        if ((image->progress_monitor != (MagickProgressMonitor) NULL) &&
            (QuantumTick(tile_y,image->rows) != MagickFalse))
          {
            status=image->progress_monitor(RotateImageTag,tile_y,image->rows,
              image->client_data);
            if (status == MagickFalse)
              break;
          }
      }
      Swap(page.width,page.height);
      Swap(page.x,page.y);
      if (page.height != 0)
        page.y=(long) (page.height-rotate_image->rows-page.y);
      break;
    }
  }
  rotate_image->page=page;
  return(rotate_image);
}
Exemple #17
0
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   I d e n t i f y I m a g e                                                 %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  IdentifyImage() identifies an image by printing its attributes to the file.
%  Attributes include the image width, height, size, and others.
%
%  The format of the IdentifyImage method is:
%
%      MagickBooleanType IdentifyImage(Image *image,FILE *file,
%        const MagickBooleanType verbose)
%
%  A description of each parameter follows:
%
%    o image: The image.
%
%    o file: The file, typically stdout.
%
%    o verbose: A value other than zero prints more detailed information
%      about the image.
%
*/
MagickExport MagickBooleanType IdentifyImage(Image *image,FILE *file,
  const MagickBooleanType verbose)
{
#define IdentifyFormat "    %s:\n      Min: " QuantumFormat  \
  " (%g)\n      Max: " QuantumFormat " (%g)\n"  \
  "      Mean: %g (%g)\n      Standard deviation: %g (%g)\n"

  char
    color[MaxTextExtent],
    format[MaxTextExtent],
    key[MaxTextExtent];

  ColorspaceType
    colorspace;

  const char
    *property,
    *value;

  const MagickInfo
    *magick_info;

  const PixelPacket
    *pixels;

  double
    elapsed_time,
    user_time;

  ExceptionInfo
    *exception;

  Image
    *p;

  ImageType
    type;

  long
    y;

  MagickBooleanType
    ping;

  register long
    i,
    x;

  unsigned long
    scale;

  assert(image != (Image *) NULL);
  assert(image->signature == MagickSignature);
  if (image->debug != MagickFalse)
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
  if (file == (FILE *) NULL)
    file=stdout;
  *format='\0';
  elapsed_time=GetElapsedTime(&image->timer);
  user_time=GetUserTime(&image->timer);
  GetTimerInfo(&image->timer);
  if (verbose == MagickFalse)
    {
      /*
        Display summary info about the image.
      */
      if (*image->magick_filename != '\0')
        if (LocaleCompare(image->magick_filename,image->filename) != 0)
          (void) fprintf(file,"%s=>",image->magick_filename);
       if ((GetPreviousImageInList(image) == (Image *) NULL) &&
           (GetNextImageInList(image) == (Image *) NULL) && (image->scene == 0))
        (void) fprintf(file,"%s ",image->filename);
      else
        (void) fprintf(file,"%s[%lu] ",image->filename,image->scene);
      (void) fprintf(file,"%s ",image->magick);
      if ((image->magick_columns != 0) || (image->magick_rows != 0))
        if ((image->magick_columns != image->columns) ||
            (image->magick_rows != image->rows))
          (void) fprintf(file,"%lux%lu=>",image->magick_columns,
            image->magick_rows);
      (void) fprintf(file,"%lux%lu ",image->columns,image->rows);
      if ((image->page.width != 0) || (image->page.height != 0) ||
          (image->page.x != 0) || (image->page.y != 0))
        (void) fprintf(file,"%lux%lu%+ld%+ld ",image->page.width,
          image->page.height,image->page.x,image->page.y);
      if (image->storage_class == DirectClass)
        {
          (void) fprintf(file,"DirectClass ");
          if (image->total_colors != 0)
            {
              (void) FormatMagickSize(image->total_colors,format);
              (void) fprintf(file,"%s ",format);
            }
        }
      else
        if (image->total_colors <= image->colors)
          (void) fprintf(file,"PseudoClass %luc ",image->colors);
        else
          (void) fprintf(file,"PseudoClass %lu=>%luc ",image->total_colors,
            image->colors);
      (void) fprintf(file,"%lu-bit ",image->depth);
      if (image->error.mean_error_per_pixel != 0.0)
        (void) fprintf(file,"%ld/%f/%fdb ",
          (long) (image->error.mean_error_per_pixel+0.5),
          image->error.normalized_mean_error,
          image->error.normalized_maximum_error);
      if (GetBlobSize(image) != 0)
        {
          (void) FormatMagickSize(GetBlobSize(image),format);
          (void) fprintf(file,"%s ",format);
        }
      if (elapsed_time > 0.06)
        (void) fprintf(file,"%0.3fu %ld:%02ld",user_time,
          (long) (elapsed_time/60.0+0.5),(long) ceil(fmod(elapsed_time,60.0)));
      (void) fprintf(file,"\n");
      (void) fflush(file);
      return(ferror(file) != 0 ? MagickFalse : MagickTrue);
    }
  /*
    Display verbose info about the image.
  */
  exception=AcquireExceptionInfo();
  pixels=AcquireImagePixels(image,0,0,1,1,exception);
  exception=DestroyExceptionInfo(exception);
  ping=pixels == (const PixelPacket *) NULL ? MagickTrue : MagickFalse;
  type=GetImageType(image,&image->exception);
  (void) SignatureImage(image);
  (void) fprintf(file,"Image: %s\n",image->filename);
  if (*image->magick_filename != '\0')
    if (LocaleCompare(image->magick_filename,image->filename) != 0)
      {
        char
          filename[MaxTextExtent];

        GetPathComponent(image->magick_filename,TailPath,filename);
        (void) fprintf(file,"  Base filename: %s\n",filename);
      }
  magick_info=GetMagickInfo(image->magick,&image->exception);
  if ((magick_info == (const MagickInfo *) NULL) ||
      (*GetMagickDescription(magick_info) == '\0'))
    (void) fprintf(file,"  Format: %s\n",image->magick);
  else
    (void) fprintf(file,"  Format: %s (%s)\n",image->magick,
      GetMagickDescription(magick_info));
  (void) fprintf(file,"  Class: %s\n",
    MagickOptionToMnemonic(MagickClassOptions,(long) image->storage_class));
  (void) fprintf(file,"  Geometry: %lux%lu%+ld%+ld\n",image->columns,
    image->rows,image->tile_offset.x,image->tile_offset.y);
  if ((image->magick_columns != 0) || (image->magick_rows != 0))
    if ((image->magick_columns != image->columns) ||
        (image->magick_rows != image->rows))
      (void) fprintf(file,"  Base geometry: %lux%lu\n",image->magick_columns,
        image->magick_rows);
  (void) fprintf(file,"  Type: %s\n",MagickOptionToMnemonic(MagickTypeOptions,
    (long) type));
  (void) fprintf(file,"  Endianess: %s\n",MagickOptionToMnemonic(
    MagickEndianOptions,(long) image->endian));
  /*
    Detail channel depth and extrema.
  */
  colorspace=image->colorspace;
  if (IsGrayImage(image,&image->exception) != MagickFalse)
    colorspace=GRAYColorspace;
  (void) fprintf(file,"  Colorspace: %s\n",
    MagickOptionToMnemonic(MagickColorspaceOptions,(long) colorspace));
  if (ping == MagickFalse)
    {
      ChannelStatistics
        *channel_statistics;

      (void) fprintf(file,"  Depth: %lu-bit\n",GetImageDepth(image,
        &image->exception));
      channel_statistics=GetImageChannelStatistics(image,&image->exception);
      (void) fprintf(file,"  Channel depth:\n");
      switch (colorspace)
      {
        case RGBColorspace:
        default:
        {
          (void) fprintf(file,"    Red: %lu-bit\n",
            channel_statistics[RedChannel].depth);
          (void) fprintf(file,"    Green: %lu-bit\n",
            channel_statistics[GreenChannel].depth);
          (void) fprintf(file,"    Blue: %lu-bit\n",
            channel_statistics[BlueChannel].depth);
          if (image->matte != MagickFalse)
            (void) fprintf(file,"    Alpha: %lu-bit\n",
              channel_statistics[OpacityChannel].depth);
          break;
        }
        case CMYKColorspace:
        {
          (void) fprintf(file,"    Cyan: %lu-bit\n",
            channel_statistics[CyanChannel].depth);
          (void) fprintf(file,"    Magenta: %lu-bit\n",
            channel_statistics[MagentaChannel].depth);
          (void) fprintf(file,"    Yellow: %lu-bit\n",
            channel_statistics[YellowChannel].depth);
          (void) fprintf(file,"    Black: %lu-bit\n",
            channel_statistics[BlackChannel].depth);
          if (image->matte != MagickFalse)
            (void) fprintf(file,"    Alpha: %lu-bit\n",
              channel_statistics[OpacityChannel].depth);
          break;
        }
        case GRAYColorspace:
        {
          (void) fprintf(file,"    Gray: %lu-bit\n",
            channel_statistics[GrayChannel].depth);
          if (image->matte != MagickFalse)
            (void) fprintf(file,"    Alpha: %lu-bit\n",
              channel_statistics[OpacityChannel].depth);
          break;
        }
      }
      scale=QuantumRange/((unsigned long) QuantumRange >> ((unsigned long)
        MAGICKCORE_QUANTUM_DEPTH-channel_statistics[AllChannels].depth));
      (void) fprintf(file,"  Channel statistics:\n");
      switch (colorspace)
      {
        case RGBColorspace:
        default:
        {
          (void) fprintf(file,IdentifyFormat,"Red",(Quantum)
            (channel_statistics[RedChannel].minima/scale),(double)
            channel_statistics[RedChannel].minima/(double) QuantumRange,
            (Quantum) (channel_statistics[RedChannel].maxima/scale),(double)
            channel_statistics[RedChannel].maxima/(double) QuantumRange,
            channel_statistics[RedChannel].mean/(double) scale,
            channel_statistics[RedChannel].mean/(double) QuantumRange,
            channel_statistics[RedChannel].standard_deviation/(double) scale,
            channel_statistics[RedChannel].standard_deviation/(double)
            QuantumRange);
          (void) fprintf(file,IdentifyFormat,"Green",(Quantum)
            (channel_statistics[GreenChannel].minima/scale),(double)
            channel_statistics[GreenChannel].minima/(double) QuantumRange,
            (Quantum) (channel_statistics[GreenChannel].maxima/scale),(double)
            channel_statistics[GreenChannel].maxima/(double) QuantumRange,
            channel_statistics[GreenChannel].mean/(double) scale,
            channel_statistics[GreenChannel].mean/(double) QuantumRange,
            channel_statistics[GreenChannel].standard_deviation/(double) scale,
            channel_statistics[GreenChannel].standard_deviation/(double)
            QuantumRange);
          (void) fprintf(file,IdentifyFormat,"Blue",(Quantum)
            (channel_statistics[BlueChannel].minima/scale),(double)
            channel_statistics[BlueChannel].minima/(double) QuantumRange,
            (Quantum) (channel_statistics[BlueChannel].maxima/scale),(double)
            channel_statistics[BlueChannel].maxima/(double) QuantumRange,
            channel_statistics[BlueChannel].mean/(double) scale,
            channel_statistics[BlueChannel].mean/(double) QuantumRange,
            channel_statistics[BlueChannel].standard_deviation/(double) scale,
            channel_statistics[BlueChannel].standard_deviation/(double)
            QuantumRange);
          break;
        }
        case CMYKColorspace:
        {
          (void) fprintf(file,IdentifyFormat,"Cyan",(Quantum)
            (channel_statistics[CyanChannel].minima/scale),(double)
            channel_statistics[CyanChannel].minima/(double) QuantumRange,
            (Quantum) (channel_statistics[CyanChannel].maxima/scale),(double)
            channel_statistics[CyanChannel].maxima/(double) QuantumRange,
            channel_statistics[CyanChannel].mean/(double) scale,
            channel_statistics[CyanChannel].mean/(double) QuantumRange,
            channel_statistics[CyanChannel].standard_deviation/(double) scale,
            channel_statistics[CyanChannel].standard_deviation/(double)
            QuantumRange);
          (void) fprintf(file,IdentifyFormat,"Magenta",(Quantum)
            (channel_statistics[MagentaChannel].minima/scale),(double)
            channel_statistics[MagentaChannel].minima/(double) QuantumRange,
            (Quantum) (channel_statistics[MagentaChannel].maxima/scale),(double)
            channel_statistics[MagentaChannel].maxima/(double) QuantumRange,
            channel_statistics[MagentaChannel].mean/(double) scale,
            channel_statistics[MagentaChannel].mean/(double) QuantumRange,
            channel_statistics[MagentaChannel].standard_deviation/(double)
            scale,channel_statistics[MagentaChannel].standard_deviation/(double)
            QuantumRange);
          (void) fprintf(file,IdentifyFormat,"Yellow",(Quantum)
            (channel_statistics[YellowChannel].minima/scale),(double)
            channel_statistics[YellowChannel].minima/(double) QuantumRange,
            (Quantum) (channel_statistics[YellowChannel].maxima/scale),(double)
            channel_statistics[YellowChannel].maxima/(double) QuantumRange,
            channel_statistics[YellowChannel].mean/(double) scale,
            channel_statistics[YellowChannel].mean/(double) QuantumRange,
            channel_statistics[YellowChannel].standard_deviation/(double) scale,
            channel_statistics[YellowChannel].standard_deviation/(double)
            QuantumRange);
          (void) fprintf(file,IdentifyFormat,"Black",(Quantum)
            (channel_statistics[BlackChannel].minima/scale),(double)
            channel_statistics[BlackChannel].minima/(double) QuantumRange,
            (Quantum) (channel_statistics[BlackChannel].maxima/scale),(double)
            channel_statistics[BlackChannel].maxima/(double) QuantumRange,
            channel_statistics[BlackChannel].mean/(double) scale,
            channel_statistics[BlackChannel].mean/(double) QuantumRange,
            channel_statistics[BlackChannel].standard_deviation/(double) scale,
            channel_statistics[BlackChannel].standard_deviation/(double)
            QuantumRange);
          break;
        }
        case GRAYColorspace:
        {
          (void) fprintf(file,IdentifyFormat,"Gray",(Quantum)
            (channel_statistics[GrayChannel].minima/scale),(double)
            channel_statistics[GrayChannel].minima/(double) QuantumRange,
            (Quantum) (channel_statistics[GrayChannel].maxima/scale),(double)
            channel_statistics[GrayChannel].maxima/(double) QuantumRange,
            channel_statistics[GrayChannel].mean/(double) scale,
            channel_statistics[GrayChannel].mean/(double) QuantumRange,
            channel_statistics[GrayChannel].standard_deviation/(double) scale,
            channel_statistics[GrayChannel].standard_deviation/(double)
            QuantumRange);
          break;
        }
      }
      if (image->matte != MagickFalse)
        (void) fprintf(file,IdentifyFormat,"Opacity",(Quantum)
          (channel_statistics[OpacityChannel].minima/scale),(double)
          channel_statistics[OpacityChannel].minima/(double) QuantumRange,
          (Quantum) (channel_statistics[OpacityChannel].maxima/scale),(double)
          channel_statistics[OpacityChannel].maxima/(double) QuantumRange,
          channel_statistics[OpacityChannel].mean/(double) scale,
          channel_statistics[OpacityChannel].mean/(double) QuantumRange,
          channel_statistics[OpacityChannel].standard_deviation/(double) scale,
          channel_statistics[OpacityChannel].standard_deviation/(double)
          QuantumRange);
      channel_statistics=(ChannelStatistics *) RelinquishMagickMemory(
        channel_statistics);
      if (colorspace == CMYKColorspace)
        (void) fprintf(file,"  Total ink density: %.0f%%\n",100.0*
          GetImageTotalInkDensity(image)/(double) QuantumRange);
      x=0;
      p=NewImageList();
      if (image->matte != MagickFalse)
        {
          register const IndexPacket
            *indexes;

          register const PixelPacket
            *p;

          p=(PixelPacket *) NULL;
          indexes=(IndexPacket *) NULL;
          for (y=0; y < (long) image->rows; y++)
          {
            p=AcquireImagePixels(image,0,y,image->columns,1,&image->exception);
            if (p == (const PixelPacket *) NULL)
              break;
            indexes=AcquireIndexes(image);
            for (x=0; x < (long) image->columns; x++)
            {
              if (p->opacity == (Quantum) TransparentOpacity)
                break;
              p++;
            }
            if (x < (long) image->columns)
              break;
          }
          if ((x < (long) image->columns) || (y < (long) image->rows))
            {
              char
                tuple[MaxTextExtent];

              MagickPixelPacket
                pixel;

              GetMagickPixelPacket(image,&pixel);
              SetMagickPixelPacket(image,p,indexes+x,&pixel);
              (void) QueryMagickColorname(image,&pixel,SVGCompliance,
                MagickFalse,tuple,&image->exception);
              (void) fprintf(file,"  Alpha: %s  ",tuple);
              (void) QueryMagickColorname(image,&pixel,SVGCompliance,MagickTrue,
                tuple,&image->exception);
              (void) fprintf(file,"  %s\n",tuple);
            }
        }
      if ((ping == MagickFalse) &&
          (IsHistogramImage(image,&image->exception) != MagickFalse))
        {
          (void) fprintf(file,"  Histogram:\n");
          (void) GetNumberColors(image,file,&image->exception);
        }
    }
Exemple #18
0
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
+   Y S h e a r I m a g e                                                     %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  YShearImage shears the image in the Y direction with a shear angle of
%  'degrees'.  Positive angles shear counter-clockwise (right-hand rule), and
%  negative angles shear clockwise.  Angles are measured relative to a
%  horizontal X-axis.  Y shears will increase the height of an image creating
%  'empty' triangles on the top and bottom of the source image.
%
%  The format of the YShearImage method is:
%
%      void YShearImage(Image *image,const MagickRealType degrees,
%        const unsigned long width,const unsigned long height,long x_offset,
%        const long y_offset)
%
%  A description of each parameter follows.
%
%    o image: the image.
%
%    o degrees: A MagickRealType representing the shearing angle along the Y
%      axis.
%
%    o width, height, x_offset, y_offset: Defines a region of the image
%      to shear.
%
*/
static void YShearImage(Image *image,const MagickRealType degrees,
  const unsigned long width,const unsigned long height,long x_offset,
  const long y_offset)
{
#define YShearImageTag  "YShear/Image"

  enum {UP, DOWN}
    direction;

  IndexPacket
    *indexes,
    *shear_indexes;

  long
    step,
    y;

  MagickBooleanType
    status;

  MagickPixelPacket
    background,
    pixel,
    source,
    destination;

  MagickRealType
    area,
    displacement;

  register PixelPacket
    *p,
    *q;

  register long
    i;

  assert(image != (Image *) NULL);
  x_offset--;
  for (y=0; y < (long) width; y++)
  {
    x_offset++;
    displacement=degrees*(MagickRealType) (y-width/2.0);
    if (displacement == 0.0)
      continue;
    if (displacement > 0.0)
      direction=DOWN;
    else
      {
        displacement*=(-1.0);
        direction=UP;
      }
    step=(long) floor((double) displacement);
    area=(MagickRealType) (displacement-step);
    step++;
    GetMagickPixelPacket(image,&background);
    SetMagickPixelPacket(image,&image->background_color,(IndexPacket *) NULL,
      &background);
    if (image->colorspace == CMYKColorspace)
      ConvertRGBToCMYK(&background);
    pixel=background;
    GetMagickPixelPacket(image,&source);
    GetMagickPixelPacket(image,&destination);
    switch (direction)
    {
      case UP:
      {
        /*
          Transfer pixels top-to-bottom.
        */
        if (step > y_offset)
          break;
        p=GetImagePixels(image,x_offset,0,1,image->rows);
        if (p == (PixelPacket *) NULL)
          break;
        p+=y_offset;
        indexes=GetIndexes(image);
        indexes+=y_offset;
        q=p-step;
        shear_indexes=indexes-step;
        for (i=0; i < (long) height; i++)
        {
          if ((y_offset+i) < step)
            {
              SetMagickPixelPacket(image,++p,++indexes,&pixel);
              q++;
              shear_indexes++;
              continue;
            }
          SetMagickPixelPacket(image,p,indexes,&source);
          MagickCompositeBlend(&pixel,(MagickRealType) pixel.opacity,&source,
            (MagickRealType) p->opacity,area,&destination);
          SetPixelPacket(image,&destination,q++,shear_indexes++);
          SetMagickPixelPacket(image,p++,indexes++,&pixel);
        }
        MagickCompositeBlend(&pixel,(MagickRealType) pixel.opacity,&background,
          (MagickRealType) background.opacity,area,&destination);
        SetPixelPacket(image,&destination,q++,shear_indexes++);
        for (i=0; i < (step-1); i++)
          SetPixelPacket(image,&background,q++,shear_indexes++);
        break;
      }
      case DOWN:
      {
        /*
          Transfer pixels bottom-to-top.
        */
        p=GetImagePixels(image,x_offset,0,1,image->rows);
        if (p == (PixelPacket *) NULL)
          break;
        p+=y_offset+height;
        indexes=GetIndexes(image);
        indexes+=y_offset+height;
        q=p+step;
        shear_indexes=indexes+step;
        for (i=0; i < (long) height; i++)
        {
          p--;
          indexes--;
          q--;
          shear_indexes--;
          if ((unsigned long) (y_offset+height+step-i) >= image->rows)
            continue;
          SetMagickPixelPacket(image,p,indexes,&source);
          MagickCompositeBlend(&pixel,(MagickRealType) pixel.opacity,&source,
            (MagickRealType) p->opacity,area,&destination);
          SetPixelPacket(image,&destination,q,shear_indexes);
          SetMagickPixelPacket(image,p,indexes,&pixel);
        }
        MagickCompositeBlend(&pixel,(MagickRealType) pixel.opacity,&background,
          (MagickRealType) background.opacity,area,&destination);
        SetPixelPacket(image,&destination,--q,--shear_indexes);
        for (i=0; i < (step-1); i++)
          SetPixelPacket(image,&background,--q,--shear_indexes);
        break;
      }
    }
    if (SyncImagePixels(image) == MagickFalse)
      break;
    if ((image->progress_monitor != (MagickProgressMonitor) NULL) &&
        (QuantumTick(y,width) != MagickFalse))
      {
        status=image->progress_monitor(XShearImageTag,y,width,
          image->client_data);
        if (status == MagickFalse)
          break;
      }
  }
}
Exemple #19
0
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%     T r a n s p a r e n t P a i n t I m a g e C h r o m a                   %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  TransparentPaintImageChroma() changes the opacity value associated with any
%  pixel that matches color to the value defined by opacity.
%
%  As there is one fuzz value for the all the channels, the
%  TransparentPaintImage() API is not suitable for the operations like chroma,
%  where the tolerance for similarity of two color component (RGB) can be
%  different, Thus we define this method take two target pixels (one
%  low and one hight) and all the pixels of an image which are lying between
%  these two pixels are made transparent.
%
%  The format of the TransparentPaintImage method is:
%
%      MagickBooleanType TransparentPaintImage(Image *image,
%        const MagickPixelPacket *low,const MagickPixelPacket *hight,
%        const Quantum opacity,const MagickBooleanType invert)
%
%  A description of each parameter follows:
%
%    o image: the image.
%
%    o low: the low target color.
%
%    o high: the high target color.
%
%    o opacity: the replacement opacity value.
%
%    o invert: paint any pixel that does not match the target color.
%
*/
MagickExport MagickBooleanType TransparentPaintImageChroma(Image *image,
  const MagickPixelPacket *low,const MagickPixelPacket *high,
  const Quantum opacity,const MagickBooleanType invert)
{
#define TransparentPaintImageTag  "Transparent/Image"

  CacheView
    *image_view;

  ExceptionInfo
    *exception;

  MagickBooleanType
    status;

  MagickOffsetType
    progress;

  ssize_t
    y;

  assert(image != (Image *) NULL);
  assert(image->signature == MagickSignature);
  assert(high != (MagickPixelPacket *) NULL);
  assert(low != (MagickPixelPacket *) NULL);
  if (image->debug != MagickFalse)
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
  if (SetImageStorageClass(image,DirectClass) == MagickFalse)
    return(MagickFalse);
  if (image->matte == MagickFalse)
    (void) SetImageAlphaChannel(image,ResetAlphaChannel);
  /*
    Make image color transparent.
  */
  status=MagickTrue;
  progress=0;
  exception=(&image->exception);
  image_view=AcquireCacheView(image);
#if defined(MAGICKCORE_OPENMP_SUPPORT)
  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
#endif
  for (y=0; y < (ssize_t) image->rows; y++)
  {
    MagickBooleanType
      match;

    MagickPixelPacket
      pixel;

    register IndexPacket
      *restrict indexes;

    register ssize_t
      x;

    register PixelPacket
      *restrict q;

    if (status == MagickFalse)
      continue;
    q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
    if (q == (PixelPacket *) NULL)
      {
        status=MagickFalse;
        continue;
      }
    indexes=GetCacheViewAuthenticIndexQueue(image_view);
    GetMagickPixelPacket(image,&pixel);
    for (x=0; x < (ssize_t) image->columns; x++)
    {
      SetMagickPixelPacket(image,q,indexes+x,&pixel);
      match=((pixel.red >= low->red) && (pixel.red <= high->red) &&
        (pixel.green >= low->green) && (pixel.green <= high->green) &&
        (pixel.blue  >= low->blue) && (pixel.blue <= high->blue)) ?
        MagickTrue : MagickFalse;
      if (match != invert)
        q->opacity=opacity;
      q++;
    }
    if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
      status=MagickFalse;
    if (image->progress_monitor != (MagickProgressMonitor) NULL)
      {
        MagickBooleanType
          proceed;

#if defined(MAGICKCORE_OPENMP_SUPPORT)
  #pragma omp critical (MagickCore_TransparentPaintImageChroma)
#endif
        proceed=SetImageProgress(image,TransparentPaintImageTag,progress++,
          image->rows);
        if (proceed == MagickFalse)
          status=MagickFalse;
      }
  }
  image_view=DestroyCacheView(image_view);
  return(status);
}
Exemple #20
0
static MagickBooleanType StatisticsComponentsStatistics(const Image *image,
  const Image *component_image,const size_t number_objects,
  ExceptionInfo *exception)
{
  CacheView
    *component_view,
    *image_view;

  CCObject
    *object;

  MagickBooleanType
    status;

  register ssize_t
    i;

  ssize_t
    y;

  /*
    Collect statistics on unique objects.
  */
  object=(CCObject *) AcquireQuantumMemory(number_objects,sizeof(*object));
  if (object == (CCObject *) NULL)
    {
      (void) ThrowMagickException(exception,GetMagickModule(),
         ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
      return(MagickFalse);
    }
  (void) ResetMagickMemory(object,0,number_objects*sizeof(*object));
  for (i=0; i < (ssize_t) number_objects; i++)
  {
    object[i].id=i;
    object[i].bounding_box.x=(ssize_t) image->columns;
    object[i].bounding_box.y=(ssize_t) image->rows;
    GetMagickPixelPacket(image,&object[i].color);
  }
  status=MagickTrue;
  image_view=AcquireVirtualCacheView(image,exception);
  component_view=AcquireVirtualCacheView(component_image,exception);
  for (y=0; y < (ssize_t) image->rows; y++)
  {
    register const PixelPacket
      *restrict p,
      *restrict q;

    register const IndexPacket
      *indexes;

    register ssize_t
      x;

    if (status == MagickFalse)
      continue;
    p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
    q=GetCacheViewVirtualPixels(component_view,0,y,component_image->columns,1,
      exception);
    if ((p == (const PixelPacket *) NULL) ||
        (q == (const PixelPacket *) NULL))
      {
        status=MagickFalse;
        continue;
      }
    indexes=GetVirtualIndexQueue(image);
    for (x=0; x < (ssize_t) image->columns; x++)
    {
      i=(ssize_t) q->red;
      if (x < object[i].bounding_box.x)
        object[i].bounding_box.x=x;
      if (x > (ssize_t) object[i].bounding_box.width)
        object[i].bounding_box.width=(size_t) x;
      if (y < object[i].bounding_box.y)
        object[i].bounding_box.y=y;
      if (y > (ssize_t) object[i].bounding_box.height)
        object[i].bounding_box.height=(size_t) y;
      object[i].color.red+=p->red;
      object[i].color.green+=p->green;
      object[i].color.blue+=p->blue;
      if (image->matte != MagickFalse)
        object[i].color.opacity+=p->opacity;
      if (image->colorspace == CMYKColorspace)
        object[i].color.index+=indexes[x];
      object[i].centroid.x+=x;
      object[i].centroid.y+=y;
      object[i].area++;
      p++;
      q++;
    }
  }
  for (i=0; i < (ssize_t) number_objects; i++)
  {
    object[i].bounding_box.width-=(object[i].bounding_box.x-1);
    object[i].bounding_box.height-=(object[i].bounding_box.y-1);
    object[i].color.red=object[i].color.red/object[i].area;
    object[i].color.green=object[i].color.green/object[i].area;
    object[i].color.blue=object[i].color.blue/object[i].area;
    if (image->matte != MagickFalse)
      object[i].color.opacity=object[i].color.opacity/object[i].area;
    if (image->colorspace == CMYKColorspace)
      object[i].color.index=object[i].color.index/object[i].area;
    object[i].centroid.x=object[i].centroid.x/object[i].area;
    object[i].centroid.y=object[i].centroid.y/object[i].area;
  }
  component_view=DestroyCacheView(component_view);
  image_view=DestroyCacheView(image_view);
  /*
    Report statistics on unique objects.
  */
  qsort((void *) object,number_objects,sizeof(*object),CCObjectCompare);
  (void) fprintf(stdout,
    "Objects (id: bounding-box centroid area mean-color):\n");
  for (i=0; i < (ssize_t) number_objects; i++)
  {
    char
      mean_color[MaxTextExtent];

    if (status == MagickFalse)
      break;
    if (object[i].area < MagickEpsilon)
      continue;
    GetColorTuple(&object[i].color,MagickFalse,mean_color);
    (void) fprintf(stdout,
      "  %.20g: %.20gx%.20g%+.20g%+.20g %.1f,%.1f %.20g %s\n",(double)
      object[i].id,(double) object[i].bounding_box.width,(double)
      object[i].bounding_box.height,(double) object[i].bounding_box.x,
      (double) object[i].bounding_box.y,object[i].centroid.x,
      object[i].centroid.y,(double) object[i].area,mean_color);
  }
  object=(CCObject *) RelinquishMagickMemory(object);
  return(status);
}
MagickExport Image *DistortImage(Image *image,const DistortImageMethod method,
  const unsigned long number_arguments,const double *arguments,
  MagickBooleanType bestfit, ExceptionInfo *exception)
{
#define DistortImageTag  "Distort/Image"

  double
    coefficients[9],
    validity;

  Image
    *distort_image;

  register long
    i,
    x;

  long
    j,
    y;

  PointInfo
    point;          /* point to sample (center of filtered resample of area) */

  MagickPixelPacket
    pixel,          /* pixel to assign to distorted image */
    invalid;  /* the color to assign when distort result is invalid */

  register IndexPacket
    *indexes;

  register PixelPacket
    *q;

  ResampleFilter
    *resample_filter;

  ViewInfo
    *distort_view;

  MagickBooleanType
    status;

  RectangleInfo
    geometry;

  const char
     *property;

  assert(image != (Image *) NULL);
  assert(image->signature == MagickSignature);
  if (image->debug != MagickFalse)
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
  assert(exception != (ExceptionInfo *) NULL);
  assert(exception->signature == MagickSignature);
  (void) ResetMagickMemory(coefficients,0,sizeof(coefficients));

  /*
    Convert input arguments into mapping coefficents for distortion
  */
  switch (method)
  {
    case AffineDistortion:
    {
      double
        **matrix;

      PointInfo
        *points;

      /* Affine Distortion

            u =   c0*x + c2*y + c4

            v =   c1*x + c3*y + c5

         Input Arguments are pairs of distorted coodinates (minimum 3 sets)
         Which will be used to generate the coefficients of the above.
            u1,v1, x1,y1,  u2,v2, x2,y2,  u3,v3, x3,y3, ...
      */
      if (number_arguments != 12) {  /* to be removed */
        (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
                     "InvalidArgument","%s : '%s'","distort Affine",
                     "Needs 12 numbers");
        return((Image *) NULL);
      }
      if (number_arguments%4 != 0) {
        (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
                     "InvalidArgument","%s : '%s'","distort Affine",
                     "Requires pairs of coords (4 numbers U,V,X,Y)");
        return((Image *) NULL);
      }
      if (number_arguments < 12) {
        (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
                     "InvalidArgument","%s : '%s'","distort Affine",
                     "Minimum of 3 pairs of coords needed (12 numbers)");
        return((Image *) NULL);
      }
      points=(PointInfo *) AcquireQuantumMemory((number_arguments)/2UL,
        sizeof(*points));
      if (points == (PointInfo *) NULL)
        ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
      for (i=0; i < (long) number_arguments; i++)
        if ((i % 2 ) == 0)
          points[i/2].x=arguments[i];
        else
          points[i/2].y=arguments[i];
      matrix = AcquireMagickMatrix(6UL,6UL);
      if (matrix == (double **) NULL)
      {
        points=(PointInfo *) RelinquishMagickMemory(points);
        ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
      }
      status=SolveAffineDistortion(6UL,points,matrix,coefficients);
      matrix = RelinquishMagickMatrix(matrix, 6UL);
      points = (PointInfo *) RelinquishMagickMemory(points);
      if ( status == MagickFalse ) {
        (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
                     "InvalidArgument","%s : '%s'","distort Affine",
                     "Degenerate Result");
        return((Image *) NULL);
      }
      break;
    }
    case AffineProjectionDistortion:
    {
      /*
        Arguments: Affine Matrix (forward mapping)
           sx, rx, ry, sy, tx, ty
      */
      if (number_arguments != 6) {
        (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
                     "InvalidArgument","%s : '%s'","distort AffineProjection",
                     "Needs 6 numbers");
        return((Image *) NULL);
      }
      InvertAffineCoefficients(arguments, coefficients);
      break;
    }
    case BilinearDistortion:
    {
      double
        **matrix;

      PointInfo
        *points;

      /* Bilinear Distortion (reversed)

            u = c0*x + c1*y + c2*x*y + c3;

            v = c4*x + c5*y + c6*x*y + c7;

         Input Arguments are pairs of distorted coodinates (minimum 4 pairs)
         Which will be used to generate the coefficients of the above.
            u1,v1, x1,y1,  u2,v2, x2,y2,  u3,v3, x3,y3,  u4,v4, x4,y4 ...
      */
      if (number_arguments != 16) {  /* to be removed */
        (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
                     "InvalidArgument","%s : '%s'","distort Bilinear",
                     "Needs 16 numbers");
        return((Image *) NULL);
      }
      if (number_arguments%4 != 0) {
        (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
                     "InvalidArgument","%s : '%s'","distort Bilinear",
                     "Requires pairs of coords (4 numbers U,V,X,Y)");
        return((Image *) NULL);
      }
      if (number_arguments < 16) {
        (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
                     "InvalidArgument","%s : '%s'","distort Bilinear",
                     "Minimum of 4 pairs of coords needed (16 numbers)");
        return((Image *) NULL);
      }
      points=(PointInfo *) AcquireQuantumMemory((number_arguments+1UL)/2UL,
        sizeof(*points));
      if (points == (PointInfo *) NULL)
        ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
      for (i=0; i < (long) number_arguments; i++)
        if ((i % 2 ) == 0)
          points[i/2].x=arguments[i];
        else
          points[i/2].y=arguments[i];
      matrix = AcquireMagickMatrix(8UL,8UL);
      if (matrix == (double **) NULL)
      {
        points=(PointInfo *) RelinquishMagickMemory(points);
        ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
      }
      status=SolveBilinearDistortion(8UL,points,matrix,coefficients);
      matrix = RelinquishMagickMatrix(matrix, 8UL);
      points = (PointInfo *) RelinquishMagickMemory(points);
      if ( status == MagickFalse ) {
        (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
                     "InvalidArgument","%s : '%s'","distort Bilinear",
                     "Degenerate Result");
        return((Image *) NULL);
      }
      break;
    }
    case PerspectiveDistortion:
    {
      double
        **matrix;

      PointInfo
        *points;

      /* Perspective Distortion (a ratio of affine distortions)

                 p     c0*x + c1*y + c2
            u = --- = ------------------
                 r     c6*x + c7*y + 1

                 q     c3*x + c4*y + c5
            v = --- = ------------------
                 r     c6*x + c7*y + 1

            c8 = Sign of 'r', or the denominator affine, for the actual image.
                 This determines what part of the distorted image is 'ground'
                 side of the horizon, the other part is 'sky' or invalid.

         Input Arguments are pairs of distorted coodinates (minimum 4 pairs)
         Which will be used to generate the coefficients of the above.
            u1,v1, x1,y1,  u2,v2, x2,y2,  u3,v3, x3,y3,  u4,v4, x4,y4 ...
      */
      if (number_arguments != 16) {  /* to be removed */
        (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
                     "InvalidArgument","%s : '%s'","distort Bilinear",
                     "Needs 16 numbers");
        return((Image *) NULL);
      }
      if (number_arguments%4 != 0) {
        (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
                     "InvalidArgument","%s : '%s'","distort Bilinear",
                     "Requires pairs of coords (4 numbers U,V,X,Y)");
        return((Image *) NULL);
      }
      if (number_arguments < 16) {
        (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
                     "InvalidArgument","%s : '%s'","distort Bilinear",
                     "Minimum of 4 pairs of coords needed (16 numbers)");
        return((Image *) NULL);
      }
      points=(PointInfo *) AcquireQuantumMemory((number_arguments+1UL)/2UL,
        sizeof(*points));
      if (points == (PointInfo *) NULL)
        ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
      for (i=0; i < (long) number_arguments; i++)
        if ((i % 2 ) == 0)
          points[i/2].x=arguments[i];
        else
          points[i/2].y=arguments[i];
      matrix = AcquireMagickMatrix(8UL,8UL);
      if (matrix == (double **) NULL)
      {
        points=(PointInfo *) RelinquishMagickMemory(points);
        ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
      }
      status=SolvePerspectiveDistortion(8UL,points,matrix,coefficients);
      matrix = RelinquishMagickMatrix(matrix, 8UL);
      points = (PointInfo *) RelinquishMagickMemory(points);
      if ( status == MagickFalse ) {
        (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
                     "InvalidArgument","%s : '%s'","distort Prespective",
                     "Degenerate Result");
        return((Image *) NULL);
      }
      /*
        What is the 'ground' of the perspective distortion.
        Just find the sign of denomitor affine for any image coordinate.
        This is a 9'th coefficient!
      */
      coefficients[8] = coefficients[6]*arguments[number_arguments-2]
                  + coefficients[7]*arguments[number_arguments-1] + 1.0;
      coefficients[8] = (coefficients[8] < 0.0) ? -1.0 : +1.0;
      break;
    }
    case PerspectiveProjectionDistortion:
    {
      /*
        Arguments: Perspective Coefficents (forward mapping)
      */
      if (number_arguments != 8) {
        (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
                     "InvalidArgument","%s : '%s'",
                     "distort PerspectiveProjection", "Needs 8 numbers");
        return((Image *) NULL);
      }
      InvertPerspectiveCoefficients(arguments, coefficients);
      /*
        What is the 'ground' of the perspective distortion?  For a forward
        mapped perspective the images 0,0 coord will map to c2,c5  in the
        distorted image, so get the sign of denominator of that.
        This is a 9'th coefficient!
      */
      coefficients[8] = coefficients[6]*arguments[2]
                  + coefficients[7]*arguments[5] + 1.0;
      coefficients[8] = (coefficients[8] < 0.0) ? -1.0 : +1.0;
      break;
    }
    case ScaleRotateTranslateDistortion:
    {
      double
        cosine, sine,
        x,y,sx,sy,a,nx,ny;

      /*
         Argument options, by number of arguments given:
           7: x,y, sx,sy, a, nx,ny
           6: x,y,   s,   a, nx,ny
           5: x,y, sx,sy, a
           4: x,y,   s,   a
           3: x,y,        a
           2:        s,   a
           1:             a
         Where actions are (in order of application)
            x,y     'center' of transforms     (default = image center)
            sx,sy   scale image by this amount (default = 1)
            a       angle of rotation          (argument required)
            nx,ny   move 'center' here         (default = no movement)
         And convert to affine mapping coefficients
      */
      x = nx = (double)image->columns/2.0;
      y = ny = (double)image->rows/2.0;
      if ( bestfit ) {
        x = nx += (double)image->page.x;
        y = ny += (double)image->page.y;
      }
      sx = sy = 1.0;
      switch ( number_arguments ) {
      case 0:
        (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
                     "InvalidArgument","%s : '%s'",
                     "distort ScaleTranslateRotate",
                     "Needs at least 1 argument");
        return((Image *) NULL);
      case 1:
        a = arguments[0];
        break;
      case 2:
        sx = sy = arguments[0];
        a = arguments[1];
        break;
      default:
        x = nx = arguments[0];
        y = ny = arguments[1];
        switch ( number_arguments ) {
        case 3:
          a = arguments[2];
          break;
        case 4:
          sx = sy = arguments[2];
          a = arguments[3];
          break;
        case 5:
          sx = arguments[2];
          sy = arguments[3];
          a = arguments[4];
          break;
        case 6:
          sx = sy = arguments[2];
          a = arguments[3];
          nx = arguments[4];
          ny = arguments[5];
          break;
        case 7:
          sx = arguments[2];
          sy = arguments[3];
          a = arguments[4];
          nx = arguments[5];
          ny = arguments[6];
          break;
        default:
          (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
                     "InvalidArgument","%s : '%s'",
                     "distort ScaleTranslateRotate",
                     "Too Many Arguments (7 or less)");
          return((Image *) NULL);
        }
        break;
      }
      a=DegreesToRadians(a);
      cosine=cos(a);
      sine=sin(a);
      coefficients[0]=cosine/sx;
      coefficients[1]=(-sine)/sy;
      coefficients[2]=sine/sx;
      coefficients[3]=cosine/sy;
      coefficients[4]=x-nx*coefficients[0]-ny*coefficients[2];
      coefficients[5]=y-nx*coefficients[1]-ny*coefficients[3];
      break;
    }
    case ArcDistortion:
    {
      /* Arc Distortion
         Args: arc_width  rotate  top_edge_radius  bottom_edge_radius
         All but first argument are optional
            arc_width      The angle over which to arc the image side-to-side
            rotate         Angle to rotate image from vertical center
            top_radius     Set top edge of source image at this radius
            bottom_radius  Set bootom edge to this radius (radial scaling)

         By default, if the radii arguments are nor provided the image radius
         is calculated so the horizontal center-line is fits the given arc
         without scaling.

         The output image size is ALWAYS adjusted to contain the whole image,
         and an offset is given to position image relative to the 0,0 point of
         the origin, allowing users to use relative positioning onto larger
         background (via -flatten).

         The arguments are converted to these coefficents
            c0: angle for center of source image
            c1: angle scale for mapping to source image
            c2: radius for top of source image
            c3: radius scale for mapping source image
            c4: centerline of arc within source image

         Note the coefficents use a center angle, so asymptotic join is
         furthest from both sides of the source image. This also means that
         for arc angles greater than 360 the sides of the image will be
         trimmed equally.
      */
      if ( number_arguments >= 1 && arguments[0] < MagickEpsilon ) {
        (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
                     "InvalidArgument","%s : '%s'", "distort Arc",
                     "Arc Angle Too Small");
        return((Image *) NULL);
      }
      if ( number_arguments >= 3 && arguments[2] < MagickEpsilon ) {
        (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
                     "InvalidArgument","%s : '%s'", "distort Arc",
                     "Outer Radius Too Small");
        return((Image *) NULL);
      }
      coefficients[0] = -MagickPI/2.0;
      if ( number_arguments >= 1 )
        coefficients[1] = DegreesToRadians(arguments[0]);
      else
        coefficients[1] = MagickPI/2.0;
      if ( number_arguments >= 2 )
        coefficients[0] += DegreesToRadians(arguments[1]);
      coefficients[0] -= MagickRound(coefficients[0]/(2.0*MagickPI))
                             *2.0*MagickPI;
      coefficients[3] = 1.0*image->rows-1;
      coefficients[2] = 1.0*image->columns/coefficients[1] + coefficients[3]/2.0;
      if ( number_arguments >= 3 ) {
        if ( number_arguments >= 4 )
          coefficients[3] = arguments[2] - arguments[3];
        else
          coefficients[3] *= arguments[2]/coefficients[2];
        coefficients[2] = arguments[2];
      }
      coefficients[4] = (1.0*image->columns-1.0)/2.0;
      /* Always work out the 'best fit' for Arc Distort (required) */
      bestfit = MagickTrue;
      break;
    }
    default:
      break;
  }

  /*
    Determine the size and offset for a 'bestfit' destination.
    Usally the four corners of the source image is enough.
  */

  /* default output image bounds, when no 'bestfit' is requested */
  geometry.width=image->columns;
  geometry.height=image->rows;
  geometry.x=0;
  geometry.y=0;
  point.x=0.0;
  point.y=0.0;

  if ( bestfit ) {
    double
      min_x,max_x,min_y,max_y;

/* defines to figure out the bounds of the distorted image */
#define InitalBounds(px,py) \
{ \
  min_x = max_x = (px); \
  min_y = max_y = (py); \
}
#define ExpandBounds(px,py) \
{ \
  if ( (px) < min_x )  min_x = (px); \
  if ( (px) > max_x )  max_x = (px); \
  if ( (py) < min_y )  min_y = (py); \
  if ( (py) > max_y )  max_y = (py); \
}

    switch (method)
    {
      case AffineDistortion:
      case AffineProjectionDistortion:
      case ScaleRotateTranslateDistortion:
      { double inverse[6];
        InvertAffineCoefficients(coefficients, inverse);
        x = image->page.x;  y = image->page.y;
        point.x=inverse[0]*x+inverse[2]*y+inverse[4];
        point.y=inverse[1]*x+inverse[3]*y+inverse[5];
        InitalBounds( point.x, point.y );
        x = image->page.x+image->columns-1;  y = image->page.y;
        point.x=inverse[0]*x+inverse[2]*y+inverse[4];
        point.y=inverse[1]*x+inverse[3]*y+inverse[5];
        ExpandBounds( point.x, point.y );
        x = image->page.x;  y = image->page.y+image->rows-1;
        point.x=inverse[0]*x+inverse[2]*y+inverse[4];
        point.y=inverse[1]*x+inverse[3]*y+inverse[5];
        ExpandBounds( point.x, point.y );
        x = image->page.x+image->columns-1;
        y = image->page.y+image->rows-1;
        point.x=inverse[0]*x+inverse[2]*y+inverse[4];
        point.y=inverse[1]*x+inverse[3]*y+inverse[5];
        ExpandBounds( point.x, point.y );
        break;
      }
      case PerspectiveDistortion:
      case PerspectiveProjectionDistortion:
      { double inverse[8], scale;
        InvertPerspectiveCoefficients(coefficients, inverse);
        x = image->page.x;  y = image->page.y;
        scale=inverse[6]*x+inverse[7]*y+1.0;
        scale=1.0/(  (fabs(scale) <= MagickEpsilon) ? 1.0 : scale );
        point.x=scale*(inverse[0]*x+inverse[1]*y+inverse[2]);
        point.y=scale*(inverse[3]*x+inverse[4]*y+inverse[5]);
        InitalBounds( point.x, point.y );
        x = image->page.x+image->columns-1;  y = image->page.y;
        scale=inverse[6]*x+inverse[7]*y+1.0;
        scale=1.0/(  (fabs(scale) <= MagickEpsilon) ? 1.0 : scale );
        point.x=scale*(inverse[0]*x+inverse[1]*y+inverse[2]);
        point.y=scale*(inverse[3]*x+inverse[4]*y+inverse[5]);
        ExpandBounds( point.x, point.y );
        x = image->page.x;  y = image->page.y+image->rows-1;
        scale=inverse[6]*x+inverse[7]*y+1.0;
        scale=1.0/(  (fabs(scale) <= MagickEpsilon) ? 1.0 : scale );
        point.x=scale*(inverse[0]*x+inverse[1]*y+inverse[2]);
        point.y=scale*(inverse[3]*x+inverse[4]*y+inverse[5]);
        ExpandBounds( point.x, point.y );
        x = image->page.x+image->columns-1;
        y = image->page.y+image->rows-1;
        scale=inverse[6]*x+inverse[7]*y+1.0;
        scale=1.0/(  (fabs(scale) <= MagickEpsilon) ? 1.0 : scale );
        point.x=scale*(inverse[0]*x+inverse[1]*y+inverse[2]);
        point.y=scale*(inverse[3]*x+inverse[4]*y+inverse[5]);
        ExpandBounds( point.x, point.y );
        break;
      }
      case ArcDistortion:
      { double a, ca, sa;
        /* Forward Map Corners */
        a = coefficients[0]-coefficients[1]/2; ca = cos(a); sa = sin(a);
        point.x = coefficients[2]*ca;
        point.y = coefficients[2]*sa;
        InitalBounds( point.x, point.y );
        point.x = (coefficients[2]-coefficients[3])*ca;
        point.y = (coefficients[2]-coefficients[3])*sa;
        ExpandBounds( point.x, point.y );
        a = coefficients[0]+coefficients[1]/2; ca = cos(a); sa = sin(a);
        point.x = coefficients[2]*ca;
        point.y = coefficients[2]*sa;
        ExpandBounds( point.x, point.y );
        point.x = (coefficients[2]-coefficients[3])*ca;
        point.y = (coefficients[2]-coefficients[3])*sa;
        ExpandBounds( point.x, point.y );
        /* orthogonal points along top of arc */
        for( a=ceil((coefficients[0]-coefficients[1]/2.0)*2.0/MagickPI)
                              *MagickPI/2.0;
               a<(coefficients[0]+coefficients[1]/2.0); a+=MagickPI/2.0 ) {
          ca = cos(a); sa = sin(a);
          point.x = coefficients[2]*ca;
          point.y = coefficients[2]*sa;
          ExpandBounds( point.x, point.y );
        }
        /*
          Convert the angle_to_width and radius_to_height
          to appropriate scaling factors, to allow faster processing
          in the mapping function.
        */
        coefficients[1] = 2.0*MagickPI*image->columns/coefficients[1];
        coefficients[3] = 1.0*image->rows/coefficients[3];
        break;
      }
      case BilinearDistortion:
      default:
        /* no bestfit available for this distortion YET */
        bestfit = MagickFalse;
    }
    /* Set the output image geometry to the 'bestfit' of the image */
    if ( bestfit ) {
      geometry.x=(long) floor(min_x-MagickEpsilon);
      geometry.y=(long) floor(min_y-MagickEpsilon);
      geometry.width=(unsigned long) ceil(max_x-geometry.x+1+MagickEpsilon);
      geometry.height=(unsigned long) ceil(max_y-geometry.y+1+MagickEpsilon);
    }
  }

  /* User provided override of the output geometry */
  property=GetImageArtifact(image,"distort:viewport");
  if (property != (const char *) NULL)
    (void) ParseAbsoluteGeometry(property, &geometry);

  /*
    Initialize the distort image attributes.
  */
  distort_image=CloneImage(image,geometry.width,geometry.height,MagickTrue,
    exception);
  if (distort_image == (Image *) NULL)
    return((Image *) NULL);
  if (SetImageStorageClass(distort_image,DirectClass) == MagickFalse)
    {
      InheritException(exception,&distort_image->exception);
      distort_image=DestroyImage(distort_image);
      return((Image *) NULL);
    }
  distort_image->page.x=geometry.x;
  distort_image->page.y=geometry.y;
  if (distort_image->background_color.opacity != OpaqueOpacity)
    distort_image->matte=MagickTrue;

  /* Open Image views as needed. */
  resample_filter=AcquireResampleFilter(image,exception);
  GetMagickPixelPacket(distort_image,&pixel);
  distort_view=OpenCacheView(distort_image);

  /* Define constant scaling vectors for Affine Distortions */
  switch (method)
  {
    case AffineDistortion:
    case AffineProjectionDistortion:
    case ScaleRotateTranslateDistortion:
      ScaleResampleFilter( resample_filter,
        coefficients[0], coefficients[2],
        coefficients[1], coefficients[3] );
      break;
    default:
      break;
  }

  /* Initialize default pixel validity
   *    negative:         pixel is invalid  output 'matte_color'
   *    0.0 to 1.0:       antialiased, mix with resample output
   *    1.0 or greater:   use resampled output.
   */
  validity = 1.0;
  GetMagickPixelPacket(distort_image,&invalid);
  SetMagickPixelPacket(distort_image, &distort_image->matte_color,
             (IndexPacket *) NULL, &invalid);
  if (distort_image->colorspace == CMYKColorspace)
        ConvertRGBToCMYK(&invalid);   /* what about other color spaces? */

  /* Sample the source image to each pixel in the distort image.  */
  for (j=0; j < (long) distort_image->rows; j++)
  {
    q=SetCacheView(distort_view,0,j,distort_image->columns,1);
    if (q == (PixelPacket *) NULL)
      break;
    indexes=GetCacheViewIndexes(distort_view);
    y = j+geometry.y;
    for (i=0; i < (long) distort_image->columns; i++)
    {
      x = i+geometry.x;
      switch (method)
      {
        case AffineDistortion:
        case AffineProjectionDistortion:
        case ScaleRotateTranslateDistortion:
        {
          point.x=coefficients[0]*x+coefficients[2]*y+coefficients[4];
          point.y=coefficients[1]*x+coefficients[3]*y+coefficients[5];
          /* Affine partical derivitives are constant -- set above */
          break;
        }
        case BilinearDistortion:
        {
          point.x=coefficients[0]*x+coefficients[1]*y+coefficients[2]*x*y+
            coefficients[3];
          point.y=coefficients[4]*x+coefficients[5]*y+coefficients[6]*x*y+
            coefficients[7];
          /* Bilinear partical derivitives of scaling vectors */
          ScaleResampleFilter( resample_filter,
              coefficients[0] + coefficients[2]*y,
              coefficients[1] + coefficients[2]*x,
              coefficients[4] + coefficients[6]*y,
              coefficients[5] + coefficients[6]*x );
          break;
        }
        case PerspectiveDistortion:
        case PerspectiveProjectionDistortion:
        {
          double
            p,q,r,abs_r,abs_c6,abs_c7,scale;
          /* perspective is a ratio of affines */
          p=coefficients[0]*x+coefficients[1]*y+coefficients[2];
          q=coefficients[3]*x+coefficients[4]*y+coefficients[5];
          r=coefficients[6]*x+coefficients[7]*y+1.0;
          /* Pixel Validity -- is it a 'sky' or 'ground' pixel */
          validity = (r*coefficients[8] < 0.0) ? 0.0 : 1.0;
          /* Determine horizon anti-aliase blending */
          abs_r = fabs(r)*2;
          abs_c6 = fabs(coefficients[6]);
          abs_c7 = fabs(coefficients[7]);
          if ( abs_c6 > abs_c7 ) {
            if ( abs_r < abs_c6 )
              validity = 0.5 - coefficients[8]*r/coefficients[6];
          }
          else if ( abs_r < abs_c7 )
            validity = .5 - coefficients[8]*r/coefficients[7];
          /* Perspective Sampling Point (if valid) */
          if ( validity > 0.0 ) {
            scale = 1.0/r;
            point.x = p*scale;
            point.y = q*scale;
            /* Perspective Partial Derivatives or Scaling Vectors */
            scale *= scale;
            ScaleResampleFilter( resample_filter,
              (r*coefficients[0] - p*coefficients[6])*scale,
              (r*coefficients[1] - p*coefficients[7])*scale,
              (r*coefficients[3] - q*coefficients[6])*scale,
              (r*coefficients[4] - q*coefficients[7])*scale );
          }
          break;
        }
        case ArcDistortion:
        {
          double radius = sqrt((double) x*x+y*y);
          point.x = (atan2((double)y,(double)x) - coefficients[0])/(2*MagickPI);
          point.x -= MagickRound(point.x);
          point.x = point.x*coefficients[1] + coefficients[4];
          point.y = (coefficients[2] - radius) * coefficients[3];
          /* Polar Distortion Partial Derivatives or Scaling Vectors
             We give the deritives of  du/dr, dv/dr  and du/da, dv/da
             rather than provide the complex  du/dx,dv/dx and du/dy,dv/dy.
             The result will be the same, but it is simplier to calculate.
          */
          if ( radius > MagickEpsilon )
            ScaleResampleFilter( resample_filter,
                coefficients[1]/(2*MagickPI) / radius, 0, 0, coefficients[3] );
          else
            ScaleResampleFilter( resample_filter,
                 MagickHuge, 0, 0, coefficients[3] );
          break;
        }
        default:
        {
          /*
            Noop distortion (failsafe).
          */
          point.x=(double) i;
          point.y=(double) j;
          break;
        }
      }
      if ( bestfit && method != ArcDistortion ) {
        point.x -= image->page.x;
        point.y -= image->page.y;
      }

      if ( validity <= 0.0 ) {
        /* result of distortion is an invalid pixel - don't resample */
        SetPixelPacket(distort_image,&invalid,q,indexes);
      }
      else {
        /* resample the source image to find its correct color */
        pixel=ResamplePixelColor(resample_filter,point.x,point.y);
        /* if validity between 0.0 and 1.0 mix result with invalid pixel */
        if ( validity < 1.0 ) {
          /* Do a blend of sample color and invalid pixel */
          /* should this be a 'Blend', or an 'Over' compose */
          MagickPixelCompositeBlend(&pixel, validity,
               &invalid, (1.0-validity), &pixel);
        }
        SetPixelPacket(distort_image,&pixel,q,indexes);
      }
      q++;
      indexes++;
    }
    if (SyncImagePixels(distort_image) == MagickFalse)
      break;
    if ((image->progress_monitor != (MagickProgressMonitor) NULL) &&
        (QuantumTick(y,image->rows) != MagickFalse))
      {
        status=image->progress_monitor(DistortImageTag,y,image->rows,
          image->client_data);
        if (status == MagickFalse)
          break;
      }
  }
  distort_view=CloseCacheView(distort_view);
  resample_filter=DestroyResampleFilter(resample_filter);

  /* Arc does not return an offset unless 'bestfit' is in effect */
  if ( method == ArcDistortion && !bestfit &&
       property==(const char *)NULL ) {
    distort_image->page.x = 0;
    distort_image->page.y = 0;
  }
  return(distort_image);
}
Exemple #22
0
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
+   G e t I m a g e B o u n d i n g B o x                                     %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  GetImageBoundingBox() returns the bounding box of an image canvas.
%
%  The format of the GetImageBoundingBox method is:
%
%      RectangleInfo GetImageBoundingBox(const Image *image,
%        ExceptionInfo *exception)
%
%  A description of each parameter follows:
%
%    o bounds: Method GetImageBoundingBox returns the bounding box of an
%      image canvas.
%
%    o image: the image.
%
%    o exception: return any errors or warnings in this structure.
%
*/
MagickExport RectangleInfo GetImageBoundingBox(const Image *image,
  ExceptionInfo *exception)
{
  CacheView
    *image_view;

  long
    y;

  MagickBooleanType
    status;

  MagickPixelPacket
    target[3],
    zero;

  RectangleInfo
    bounds;

  register const PixelPacket
    *p;

  assert(image != (Image *) NULL);
  assert(image->signature == MagickSignature);
  if (image->debug != MagickFalse)
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
  bounds.width=0;
  bounds.height=0;
  bounds.x=(long) image->columns;
  bounds.y=(long) image->rows;
  GetMagickPixelPacket(image,&target[0]);
  image_view=AcquireCacheView(image);
  p=GetCacheViewVirtualPixels(image_view,0,0,1,1,exception);
  if (p == (const PixelPacket *) NULL)
    {
      image_view=DestroyCacheView(image_view);
      return(bounds);
    }
  SetMagickPixelPacket(image,p,GetCacheViewAuthenticIndexQueue(image_view),
    &target[0]);
  GetMagickPixelPacket(image,&target[1]);
  p=GetCacheViewVirtualPixels(image_view,(long) image->columns-1,0,1,1,
    exception);
  SetMagickPixelPacket(image,p,GetCacheViewAuthenticIndexQueue(image_view),
    &target[1]);
  GetMagickPixelPacket(image,&target[2]);
  p=GetCacheViewVirtualPixels(image_view,0,(long) image->rows-1,1,1,exception);
  SetMagickPixelPacket(image,p,GetCacheViewAuthenticIndexQueue(image_view),
    &target[2]);
  status=MagickTrue;
  GetMagickPixelPacket(image,&zero);
#if defined(MAGICKCORE_OPENMP_SUPPORT)
  #pragma omp parallel for schedule(dynamic,4) shared(status)
#endif
  for (y=0; y < (long) image->rows; y++)
  {
    MagickPixelPacket
      pixel;

    RectangleInfo
      bounding_box;

    register const IndexPacket
      *restrict indexes;

    register const PixelPacket
      *restrict p;

    register long
      x;

    if (status == MagickFalse)
      continue;
#if defined(MAGICKCORE_OPENMP_SUPPORT)
#  pragma omp critical (MagickCore_GetImageBoundingBox)
#endif
    bounding_box=bounds;
    p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
    if (p == (const PixelPacket *) NULL)
      {
        status=MagickFalse;
        continue;
      }
    indexes=GetCacheViewVirtualIndexQueue(image_view);
    pixel=zero;
    for (x=0; x < (long) image->columns; x++)
    {
      SetMagickPixelPacket(image,p,indexes+x,&pixel);
      if ((x < bounding_box.x) &&
          (IsMagickColorSimilar(&pixel,&target[0]) == MagickFalse))
        bounding_box.x=x;
      if ((x > (long) bounding_box.width) &&
          (IsMagickColorSimilar(&pixel,&target[1]) == MagickFalse))
        bounding_box.width=(unsigned long) x;
      if ((y < bounding_box.y) &&
          (IsMagickColorSimilar(&pixel,&target[0]) == MagickFalse))
        bounding_box.y=y;
      if ((y > (long) bounding_box.height) &&
          (IsMagickColorSimilar(&pixel,&target[2]) == MagickFalse))
        bounding_box.height=(unsigned long) y;
      p++;
    }
#if defined(MAGICKCORE_OPENMP_SUPPORT)
#  pragma omp critical (MagickCore_GetImageBoundingBox)
#endif
    {
      if (bounding_box.x < bounds.x)
        bounds.x=bounding_box.x;
      if (bounding_box.y < bounds.y)
        bounds.y=bounding_box.y;
      if (bounding_box.width > bounds.width)
        bounds.width=bounding_box.width;
      if (bounding_box.height > bounds.height)
        bounds.height=bounding_box.height;
    }
  }
  image_view=DestroyCacheView(image_view);
  if ((bounds.width == 0) || (bounds.height == 0))
    (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning,
      "GeometryDoesNotContainImage","`%s'",image->filename);
  else
    {
      bounds.width-=(bounds.x-1);
      bounds.height-=(bounds.y-1);
    }
  return(bounds);
}
Exemple #23
0
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   F l o o d f i l l P a i n t I m a g e                                     %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  FloodfillPaintImage() changes the color value of any pixel that matches
%  target and is an immediate neighbor.  If the method FillToBorderMethod is
%  specified, the color value is changed for any neighbor pixel that does not
%  match the bordercolor member of image.
%
%  By default target must match a particular pixel color exactly.
%  However, in many cases two colors may differ by a small amount.  The
%  fuzz member of image defines how much tolerance is acceptable to
%  consider two colors as the same.  For example, set fuzz to 10 and the
%  color red at intensities of 100 and 102 respectively are now
%  interpreted as the same color for the purposes of the floodfill.
%
%  The format of the FloodfillPaintImage method is:
%
%      MagickBooleanType FloodfillPaintImage(Image *image,
%        const ChannelType channel,const DrawInfo *draw_info,
%        const MagickPixelPacket target,const ssize_t x_offset,
%        const ssize_t y_offset,const MagickBooleanType invert)
%
%  A description of each parameter follows:
%
%    o image: the image.
%
%    o channel: the channel(s).
%
%    o draw_info: the draw info.
%
%    o target: the RGB value of the target color.
%
%    o x_offset,y_offset: the starting location of the operation.
%
%    o invert: paint any pixel that does not match the target color.
%
*/
MagickExport MagickBooleanType FloodfillPaintImage(Image *image,
  const ChannelType channel,const DrawInfo *draw_info,
  const MagickPixelPacket *target,const ssize_t x_offset,const ssize_t y_offset,
  const MagickBooleanType invert)
{
#define MaxStacksize  (1UL << 15)
#define PushSegmentStack(up,left,right,delta) \
{ \
  if (s >= (segment_stack+MaxStacksize)) \
    ThrowBinaryException(DrawError,"SegmentStackOverflow",image->filename) \
  else \
    { \
      if ((((up)+(delta)) >= 0) && (((up)+(delta)) < (ssize_t) image->rows)) \
        { \
          s->x1=(double) (left); \
          s->y1=(double) (up); \
          s->x2=(double) (right); \
          s->y2=(double) (delta); \
          s++; \
        } \
    } \
}

  CacheView
    *floodplane_view,
    *image_view;

  ExceptionInfo
    *exception;

  Image
    *floodplane_image;

  MagickBooleanType
    skip;

  MagickPixelPacket
    fill,
    pixel;

  PixelPacket
    fill_color;

  register SegmentInfo
    *s;

  SegmentInfo
    *segment_stack;

  ssize_t
    offset,
    start,
    x,
    x1,
    x2,
    y;

  /*
    Check boundary conditions.
  */
  assert(image != (Image *) NULL);
  assert(image->signature == MagickSignature);
  if (image->debug != MagickFalse)
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
  assert(draw_info != (DrawInfo *) NULL);
  assert(draw_info->signature == MagickSignature);
  if ((x_offset < 0) || (x_offset >= (ssize_t) image->columns))
    return(MagickFalse);
  if ((y_offset < 0) || (y_offset >= (ssize_t) image->rows))
    return(MagickFalse);
  if (SetImageStorageClass(image,DirectClass) == MagickFalse)
    return(MagickFalse);
  if (IsGrayColorspace(image->colorspace) != MagickFalse)
    (void) TransformImageColorspace(image,sRGBColorspace);
  if ((image->matte == MagickFalse) &&
      (draw_info->fill.opacity != OpaqueOpacity))
    (void) SetImageAlphaChannel(image,OpaqueAlphaChannel);
  /*
    Set floodfill state.
  */
  floodplane_image=CloneImage(image,0,0,MagickTrue,&image->exception);
  if (floodplane_image == (Image *) NULL)
    return(MagickFalse);
  (void) SetImageAlphaChannel(floodplane_image,OpaqueAlphaChannel);
  segment_stack=(SegmentInfo *) AcquireQuantumMemory(MaxStacksize,
    sizeof(*segment_stack));
  if (segment_stack == (SegmentInfo *) NULL)
    {
      floodplane_image=DestroyImage(floodplane_image);
      ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
        image->filename);
    }
  /*
    Push initial segment on stack.
  */
  exception=(&image->exception);
  x=x_offset;
  y=y_offset;
  start=0;
  s=segment_stack;
  PushSegmentStack(y,x,x,1);
  PushSegmentStack(y+1,x,x,-1);
  GetMagickPixelPacket(image,&fill);
  GetMagickPixelPacket(image,&pixel);
  image_view=AcquireVirtualCacheView(image,exception);
  floodplane_view=AcquireAuthenticCacheView(floodplane_image,exception);
  while (s > segment_stack)
  {
    register const IndexPacket
      *restrict indexes;

    register const PixelPacket
      *restrict p;

    register ssize_t
      x;

    register PixelPacket
      *restrict q;

    /*
      Pop segment off stack.
    */
    s--;
    x1=(ssize_t) s->x1;
    x2=(ssize_t) s->x2;
    offset=(ssize_t) s->y2;
    y=(ssize_t) s->y1+offset;
    /*
      Recolor neighboring pixels.
    */
    p=GetCacheViewVirtualPixels(image_view,0,y,(size_t) (x1+1),1,exception);
    q=GetCacheViewAuthenticPixels(floodplane_view,0,y,(size_t) (x1+1),1,
      exception);
    if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
      break;
    indexes=GetCacheViewVirtualIndexQueue(image_view);
    p+=x1;
    q+=x1;
    for (x=x1; x >= 0; x--)
    {
      if (q->opacity == (Quantum) TransparentOpacity)
        break;
      SetMagickPixelPacket(image,p,indexes+x,&pixel);
      if (IsMagickColorSimilar(&pixel,target) == invert)
        break;
      q->opacity=(Quantum) TransparentOpacity;
      p--;
      q--;
    }
    if (SyncCacheViewAuthenticPixels(floodplane_view,exception) == MagickFalse)
      break;
    skip=x >= x1 ? MagickTrue : MagickFalse;
    if (skip == MagickFalse)
      {
        start=x+1;
        if (start < x1)
          PushSegmentStack(y,start,x1-1,-offset);
        x=x1+1;
      }
    do
    {
      if (skip == MagickFalse)
        {
          if (x < (ssize_t) image->columns)
            {
              p=GetCacheViewVirtualPixels(image_view,x,y,image->columns-x,1,
                exception);
              q=GetCacheViewAuthenticPixels(floodplane_view,x,y,
                image->columns-x,1,exception);
              if ((p == (const PixelPacket *) NULL) ||
                  (q == (PixelPacket *) NULL))
                break;
              indexes=GetCacheViewVirtualIndexQueue(image_view);
              for ( ; x < (ssize_t) image->columns; x++)
              {
                if (q->opacity == (Quantum) TransparentOpacity)
                  break;
                SetMagickPixelPacket(image,p,indexes+x,&pixel);
                if (IsMagickColorSimilar(&pixel,target) == invert)
                  break;
                q->opacity=(Quantum) TransparentOpacity;
                p++;
                q++;
              }
              if (SyncCacheViewAuthenticPixels(floodplane_view,exception) == MagickFalse)
                break;
            }
          PushSegmentStack(y,start,x-1,offset);
          if (x > (x2+1))
            PushSegmentStack(y,x2+1,x-1,-offset);
        }
      skip=MagickFalse;
      x++;
      if (x <= x2)
        {
          p=GetCacheViewVirtualPixels(image_view,x,y,(size_t) (x2-x+1),1,
            exception);
          q=GetCacheViewAuthenticPixels(floodplane_view,x,y,(size_t) (x2-x+1),1,
            exception);
          if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
            break;
          indexes=GetCacheViewVirtualIndexQueue(image_view);
          for ( ; x <= x2; x++)
          {
            if (q->opacity == (Quantum) TransparentOpacity)
              break;
            SetMagickPixelPacket(image,p,indexes+x,&pixel);
            if (IsMagickColorSimilar(&pixel,target) != invert)
              break;
            p++;
            q++;
          }
        }
      start=x;
    } while (x <= x2);
  }
  for (y=0; y < (ssize_t) image->rows; y++)
  {
    register const PixelPacket
      *restrict p;

    register IndexPacket
      *restrict indexes;

    register ssize_t
      x;

    register PixelPacket
      *restrict q;

    /*
      Tile fill color onto floodplane.
    */
    p=GetCacheViewVirtualPixels(floodplane_view,0,y,image->columns,1,
      exception);
    q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
    if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
      break;
    indexes=GetCacheViewAuthenticIndexQueue(image_view);
    for (x=0; x < (ssize_t) image->columns; x++)
    {
      if (GetPixelOpacity(p) != OpaqueOpacity)
        {
          (void) GetFillColor(draw_info,x,y,&fill_color);
          SetMagickPixelPacket(image,&fill_color,(IndexPacket *) NULL,&fill);
          if (image->colorspace == CMYKColorspace)
            ConvertRGBToCMYK(&fill);
          if ((channel & RedChannel) != 0)
            SetPixelRed(q,ClampToQuantum(fill.red));
          if ((channel & GreenChannel) != 0)
            SetPixelGreen(q,ClampToQuantum(fill.green));
          if ((channel & BlueChannel) != 0)
            SetPixelBlue(q,ClampToQuantum(fill.blue));
          if ((channel & OpacityChannel) != 0)
            SetPixelOpacity(q,ClampToQuantum(fill.opacity));
          if (((channel & IndexChannel) != 0) &&
              (image->colorspace == CMYKColorspace))
            SetPixelIndex(indexes+x,ClampToQuantum(fill.index));
        }
      p++;
      q++;
    }
    if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
      break;
  }
  floodplane_view=DestroyCacheView(floodplane_view);
  image_view=DestroyCacheView(image_view);
  segment_stack=(SegmentInfo *) RelinquishMagickMemory(segment_stack);
  floodplane_image=DestroyImage(floodplane_image);
  return(y == (ssize_t) image->rows ? MagickTrue : MagickFalse);
}
Exemple #24
0
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   W r i t e T X T I m a g e                                                 %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  WriteTXTImage writes the pixel values as text numbers.
%
%  The format of the WriteTXTImage method is:
%
%      MagickBooleanType WriteTXTImage(const ImageInfo *image_info,Image *image)
%
%  A description of each parameter follows.
%
%    o image_info: the image info.
%
%    o image:  The image.
%
*/
static MagickBooleanType WriteTXTImage(const ImageInfo *image_info,Image *image)
{
  char
    buffer[MaxTextExtent],
    colorspace[MaxTextExtent],
    tuple[MaxTextExtent];

  MagickBooleanType
    status;

  MagickOffsetType
    scene;

  MagickPixelPacket
    pixel;

  register const IndexPacket
    *indexes;

  register const PixelPacket
    *p;

  register ssize_t
    x;

  ssize_t
    y;

  /*
    Open output image file.
  */
  assert(image_info != (const ImageInfo *) NULL);
  assert(image_info->signature == MagickSignature);
  assert(image != (Image *) NULL);
  assert(image->signature == MagickSignature);
  if (image->debug != MagickFalse)
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
  status=OpenBlob(image_info,image,WriteBlobMode,&image->exception);
  if (status == MagickFalse)
    return(status);
  scene=0;
  do
  {
    ComplianceType
      compliance;

    (void) CopyMagickString(colorspace,CommandOptionToMnemonic(
      MagickColorspaceOptions,(ssize_t) image->colorspace),MaxTextExtent);
    LocaleLower(colorspace);
    image->depth=GetImageQuantumDepth(image,MagickTrue);
    if (image->matte != MagickFalse)
      (void) ConcatenateMagickString(colorspace,"a",MaxTextExtent);
    compliance=NoCompliance;
    if (LocaleCompare(image_info->magick,"SPARSE-COLOR") != 0)
      {
        (void) FormatLocaleString(buffer,MaxTextExtent,
          "# ImageMagick pixel enumeration: %.20g,%.20g,%.20g,%s\n",(double)
          image->columns,(double) image->rows,(double) ((MagickOffsetType)
          GetQuantumRange(image->depth)),colorspace);
        (void) WriteBlobString(image,buffer);
        compliance=SVGCompliance;
      }
    GetMagickPixelPacket(image,&pixel);
    for (y=0; y < (ssize_t) image->rows; y++)
    {
      p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
      if (p == (const PixelPacket *) NULL)
        break;
      indexes=GetVirtualIndexQueue(image);
      for (x=0; x < (ssize_t) image->columns; x++)
      {
        SetMagickPixelPacket(image,p,indexes+x,&pixel);
        if (pixel.colorspace == LabColorspace)
          {
            pixel.green-=(QuantumRange+1)/2.0;
            pixel.blue-=(QuantumRange+1)/2.0;
          }
        if (LocaleCompare(image_info->magick,"SPARSE-COLOR") == 0)
          {
            /*
              Sparse-color format.
            */
            if (GetPixelOpacity(p) == (Quantum) OpaqueOpacity)
              {
                GetColorTuple(&pixel,MagickFalse,tuple);
                (void) QueryMagickColorname(image,&pixel,SVGCompliance,tuple,
                  &image->exception);
                (void) FormatLocaleString(buffer,MaxTextExtent,"%.20g,%.20g,",
                  (double) x,(double) y);
                (void) WriteBlobString(image,buffer);
                (void) WriteBlobString(image,tuple);
                (void) WriteBlobString(image," ");
              }
            p++;
            continue;
          }
        (void) FormatLocaleString(buffer,MaxTextExtent,"%.20g,%.20g: ",(double)
          x,(double) y);
        (void) WriteBlobString(image,buffer);
        (void) CopyMagickString(tuple,"(",MaxTextExtent);
        ConcatenateColorComponent(&pixel,RedChannel,compliance,tuple);
        (void) ConcatenateMagickString(tuple,",",MaxTextExtent);
        ConcatenateColorComponent(&pixel,GreenChannel,compliance,tuple);
        (void) ConcatenateMagickString(tuple,",",MaxTextExtent);
        ConcatenateColorComponent(&pixel,BlueChannel,compliance,tuple);
        if (pixel.colorspace == CMYKColorspace)
          {
            (void) ConcatenateMagickString(tuple,",",MaxTextExtent);
            ConcatenateColorComponent(&pixel,IndexChannel,compliance,tuple);
          }
        if (pixel.matte != MagickFalse)
          {
            (void) ConcatenateMagickString(tuple,",",MaxTextExtent);
            ConcatenateColorComponent(&pixel,AlphaChannel,compliance,tuple);
          }
        (void) ConcatenateMagickString(tuple,")",MaxTextExtent);
        (void) WriteBlobString(image,tuple);
        (void) WriteBlobString(image,"  ");
        GetColorTuple(&pixel,MagickTrue,tuple);
        (void) FormatLocaleString(buffer,MaxTextExtent,"%s",tuple);
        (void) WriteBlobString(image,buffer);
        (void) WriteBlobString(image,"  ");
        (void) QueryMagickColorname(image,&pixel,SVGCompliance,tuple,
          &image->exception);
        (void) WriteBlobString(image,tuple);
        (void) WriteBlobString(image,"\n");
        p++;
      }
      status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
        image->rows);
      if (status == MagickFalse)
        break;
    }
    if (GetNextImageInList(image) == (Image *) NULL)
      break;
    image=SyncNextImageInList(image);
    status=SetImageProgress(image,SaveImagesTag,scene++,
      GetImageListLength(image));
    if (status == MagickFalse)
      break;
  } while (image_info->adjoin != MagickFalse);
  (void) CloseBlob(image);
  return(MagickTrue);
}
Exemple #25
0
MagickExport MagickBooleanType GradientImage(Image *image,
  const GradientType type,const SpreadMethod method,
  const PixelPacket *start_color,const PixelPacket *stop_color)
{
  DrawInfo
    *draw_info;

  GradientInfo
    *gradient;

  MagickBooleanType
    status;

  register ssize_t
    i;

  /*
    Set gradient start-stop end points.
  */
  assert(image != (const Image *) NULL);
  assert(image->signature == MagickSignature);
  if (image->debug != MagickFalse)
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
  assert(start_color != (const PixelPacket *) NULL);
  assert(stop_color != (const PixelPacket *) NULL);
  draw_info=AcquireDrawInfo();
  gradient=(&draw_info->gradient);
  gradient->type=type;
  gradient->bounding_box.width=image->columns;
  gradient->bounding_box.height=image->rows;
  gradient->gradient_vector.x2=(double) image->columns-1.0;
  gradient->gradient_vector.y2=(double) image->rows-1.0;
  if ((type == LinearGradient) && (gradient->gradient_vector.y2 != 0.0))
    gradient->gradient_vector.x2=0.0;
  gradient->center.x=(double) gradient->gradient_vector.x2/2.0;
  gradient->center.y=(double) gradient->gradient_vector.y2/2.0;
  gradient->radius=MagickMax(gradient->center.x,gradient->center.y);
  gradient->spread=method;
  /*
    Define the gradient to fill between the stops.
  */
  gradient->number_stops=2;
  gradient->stops=(StopInfo *) AcquireQuantumMemory(gradient->number_stops,
    sizeof(*gradient->stops));
  if (gradient->stops == (StopInfo *) NULL)
    ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
      image->filename);
  (void) ResetMagickMemory(gradient->stops,0,gradient->number_stops*
    sizeof(*gradient->stops));
  for (i=0; i < (ssize_t) gradient->number_stops; i++)
    GetMagickPixelPacket(image,&gradient->stops[i].color);
  SetMagickPixelPacket(image,start_color,(IndexPacket *) NULL,
    &gradient->stops[0].color);
  gradient->stops[0].offset=0.0;
  SetMagickPixelPacket(image,stop_color,(IndexPacket *) NULL,
    &gradient->stops[1].color);
  gradient->stops[1].offset=1.0;
  /*
    Draw a gradient on the image.
  */
  status=DrawGradientImage(image,draw_info);
  draw_info=DestroyDrawInfo(draw_info);
  if ((start_color->opacity == OpaqueOpacity) &&
      (stop_color->opacity == OpaqueOpacity))
    image->matte=MagickFalse;
  if ((IsGrayPixel(start_color) != MagickFalse) &&
      (IsGrayPixel(stop_color) != MagickFalse))
    image->type=GrayscaleType;
  return(status);
}
Exemple #26
0
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   W r i t e X P M I m a g e                                                 %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  WriteXPMImage() writes an image to a file in the X pixmap format.
%
%  The format of the WriteXPMImage method is:
%
%      MagickBooleanType WriteXPMImage(const ImageInfo *image_info,Image *image)
%
%  A description of each parameter follows.
%
%    o image_info: the image info.
%
%    o image:  The image.
%
*/
static MagickBooleanType WriteXPMImage(const ImageInfo *image_info,Image *image)
{
#define MaxCixels  92

  static const char
    Cixel[MaxCixels+1] = " .XoO+@#$%&*=-;:>,<1234567890qwertyuipasdfghjk"
                         "lzxcvbnmMNBVCZASDFGHJKLPIUYTREWQ!~^/()_`'][{}|";

  char
    buffer[MaxTextExtent],
    basename[MaxTextExtent],
    name[MaxTextExtent],
    symbol[MaxTextExtent];

  ExceptionInfo
    *exception;

  MagickBooleanType
    status;

  MagickPixelPacket
    pixel;

  register const IndexPacket
    *indexes;

  register const PixelPacket
    *p;

  register ssize_t
    i,
    x;

  size_t
    characters_per_pixel;

  ssize_t
    j,
    k,
    opacity,
    y;

  /*
    Open output image file.
  */
  assert(image_info != (const ImageInfo *) NULL);
  assert(image_info->signature == MagickSignature);
  assert(image != (Image *) NULL);
  assert(image->signature == MagickSignature);
  if (image->debug != MagickFalse)
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
  exception=(&image->exception);
  status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
  if (status == MagickFalse)
    return(status);
  if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
    (void) TransformImageColorspace(image,sRGBColorspace);
  opacity=(-1);
  if (image->matte == MagickFalse)
    {
      if ((image->storage_class == DirectClass) || (image->colors > 256))
        (void) SetImageType(image,PaletteType);
    }
  else
    {
      MagickRealType
        alpha,
        beta;

      /*
        Identify transparent colormap index.
      */
      if ((image->storage_class == DirectClass) || (image->colors > 256))
        (void) SetImageType(image,PaletteBilevelMatteType);
      for (i=0; i < (ssize_t) image->colors; i++)
        if (image->colormap[i].opacity != OpaqueOpacity)
          {
            if (opacity < 0)
              {
                opacity=i;
                continue;
              }
            alpha=(Quantum) TransparentOpacity-(MagickRealType)
              image->colormap[i].opacity;
            beta=(Quantum) TransparentOpacity-(MagickRealType)
              image->colormap[opacity].opacity;
            if (alpha < beta)
              opacity=i;
          }
      if (opacity == -1)
        {
          (void) SetImageType(image,PaletteBilevelMatteType);
          for (i=0; i < (ssize_t) image->colors; i++)
            if (image->colormap[i].opacity != OpaqueOpacity)
              {
                if (opacity < 0)
                  {
                    opacity=i;
                    continue;
                  }
                alpha=(Quantum) TransparentOpacity-(MagickRealType)
                  image->colormap[i].opacity;
                beta=(Quantum) TransparentOpacity-(MagickRealType)
                  image->colormap[opacity].opacity;
                if (alpha < beta)
                  opacity=i;
              }
        }
      if (opacity >= 0)
        {
          image->colormap[opacity].red=image->transparent_color.red;
          image->colormap[opacity].green=image->transparent_color.green;
          image->colormap[opacity].blue=image->transparent_color.blue;
        }
    }
  /*
    Compute the character per pixel.
  */
  characters_per_pixel=1;
  for (k=MaxCixels; (ssize_t) image->colors > k; k*=MaxCixels)
    characters_per_pixel++;
  /*
    XPM header.
  */
  (void) WriteBlobString(image,"/* XPM */\n");
  GetPathComponent(image->filename,BasePath,basename);
  if (isalnum((int) ((unsigned char) *basename)) == 0)
    {
      (void) FormatLocaleString(buffer,MaxTextExtent,"xpm_%s",basename);
      (void) CopyMagickString(basename,buffer,MaxTextExtent);
    }
  if (isalpha((int) ((unsigned char) basename[0])) == 0)
    basename[0]='_';
  for (i=1; basename[i] != '\0'; i++)
    if (isalnum((int) ((unsigned char) basename[i])) == 0)
      basename[i]='_';
  (void) FormatLocaleString(buffer,MaxTextExtent,
    "static char *%s[] = {\n",basename);
  (void) WriteBlobString(image,buffer);
  (void) WriteBlobString(image,"/* columns rows colors chars-per-pixel */\n");
  (void) FormatLocaleString(buffer,MaxTextExtent,
    "\"%.20g %.20g %.20g %.20g \",\n",(double) image->columns,(double)
    image->rows,(double) image->colors,(double) characters_per_pixel);
  (void) WriteBlobString(image,buffer);
  GetMagickPixelPacket(image,&pixel);
  for (i=0; i < (ssize_t) image->colors; i++)
  {
    /*
      Define XPM color.
    */
    SetMagickPixelPacket(image,image->colormap+i,(IndexPacket *) NULL,&pixel);
    pixel.colorspace=sRGBColorspace;
    pixel.depth=8;
    pixel.opacity=(MagickRealType) OpaqueOpacity;
    (void) QueryMagickColorname(image,&pixel,XPMCompliance,name,exception);
    if (i == opacity)
      (void) CopyMagickString(name,"None",MaxTextExtent);
    /*
      Write XPM color.
    */
    k=i % MaxCixels;
    symbol[0]=Cixel[k];
    for (j=1; j < (ssize_t) characters_per_pixel; j++)
    {
      k=((i-k)/MaxCixels) % MaxCixels;
      symbol[j]=Cixel[k];
    }
    symbol[j]='\0';
    (void) FormatLocaleString(buffer,MaxTextExtent,"\"%s c %s\",\n",symbol,
      name);
    (void) WriteBlobString(image,buffer);
  }
  /*
    Define XPM pixels.
  */
  (void) WriteBlobString(image,"/* pixels */\n");
  for (y=0; y < (ssize_t) image->rows; y++)
  {
    p=GetVirtualPixels(image,0,y,image->columns,1,exception);
    if (p == (const PixelPacket *) NULL)
      break;
    indexes=GetVirtualIndexQueue(image);
    (void) WriteBlobString(image,"\"");
    for (x=0; x < (ssize_t) image->columns; x++)
    {
      k=((ssize_t) GetPixelIndex(indexes+x) % MaxCixels);
      symbol[0]=Cixel[k];
      for (j=1; j < (ssize_t) characters_per_pixel; j++)
      {
        k=(((int) GetPixelIndex(indexes+x)-k)/MaxCixels) % MaxCixels;
        symbol[j]=Cixel[k];
      }
      symbol[j]='\0';
      (void) CopyMagickString(buffer,symbol,MaxTextExtent);
      (void) WriteBlobString(image,buffer);
    }
    (void) FormatLocaleString(buffer,MaxTextExtent,"\"%s\n",
      (y == (ssize_t) (image->rows-1) ? "" : ","));
    (void) WriteBlobString(image,buffer);
    if (image->previous == (Image *) NULL)
      {
        status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
          image->rows);
        if (status == MagickFalse)
          break;
      }
  }
  (void) WriteBlobString(image,"};\n");
  (void) CloseBlob(image);
  return(MagickTrue);
}
Exemple #27
0
MagickExport MagickBooleanType OpaquePaintImageChannel(Image *image,
  const ChannelType channel,const MagickPixelPacket *target,
  const MagickPixelPacket *fill,const MagickBooleanType invert)
{
#define OpaquePaintImageTag  "Opaque/Image"

  CacheView
    *image_view;

  ExceptionInfo
    *exception;

  MagickBooleanType
    status;

  MagickOffsetType
    progress;

  MagickPixelPacket
    zero;

  ssize_t
    y;

  assert(image != (Image *) NULL);
  assert(image->signature == MagickSignature);
  assert(target != (MagickPixelPacket *) NULL);
  assert(fill != (MagickPixelPacket *) NULL);
  if (image->debug != MagickFalse)
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
  if (SetImageStorageClass(image,DirectClass) == MagickFalse)
    return(MagickFalse);
  if ((IsGrayColorspace(image->colorspace) != MagickFalse) &&
      (IsMagickGray(fill) != MagickFalse))
    (void) TransformImageColorspace(image,sRGBColorspace);
  if ((fill->opacity != OpaqueOpacity) && (image->matte == MagickFalse))
    (void) SetImageAlphaChannel(image,OpaqueAlphaChannel);
  /*
    Make image color opaque.
  */
  status=MagickTrue;
  progress=0;
  exception=(&image->exception);
  GetMagickPixelPacket(image,&zero);
  image_view=AcquireAuthenticCacheView(image,exception);
#if defined(MAGICKCORE_OPENMP_SUPPORT)
  #pragma omp parallel for schedule(static,4) shared(progress,status) \
    IsConcurrentDos(image->columns,image->rows,64)
#endif
  for (y=0; y < (ssize_t) image->rows; y++)
  {
    MagickPixelPacket
      pixel;

    register IndexPacket
      *restrict indexes;

    register ssize_t
      x;

    register PixelPacket
      *restrict q;

    if (status == MagickFalse)
      continue;
    q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
    if (q == (PixelPacket *) NULL)
      {
        status=MagickFalse;
        continue;
      }
    indexes=GetCacheViewAuthenticIndexQueue(image_view);
    pixel=zero;
    for (x=0; x < (ssize_t) image->columns; x++)
    {
      SetMagickPixelPacket(image,q,indexes+x,&pixel);
      if (IsMagickColorSimilar(&pixel,target) != invert)
        {
          if ((channel & RedChannel) != 0)
            SetPixelRed(q,ClampToQuantum(fill->red));
          if ((channel & GreenChannel) != 0)
            SetPixelGreen(q,ClampToQuantum(fill->green));
          if ((channel & BlueChannel) != 0)
            SetPixelBlue(q,ClampToQuantum(fill->blue));
          if ((channel & OpacityChannel) != 0)
            SetPixelOpacity(q,ClampToQuantum(fill->opacity));
          if (((channel & IndexChannel) != 0) &&
              (image->colorspace == CMYKColorspace))
            SetPixelIndex(indexes+x,ClampToQuantum(fill->index));
        }
      q++;
    }
    if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
      status=MagickFalse;
    if (image->progress_monitor != (MagickProgressMonitor) NULL)
      {
        MagickBooleanType
          proceed;

#if defined(MAGICKCORE_OPENMP_SUPPORT)
        #pragma omp critical (MagickCore_OpaquePaintImageChannel)
#endif
        proceed=SetImageProgress(image,OpaquePaintImageTag,progress++,
          image->rows);
        if (proceed == MagickFalse)
          status=MagickFalse;
      }
  }
  image_view=DestroyCacheView(image_view);
  return(status);
}
Exemple #28
0
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   S e t I m a g e A l p h a C h a n n e l                                   %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  SetImageAlphaChannel() activates, deactivates, resets, or sets the alpha
%  channel.
%
%  The format of the SetImageAlphaChannel method is:
%
%      MagickBooleanType SetImageAlphaChannel(Image *image,
%        const AlphaChannelType alpha_type)
%
%  A description of each parameter follows:
%
%    o image: the image.
%
%    o alpha_type:  The alpha channel type: ActivateAlphaChannel,
%      CopyAlphaChannel, DeactivateAlphaChannel, ExtractAlphaChannel,
%      OpaqueAlphaChannel, ResetAlphaChannel, SetAlphaChannel,
%      ShapeAlphaChannel, and TransparentAlphaChannel.
%
*/
MagickExport MagickBooleanType SetImageAlphaChannel(Image *image,
  const AlphaChannelType alpha_type)
{
  MagickBooleanType
    status;

  assert(image != (Image *) NULL);
  if (image->debug != MagickFalse)
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
  assert(image->signature == MagickSignature);
  status=MagickTrue;
  switch (alpha_type)
  {
    case ActivateAlphaChannel:
    {
      image->matte=MagickTrue;
      break;
    }
    case BackgroundAlphaChannel:
    {
      CacheView
        *image_view;

      ExceptionInfo
        *exception;

      IndexPacket
        index;

      MagickBooleanType
        status;

      MagickPixelPacket
        background;

      PixelPacket
        pixel;

      ssize_t
        y;

      /*
        Set transparent pixels to background color.
      */
      if (image->matte == MagickFalse)
        break;
      if (SetImageStorageClass(image,DirectClass) == MagickFalse)
        break;
      GetMagickPixelPacket(image,&background);
      SetMagickPixelPacket(image,&image->background_color,(const IndexPacket *)
        NULL,&background);
      if (image->colorspace == CMYKColorspace)
        ConvertRGBToCMYK(&background);
      index=0;
      SetPixelPacket(image,&background,&pixel,&index);
      status=MagickTrue;
      exception=(&image->exception);
      image_view=AcquireAuthenticCacheView(image,exception);
      #if defined(MAGICKCORE_OPENMP_SUPPORT)
        #pragma omp parallel for schedule(static,4) shared(status) \
          magick_threads(image,image,image->rows,1)
      #endif
      for (y=0; y < (ssize_t) image->rows; y++)
      {
        register IndexPacket
          *restrict indexes;

        register PixelPacket
          *restrict q;

        register ssize_t
          x;

        if (status == MagickFalse)
          continue;
        q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
          exception);
        if (q == (PixelPacket *) NULL)
          {
            status=MagickFalse;
            continue;
          }
        for (x=0; x < (ssize_t) image->columns; x++)
        {
          if (q->opacity == TransparentOpacity)
            {
              SetPixelRed(q,pixel.red);
              SetPixelGreen(q,pixel.green);
              SetPixelBlue(q,pixel.blue);
            }
          q++;
        }
        if (image->colorspace == CMYKColorspace)
          {
            indexes=GetCacheViewAuthenticIndexQueue(image_view);
            for (x=0; x < (ssize_t) image->columns; x++)
              SetPixelIndex(indexes+x,index);
          }
        if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
          status=MagickFalse;
      }
      image_view=DestroyCacheView(image_view);
      return(status);
    }
    case CopyAlphaChannel:
    case ShapeAlphaChannel:
    {
      /*
        Special usage case for SeparateImageChannel(): copy grayscale color to
        the alpha channel.
      */
      status=SeparateImageChannel(image,GrayChannels);
      image->matte=MagickTrue; /* make sure transparency is now on! */
      if (alpha_type == ShapeAlphaChannel)
        {
          MagickPixelPacket
            background;

          /*
            Reset all color channels to background color.
          */
          GetMagickPixelPacket(image,&background);
          SetMagickPixelPacket(image,&(image->background_color),(IndexPacket *)
            NULL,&background);
          (void) LevelColorsImage(image,&background,&background,MagickTrue);
        }
      break;
    }
    case DeactivateAlphaChannel:
    {
      image->matte=MagickFalse;
      break;
    }
    case ExtractAlphaChannel:
    {
      status=SeparateImageChannel(image,TrueAlphaChannel);
      image->matte=MagickFalse;
      break;
    }
    case RemoveAlphaChannel:
    case FlattenAlphaChannel:
    {
      CacheView
        *image_view;

      ExceptionInfo
        *exception;

      IndexPacket
        index;

      MagickBooleanType
        status;

      MagickPixelPacket
        background;

      PixelPacket
        pixel;

      ssize_t
        y;

      /*
        Flatten image pixels over the background pixels.
      */
      if (image->matte == MagickFalse)
        break;
      if (SetImageStorageClass(image,DirectClass) == MagickFalse)
        break;
      GetMagickPixelPacket(image,&background);
      SetMagickPixelPacket(image,&image->background_color,(const IndexPacket *)
        NULL,&background);
      if (image->colorspace == CMYKColorspace)
        ConvertRGBToCMYK(&background);
      index=0;
      SetPixelPacket(image,&background,&pixel,&index);
      status=MagickTrue;
      exception=(&image->exception);
      image_view=AcquireAuthenticCacheView(image,exception);
      #if defined(MAGICKCORE_OPENMP_SUPPORT)
        #pragma omp parallel for schedule(static,4) shared(status) \
          magick_threads(image,image,image->rows,1)
      #endif
      for (y=0; y < (ssize_t) image->rows; y++)
      {
        register IndexPacket
          *restrict indexes;

        register PixelPacket
          *restrict q;

        register ssize_t
          x;

        if (status == MagickFalse)
          continue;
        q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
          exception);
        if (q == (PixelPacket *) NULL)
          {
            status=MagickFalse;
            continue;
          }
        for (x=0; x < (ssize_t) image->columns; x++)
        {
          double
            gamma,
            opacity;

          gamma=1.0-QuantumScale*QuantumScale*q->opacity*pixel.opacity;
          opacity=(double) QuantumRange*(1.0-gamma);
          gamma=PerceptibleReciprocal(gamma);
          q->red=ClampToQuantum(gamma*MagickOver_((MagickRealType) q->red,
            (MagickRealType) q->opacity,(MagickRealType) pixel.red,
            (MagickRealType) pixel.opacity));
          q->green=ClampToQuantum(gamma*MagickOver_((MagickRealType) q->green,
            (MagickRealType) q->opacity,(MagickRealType) pixel.green,
            (MagickRealType) pixel.opacity));
          q->blue=ClampToQuantum(gamma*MagickOver_((MagickRealType) q->blue,
            (MagickRealType) q->opacity,(MagickRealType) pixel.blue,
            (MagickRealType) pixel.opacity));
          q->opacity=ClampToQuantum(opacity);
          q++;
        }
        if (image->colorspace == CMYKColorspace)
          {
            indexes=GetCacheViewAuthenticIndexQueue(image_view);
            for (x=0; x < (ssize_t) image->columns; x++)
              SetPixelIndex(indexes+x,index);
          }
        if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
          status=MagickFalse;
      }
      image_view=DestroyCacheView(image_view);
      return(status);
    }
    case ResetAlphaChannel: /* deprecated */
    case OpaqueAlphaChannel:
    {
      status=SetImageOpacity(image,OpaqueOpacity);
      break;
    }
    case SetAlphaChannel:
    {
      if (image->matte == MagickFalse)
        status=SetImageOpacity(image,OpaqueOpacity);
      break;
    }
    case TransparentAlphaChannel:
    {
      status=SetImageOpacity(image,TransparentOpacity);
      break;
    }
    case UndefinedAlphaChannel:
      break;
  }
  if (status == MagickFalse)
    return(status);
  return(SyncImagePixelCache(image,&image->exception));
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   P a i n t F l o o d f i l l I m a g e                                     %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  PaintFloodfill() changes the color value of any pixel that matches
%  target and is an immediate neighbor.  If the method FillToBorderMethod is
%  specified, the color value is changed for any neighbor pixel that does not
%  match the bordercolor member of image.
%
%  By default target must match a particular pixel color exactly.
%  However, in many cases two colors may differ by a small amount.  The
%  fuzz member of image defines how much tolerance is acceptable to
%  consider two colors as the same.  For example, set fuzz to 10 and the
%  color red at intensities of 100 and 102 respectively are now
%  interpreted as the same color for the purposes of the floodfill.
%
%  The format of the PaintFloodfillImage method is:
%
%      MagickBooleanType PaintFloodfillImage(Image *image,
%        const ChannelType channel,const MagickPixelPacket target,
%        const long x_offset,const long y_offset,const DrawInfo *draw_info,
%        const PaintMethod method)
%
%  A description of each parameter follows:
%
%    o image: The image.
%
%    o channel: The channel(s).
%
%    o target: The RGB value of the target color.
%
%    o x_offset,y_offset: The starting location of the operation.
%
%    o draw_info: The draw info.
%
%    o method: Choose either FloodfillMethod or FillToBorderMethod.
%
*/
MagickExport MagickBooleanType PaintFloodfillImage(Image *image,
  const ChannelType channel,const MagickPixelPacket *target,
  const long x_offset,const long y_offset,const DrawInfo *draw_info,
  const PaintMethod method)
{
#define MaxStacksize  (1UL << 15)
#define PushSegmentStack(up,left,right,delta) \
{ \
  if (s >= (segment_stack+MaxStacksize)) \
    ThrowBinaryException(DrawError,"SegmentStackOverflow",image->filename) \
  else \
    { \
      if ((((up)+(delta)) >= 0) && (((up)+(delta)) < (long) image->rows)) \
        { \
          s->x1=(double) (left); \
          s->y1=(double) (up); \
          s->x2=(double) (right); \
          s->y2=(double) (delta); \
          s++; \
        } \
    } \
}

  Image
    *floodplane_image;

  long
    offset,
    start,
    x1,
    x2,
    y;

  MagickBooleanType
    skip;

  MagickPixelPacket
    fill,
    pixel;

  PixelPacket
    fill_color;

  register const PixelPacket
    *p;

  register IndexPacket
    *indexes;

  register long
    x;

  register PixelPacket
    *q;

  register SegmentInfo
    *s;

  SegmentInfo
    *segment_stack;

  /*
    Check boundary conditions.
  */
  assert(image != (Image *) NULL);
  assert(image->signature == MagickSignature);
  if (image->debug != MagickFalse)
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
  assert(draw_info != (DrawInfo *) NULL);
  assert(draw_info->signature == MagickSignature);
  if ((x_offset < 0) || (x_offset >= (long) image->columns))
    return(MagickFalse);
  if ((y_offset < 0) || (y_offset >= (long) image->rows))
    return(MagickFalse);
  if (SetImageStorageClass(image,DirectClass) == MagickFalse)
    return(MagickFalse);
  if (image->matte == MagickFalse)
    (void) SetImageOpacity(image,OpaqueOpacity);
  /*
    Set floodfill state.
  */
  floodplane_image=CloneImage(image,image->columns,image->rows,MagickTrue,
    &image->exception);
  if (floodplane_image == (Image *) NULL)
    return(MagickFalse);
  (void) SetImageOpacity(floodplane_image,OpaqueOpacity);
  segment_stack=(SegmentInfo *) AcquireQuantumMemory(MaxStacksize,
    sizeof(*segment_stack));
  if (segment_stack == (SegmentInfo *) NULL)
    {
      floodplane_image=DestroyImage(floodplane_image);
      ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
        image->filename);
    }
  /*
    Push initial segment on stack.
  */
  x=x_offset;
  y=y_offset;
  start=0;
  s=segment_stack;
  PushSegmentStack(y,x,x,1);
  PushSegmentStack(y+1,x,x,-1);
  GetMagickPixelPacket(image,&fill);
  GetMagickPixelPacket(image,&pixel);
  while (s > segment_stack)
  {
    /*
      Pop segment off stack.
    */
    s--;
    x1=(long) s->x1;
    x2=(long) s->x2;
    offset=(long) s->y2;
    y=(long) s->y1+offset;
    /*
      Recolor neighboring pixels.
    */
    p=AcquireImagePixels(image,0,y,(unsigned long) (x1+1),1,&image->exception);
    q=GetImagePixels(floodplane_image,0,y,(unsigned long) (x1+1),1);
    if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
      break;
    indexes=GetIndexes(image);
    p+=x1;
    q+=x1;
    for (x=x1; x >= 0; x--)
    {
      if (q->opacity == (Quantum) TransparentOpacity)
        break;
      SetMagickPixelPacket(image,p,indexes+x,&pixel);
      if (method == FloodfillMethod)
        {
          if (IsMagickColorSimilar(&pixel,target) == MagickFalse)
            break;
        }
      else
        if (IsMagickColorSimilar(&pixel,target) != MagickFalse)
          break;
      q->opacity=(Quantum) TransparentOpacity;
      p--;
      q--;
    }
    if (SyncImagePixels(floodplane_image) == MagickFalse)
      break;
    skip=x >= x1 ? MagickTrue : MagickFalse;
    if (skip == MagickFalse)
      {
        start=x+1;
        if (start < x1)
          PushSegmentStack(y,start,x1-1,-offset);
        x=x1+1;
      }
    do
    {
      if (skip == MagickFalse)
        {
          if (x < (long) image->columns)
            {
              p=AcquireImagePixels(image,x,y,image->columns-x,1,
                &image->exception);
              q=GetImagePixels(floodplane_image,x,y,image->columns-x,1);
              if ((p == (const PixelPacket *) NULL) ||
                  (q == (PixelPacket *) NULL))
                break;
              indexes=GetIndexes(image);
              for ( ; x < (long) image->columns; x++)
              {
                if (q->opacity == (Quantum) TransparentOpacity)
                  break;
                SetMagickPixelPacket(image,p,indexes+x,&pixel);
                if (method == FloodfillMethod)
                  {
                    if (IsMagickColorSimilar(&pixel,target) == MagickFalse)
                      break;
                  }
                else
                  if (IsMagickColorSimilar(&pixel,target) != MagickFalse)
                    break;
                q->opacity=(Quantum) TransparentOpacity;
                p++;
                q++;
              }
              if (SyncImagePixels(floodplane_image) == MagickFalse)
                break;
            }
          PushSegmentStack(y,start,x-1,offset);
          if (x > (x2+1))
            PushSegmentStack(y,x2+1,x-1,-offset);
        }
      skip=MagickFalse;
      x++;
      if (x <= x2)
        {
          p=AcquireImagePixels(image,x,y,(unsigned long) (x2-x+1),1,
            &image->exception);
          q=GetImagePixels(floodplane_image,x,y,(unsigned long) (x2-x+1),1);
          if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
            break;
          indexes=GetIndexes(image);
          for ( ; x <= x2; x++)
          {
            if (q->opacity == (Quantum) TransparentOpacity)
              break;
            SetMagickPixelPacket(image,p,indexes+x,&pixel);
            if (method == FloodfillMethod)
              {
                if (IsMagickColorSimilar(&pixel,target) != MagickFalse)
                  break;
              }
            else
              if (IsMagickColorSimilar(&pixel,target) == MagickFalse)
                break;
            p++;
            q++;
          }
        }
      start=x;
    } while (x <= x2);
  }
  for (y=0; y < (long) image->rows; y++)
  {
    /*
      Tile fill color onto floodplane.
    */
    p=AcquireImagePixels(floodplane_image,0,y,image->columns,1,
      &image->exception);
    q=GetImagePixels(image,0,y,image->columns,1);
    if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
      break;
    indexes=GetIndexes(image);
    for (x=0; x < (long) image->columns; x++)
    {
      if (p->opacity != OpaqueOpacity)
        {
          fill_color=GetFillColor(draw_info,x,y);
          SetMagickPixelPacket(image,&fill_color,(IndexPacket *) NULL,&fill);
          if (image->colorspace == CMYKColorspace)
            ConvertRGBToCMYK(&fill);
          if ((channel & RedChannel) != 0)
            q->red=RoundToQuantum(fill.red);
          if ((channel & GreenChannel) != 0)
            q->green=RoundToQuantum(fill.green);
          if ((channel & BlueChannel) != 0)
            q->blue=RoundToQuantum(fill.blue);
          if ((channel & OpacityChannel) != 0)
            q->opacity=RoundToQuantum(fill.opacity);
          if (((channel & IndexChannel) != 0) &&
              (image->colorspace == CMYKColorspace))
            indexes[x]=RoundToQuantum(fill.index);
        }
      p++;
      q++;
    }
    if (SyncImagePixels(image) == MagickFalse)
      break;
  }
  segment_stack=(SegmentInfo *) RelinquishMagickMemory(segment_stack);
  floodplane_image=DestroyImage(floodplane_image);
  return(y == (long) image->rows ? MagickTrue : MagickFalse);
}