Esempio n. 1
0
File: txt.c Progetto: airhuman/cwf
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   R e a d T X T I m a g e                                                   %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  Method ReadTXTImage reads a text file and returns it as an image.  It
%  allocates the memory necessary for the new Image structure and returns a
%  pointer to the new image.
%
%  The format of the ReadTXTImage method is:
%
%      Image *ReadTXTImage(const ImageInfo *image_info,ExceptionInfo *exception)
%
%  A description of each parameter follows:
%
%    o image:  Method ReadTXTImage returns a pointer to the image after
%      reading. A null image is returned if there is a memory shortage or if
%      the image cannot be read.
%
%    o image_info: Specifies a pointer to a ImageInfo structure.
%
%    o exception: return any errors or warnings in this structure.
%
%
*/
static Image *ReadTXTImage(const ImageInfo *image_info,ExceptionInfo *exception)
{
  char
    filename[MaxTextExtent],
    geometry[MaxTextExtent],
    *p,
    text[MaxTextExtent];

  double
    dx_resolution,
    dy_resolution;

  DrawInfo
    *draw_info;

  Image
    *image,
    *texture;

  long
    count,
    offset;

  RectangleInfo
    page;

  TypeMetric
    metrics;

  unsigned int
    status;
  int logging;

  /*
    Open image file.
  */
  assert(image_info != (const ImageInfo *) NULL);
  assert(image_info->signature == MagickSignature);
  assert(exception != (ExceptionInfo *) NULL);
  assert(exception->signature == MagickSignature);

  logging = LogMagickEvent(CoderEvent,GetMagickModule(),"enter"); 
  image=AllocateImage(image_info);
  status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
  if (status == False)
    ThrowReaderException(FileOpenError,UnableToOpenFile,image);

  p = ReadBlobString(image,text);
  status = IsTXT((unsigned char *)p,strlen(p));
  if (logging) (void)LogMagickEvent(CoderEvent,GetMagickModule(),
				    "File type: %d", status);

  if(status)
    {
      unsigned x,y;
      unsigned x_min,x_max,y_curr;
      int ch;
      unsigned long max,i;
      char NumOfPlanes;
      unsigned char *BImgBuff;
      magick_uint16_t *WImgBuff;
      magick_uint32_t *DImgBuff;
      magick_uint32_t R,G,B,A;
      const PixelPacket *q;
      ImportPixelAreaOptions import_options;

      (void) SeekBlob(image,0,SEEK_SET);    

      A=0;
      x=0;
      y=0;
      max=0;

      switch(status)
	{
	case TXT_GM8B_HEX:
	case TXT_GM8B_HEX_Q:  max=255; break;
	case TXT_GM16B_HEX:
	case TXT_GM16B_HEX_Q: max=65535; break;	
	case TXT_GM32B_HEX:	
	case TXT_GM32B_HEX_Q: max=65536; break;
	}

      if(!strncmp(p,"# ImageMagick pixel enumeration:",32))
	{
	  if(sscanf(p+32,"%u,%u,%u",&x_min,&y_curr,&x_max)==3)
	    {
	      if(strstr(p+32,",rgb")!=NULL)
		{
		  x = x_min-1;
		  y = y_curr-1;
		  max = x_max;
		}
	      if(strstr(p+32,",rgba")!=NULL)
		{
		  status = IMAGEMAGICK_TXT_Q;
		}
	    }
	}

      ch=0;
      if(x==0 && y==0) while(!EOFBlob(image))	/* auto detect sizes and num of planes */
	{
	  while(!(ch>='0' && ch<='9'))
	    {             /* go to the begin of number */
	      ch = ReadBlobByte(image);
	      if(ch==EOF) goto EndReading;
	      if(ch=='#') 
		{readln(image,&ch); continue;}
	      if(ch==0 || ch>128 || (ch>='a' && ch<='z') || (ch>='A' && ch<='Z'))
		{
		TXT_FAIL:			/* not a text data */
		  ThrowReaderException(CoderError,ImageTypeNotSupported,image);
		}
	    }
	  /* x,y: (R,G,B) */
	  i = ReadInt(image,&ch);		/* x */
	  if(i>x) x=i;

	  while(ch!=',')
	    {  
	      ch = ReadBlobByte(image);
	      if(ch==EOF) break;
	      if(ch==10 || ch==13) goto TXT_FAIL;
	    }
	  ch=0;
	  i=ReadInt(image,&ch);		/* y */
	  if(i>y) y=i;

	  while(ch!=':')
	    {
	      ch = ReadBlobByte(image);
	      if(ch==10 || ch==13) goto TXT_FAIL;
	      if(ch==EOF) break;
	    }
	  if(status!=TXT_GM8B_PLAIN2_Q)
	    while(ch!='(')
	      {
		ch = ReadBlobByte(image);
		if(ch==10 || ch==13) goto TXT_FAIL;
		if(ch==EOF) break;
	      }
	  ch=0;
	  R = ReadInt(image,&ch);		/* R */
	  if(R>max) max=R;

	  while(ch!=',')
	    { 
	      ch = ReadBlobByte(image);
	      if(ch==10 || ch==13) goto TXT_FAIL;
	      if(ch==EOF) break;
	    }
	  ch=0;
	  G = ReadInt(image,&ch);		/* G */
	  if(G>max) max=G;

	  while(ch!=',')
	    {
	      ch = ReadBlobByte(image);
	      if(ch==10 || ch==13) goto TXT_FAIL;
	      if(ch==EOF) break;
	    }
	  ch=0;
	  B = ReadInt(image,&ch);		/* B */
	  if(B>max) max=B;

	  if(status>16)
	    {
	      while(ch!=',')
		{
		  ch = ReadBlobByte(image);
		  if(ch==10 || ch==13) goto TXT_FAIL;
		  if(ch==EOF) break;
		}
	      ch=0;
	      A = ReadInt(image,&ch);		/* A */
	      if(A>max) max=A;
	    }

	  if(status!=TXT_GM8B_PLAIN2_Q)
	    while(ch!=')')
	      {
		ch = ReadBlobByte(image);
		if(ch==10 || ch==13) goto TXT_FAIL;
		if(ch==EOF) break;
	      }

	  readln(image,&ch);
	}

    EndReading:
      x_min = 1; x_max = 0;
      y_curr = 0;

      NumOfPlanes=8;
      /*   if(max>=    2) i=2; */
      /*   if(max>=    4) i=4; */
      /*   if(max>=   16) i=8; */
      if(max>=  256) NumOfPlanes=16;
      if(max>=65536) NumOfPlanes=32;

      if (logging) (void)LogMagickEvent(CoderEvent,GetMagickModule(),
					"Image detected [%u * %u]: %d", x, y, NumOfPlanes);

      image->depth = Min(QuantumDepth,NumOfPlanes);
      ImportPixelAreaOptionsInit(&import_options);
      import_options.endian = NativeEndian;
  
      BImgBuff = MagickAllocateMemory(unsigned char *,
				      (size_t)(x+1) * ( ((status>16)?4:3) * NumOfPlanes/8));  
      WImgBuff = (magick_uint16_t *)BImgBuff;
      DImgBuff = (magick_uint32_t *)BImgBuff;  
      if(BImgBuff==NULL) 
	ThrowReaderException(ResourceLimitError,MemoryAllocationFailed,image);
  
      image->columns = x+1;
      image->rows = y+1;

      (void) SeekBlob(image,0,SEEK_SET);

      while(!EOFBlob(image)) 	/* load picture data */
	{
	  x=0;
	  while(!(ch >= '0' && ch <= '9'))
	    {		/* move to the beginning of number */
	      if(EOFBlob(image)) goto FINISH;
	      ch = ReadBlobByte(image);
	      if(ch=='#') 
		{readln(image,&ch); continue;}
	    }
    
	  x = ReadInt(image,&ch);		/* x */

	  while(ch!=',')
	    {
	      ch = ReadBlobByte(image);       
	      if(ch==EOF) break;
	    }
	  ch = 0;
	  y = ReadInt(image,&ch);		/* y */

	  while(ch!=':')
	    {
	      ch = ReadBlobByte(image);
	      if(ch==EOF) break;
	    }
	  while(ch!='(')
	    {
	      ch = ReadBlobByte(image);
	      if(ch==EOF) break;
	    }
	  ch=0;
	  R = ReadInt(image,&ch);		/* R */

	  while(ch!=',')
	    {
	      ch = ReadBlobByte(image);
	      if(ch==EOF) break;
	    }
	  ch=0;
	  G = ReadInt(image,&ch);		/* G */

	  while(ch!=',')
	    {
	      ch = ReadBlobByte(image);
	      if(ch==EOF) break;
	    }
	  ch=0;
	  B = ReadInt(image,&ch);		/* B */

	  if(status>16)
	    {
	      while(ch!=',')
		{
		  ch = ReadBlobByte(image);       
		  if(ch==EOF) break;
		}
	      ch=0;
	      A = ReadInt(image,&ch);		/* A */
	      if(A>max) max=A;
	    }

	  while(ch!=')')
	    {
	      ch = ReadBlobByte(image);
	      if(ch==EOF) break;
	    }


	  /* a new line has been detected */
	  if(y!=y_curr)
	    {
	      q = SetImagePixels(image,x_min,y_curr,x_max-x_min+1,1);
	      if (q == (PixelPacket *)NULL) break;	
	      if(status>16)
		(void)ImportImagePixelArea(image,RGBAQuantum,NumOfPlanes,
					   BImgBuff + 4*x_min*(NumOfPlanes/8),&import_options,0);
	      else
		(void)ImportImagePixelArea(image,RGBQuantum,NumOfPlanes,
					   BImgBuff + 3*x_min*(NumOfPlanes/8),&import_options,0);
	      if (!SyncImagePixels(image)) break;

	      x_min = 1; x_max = 0;
	      y_curr=y;
	    }

	  if(x<image->columns)
	    {
	      if(status>16)
		{
		  switch(NumOfPlanes)
		    {
		    case 8: BImgBuff[0+4*x] = R;
		      BImgBuff[1+4*x] = G;
		      BImgBuff[2+4*x] = B;
		      BImgBuff[3+4*x] = A;
		      break;
		    case 16:WImgBuff[0+4*x] = R;
		      WImgBuff[1+4*x] = G;
		      WImgBuff[2+4*x] = B;
		      WImgBuff[3+4*x] = A;
		      break;
		    case 32:DImgBuff[0+4*x] = R;
		      DImgBuff[1+4*x] = G;
		      DImgBuff[2+4*x] = B;
		      DImgBuff[3+4*x] = A;
		      break;
		    }    
		}
	      else
		{
		  switch(NumOfPlanes)
		    {
		    case 8: BImgBuff[0+3*x] = R;
		      BImgBuff[1+3*x] = G;
		      BImgBuff[2+3*x] = B;
		      break;
		    case 16:WImgBuff[0+3*x] = R;
		      WImgBuff[1+3*x] = G;
		      WImgBuff[2+3*x] = B;
		      break;
		    case 32:DImgBuff[0+3*x] = R;
		      DImgBuff[1+3*x] = G;
		      DImgBuff[2+3*x] = B;
		      break;
		    }    
		}
	      if(x_min>x_max) 
		x_max=x_min=x;
	      else
		{
		  if(x<x_min) x_min=x;
		  if(x>x_max) x_max=x;
		}
	    }

	  readln(image,&ch);
	}

    FINISH:
      if(x_min<=x_max)
	{
	  q = SetImagePixels(image,x_min,y_curr,x_max-x_min+1,1);	  
	  if (q != (PixelPacket *)NULL)
	    {
	      if(status>16)        
		(void)ImportImagePixelArea(image, RGBAQuantum, NumOfPlanes,
					   BImgBuff + 4*x_min*(NumOfPlanes/8), &import_options, 0);
	      else
		(void)ImportImagePixelArea(image, RGBQuantum, NumOfPlanes,
					   BImgBuff + 3*x_min*(NumOfPlanes/8), &import_options, 0);
	      if(!SyncImagePixels(image))
		{
		  if (logging) (void)LogMagickEvent(CoderEvent,GetMagickModule(),
						    "  TXT failed to sync image pixels for a row %u", y_curr);
		}

	    }
	}

      MagickFreeMemory(BImgBuff);
      goto TXT_FINISH;    
    }

  /*
    Set the page geometry.
  */
  dx_resolution=72.0;
  dy_resolution=72.0;
  if ((image->x_resolution == 0.0) || (image->y_resolution == 0.0))
    {
      char
        density[MaxTextExtent];

      (void) strcpy(density,PSDensityGeometry);
      count=GetMagickDimension(density,&image->x_resolution,
			       &image->y_resolution,NULL,NULL);
      if (count != 2)
        image->y_resolution=image->x_resolution;
    }
  SetGeometry(image,&page);
  page.width=612;
  page.height=792;
  (void) GetGeometry("612x792+43+43",&page.x,&page.y,&page.width,&page.height);
  if (image_info->page != (char *) NULL)
    (void) GetGeometry(image_info->page,&page.x,&page.y,&page.width,
		       &page.height);
  /*
    Initialize Image structure.
  */
  image->columns=(unsigned long)
    ceil(((page.width*image->x_resolution)/dx_resolution)-0.5);
  image->rows=(unsigned long)
    ceil(((page.height*image->y_resolution)/dy_resolution)-0.5);
  texture=(Image *) NULL;
  if (image_info->texture != (char *) NULL)
    {
      ImageInfo
        *clone_info;

      clone_info=CloneImageInfo(image_info);
      clone_info->blob=(void *) NULL;
      clone_info->length=0;
      (void) strlcpy(clone_info->filename,image_info->texture,MaxTextExtent);
      texture=ReadImage(clone_info,exception);
      DestroyImageInfo(clone_info);
    }
  /*
    Annotate the text image.
  */
  (void) SetImage(image,OpaqueOpacity);
  draw_info=CloneDrawInfo(image_info,(DrawInfo *) NULL);
  draw_info->fill=image_info->pen;
  (void) CloneString(&draw_info->text,image_info->filename);
  FormatString(geometry,"0x0%+ld%+ld",page.x,page.y);
  (void) CloneString(&draw_info->geometry,geometry);
  status=GetTypeMetrics(image,draw_info,&metrics);
  if (status == False)
    ThrowReaderException(TypeError,UnableToGetTypeMetrics,image);
  (void) strlcpy(filename,image_info->filename,MaxTextExtent);
  if (draw_info->text != '\0')
    *draw_info->text='\0';  

  for (offset=2*page.y; p != (char *) NULL; )
    {
      /*
	Annotate image with text.
      */
      (void) ConcatenateString(&draw_info->text,text);
      (void) ConcatenateString(&draw_info->text,"\\n");
      offset+=(long) (metrics.ascent-metrics.descent);
      if (image->previous == (Image *) NULL)
	if (QuantumTick(offset,image->rows))
	  if (!MagickMonitorFormatted(offset,image->rows,&image->exception,
				      LoadImageText,image->filename,
				      image->columns,image->rows))
	    break;
      p=ReadBlobString(image,text);
      if ((offset < (long) image->rows) && (p != (char *) NULL))
	continue;
      if (texture != (Image *) NULL)
	{
	  MonitorHandler
	    handler;

	  handler=SetMonitorHandler((MonitorHandler) NULL);
	  (void) TextureImage(image,texture);
	  (void) SetMonitorHandler(handler);
	}
      (void) AnnotateImage(image,draw_info);
      if (p == (char *) NULL)
	break;
      /*
	Page is full-- allocate next image structure.
      */
      *draw_info->text='\0';
      offset=2*page.y;
      AllocateNextImage(image_info,image);
      if (image->next == (Image *) NULL)
	{
	  DestroyImageList(image);
	  return((Image *) NULL);
	}
      image->next->columns=image->columns;
      image->next->rows=image->rows;
      image=SyncNextImageInList(image);
      (void) strlcpy(image->filename,filename,MaxTextExtent);
      (void) SetImage(image,OpaqueOpacity);
      if (!MagickMonitorFormatted(TellBlob(image),GetBlobSize(image),exception,
				  LoadImagesText,image->filename))
	break;
    }

  if (texture != (Image *) NULL)
    {
      MonitorHandler
        handler;

      handler=SetMonitorHandler((MonitorHandler) NULL);
      (void) TextureImage(image,texture);
      (void) SetMonitorHandler(handler);
    }
  (void) AnnotateImage(image,draw_info);
  if (texture != (Image *) NULL)
    DestroyImage(texture);
  DestroyDrawInfo(draw_info);
  while (image->previous != (Image *) NULL)
    image=image->previous;
 TXT_FINISH:
  CloseBlob(image);
  return(image);
}
Esempio n. 2
0
static Image *IntegralRotateImage(const Image *image,unsigned int rotations,
                                  ExceptionInfo *exception)
{
  char
    message[MaxTextExtent];

  Image
    *rotate_image;

  RectangleInfo
    page;

  long
    tile_width_max,
    tile_height_max;

  MagickPassFail
    status=MagickPass;

  /*
    Initialize rotated image attributes.
  */
  assert(image != (Image *) NULL);
  page=image->page;
  rotations%=4;

  {
    /*
      Clone appropriately to create rotate image.
    */
    unsigned long
      clone_columns=0,
      clone_rows=0;
    
    switch (rotations)
      {
      case 0:
	clone_columns=0;
	clone_rows=0;
	break;
      case 2:
	clone_columns=image->columns;
	clone_rows=image->rows;
	break;
      case 1:
      case 3:
	clone_columns=image->rows;
	clone_rows=image->columns;
	break;
      }
    rotate_image=CloneImage(image,clone_columns,clone_rows,True,exception);
    if (rotate_image == (Image *) NULL)
      return((Image *) NULL);
    if (rotations != 0)
      if (ModifyCache(rotate_image,exception) != MagickPass)
	{
	  DestroyImage(rotate_image);
	  return (Image *) NULL;
	}
  }

  tile_height_max=tile_width_max=2048/sizeof(PixelPacket); /* 2k x 2k = 4MB */
  if ((rotations == 1) || (rotations == 3))
    {
      /*
	Allow override of tile geometry for testing.
      */
      const char *
	value;

      if (!GetPixelCacheInCore(image) || !GetPixelCacheInCore(rotate_image))
	tile_height_max=tile_width_max=8192/sizeof(PixelPacket); /* 8k x 8k = 64MB */

      if ((value=getenv("MAGICK_ROTATE_TILE_GEOMETRY")))
	{
	  double
	    width,
	    height;
	  
	  if (GetMagickDimension(value,&width,&height,NULL,NULL) == 2)
	    {
	      tile_height_max=(unsigned long) height;
	      tile_width_max=(unsigned long) width;
	    }
	}
    }

  /*
    Integral rotate the image.
  */
  switch (rotations)
    {
    case 0:
      {
        /*
          Rotate 0 degrees (nothing more to do).
        */
	(void) strlcpy(message,"[%s] Rotate: 0 degrees...",sizeof(message));
	if (!MagickMonitorFormatted(image->rows-1,image->rows,exception,
				    message,image->filename))
	  status=MagickFail;
        break;
      }
    case 1:
      {
        /*
          Rotate 90 degrees.
        */
        magick_int64_t
          tile;

        magick_uint64_t
          total_tiles;

        long
          tile_y;

        (void) strlcpy(message,"[%s] Rotate: 90 degrees...",sizeof(message));
        total_tiles=(((image->rows/tile_height_max)+1)*
                     ((image->columns/tile_width_max)+1));        
        tile=0;

#if defined(IntegralRotateImageUseOpenMP)
#  if defined(HAVE_OPENMP)
#    pragma omp parallel for schedule(static,1) shared(status, tile)
#  endif
#endif
        for (tile_y=0; tile_y < (long) image->rows; tile_y+=tile_height_max)
          {
            long
              tile_x;

            MagickPassFail
              thread_status;

            thread_status=status;
            if (thread_status == MagickFail)
              continue;

            for (tile_x=0; tile_x < (long) image->columns; tile_x+=tile_width_max)
              {
                long
                  dest_tile_x,
                  dest_tile_y;

                long
                  tile_width,
                  tile_height;

                const PixelPacket
                  *tile_pixels;

                long
                  y;

                /*
                  Compute image region corresponding to tile.
                */
                if ((unsigned long) tile_x+tile_width_max > image->columns)
                  tile_width=(tile_width_max-(tile_x+tile_width_max-image->columns));
                else
                  tile_width=tile_width_max;
                if ((unsigned long) tile_y+tile_height_max > image->rows)
                  tile_height=(tile_height_max-(tile_y+tile_height_max-image->rows));
                else
                  tile_height=tile_height_max;
                /*
                  Acquire tile
                */
                tile_pixels=AcquireImagePixels(image,tile_x,tile_y,
                                               tile_width,tile_height,exception);
                if (tile_pixels == (const PixelPacket *) NULL)
                  {
                    thread_status=MagickFail;
                    break;
                  }
                /*
                  Compute destination tile coordinates.
                */
                dest_tile_x=rotate_image->columns-(tile_y+tile_height);
                dest_tile_y=tile_x;
                /*
                  Rotate tile
                */
                for (y=0; y < tile_width; y++)
                  {
                    register const PixelPacket
                      *p;
                    
                    register PixelPacket
                      *q;

                    register const IndexPacket
                      *indexes;
        
                    IndexPacket
                      *rotate_indexes;

                    register long
                      x;

                    q=SetImagePixelsEx(rotate_image,dest_tile_x,dest_tile_y+y,
                                       tile_height,1,exception);
                    if (q == (PixelPacket *) NULL)
                      {
                        thread_status=MagickFail;
                        break;
                      }
                    /*
                      DirectClass pixels
                    */
                    p=tile_pixels+(tile_height-1)*tile_width + y;
                    for (x=tile_height; x != 0; x--) 
                      {
                        *q = *p;
                        q++;
                        p-=tile_width;
                      }
                    /*
                      Indexes
                    */
                    indexes=AccessImmutableIndexes(image);
                    if (indexes != (IndexPacket *) NULL)
                      {
                        rotate_indexes=AccessMutableIndexes(rotate_image);
                        if (rotate_indexes != (IndexPacket *) NULL)
                          {
                            register IndexPacket
                              *iq;
                            
                            register const IndexPacket
                              *ip;

                            iq=rotate_indexes;
                            ip=indexes+(tile_height-1)*tile_width + y;
                            for (x=tile_height; x != 0; x--) 
                              {
                                *iq = *ip;
                                iq++;
                                ip -= tile_width;
                              }
                          }
                      }
                    if (!SyncImagePixelsEx(rotate_image,exception))
                      {
                        thread_status=MagickFail;
                        break;
                      }
                  }

#if defined(IntegralRotateImageUseOpenMP)
#  if defined(HAVE_OPENMP)
#    pragma omp critical (GM_IntegralRotateImage)
#  endif
#endif
                {
                  tile++;
                  if (QuantumTick(tile,total_tiles))
                    if (!MagickMonitorFormatted(tile,total_tiles,exception,
                                                message,image->filename))
                      thread_status=MagickFail;
                  
                  if (thread_status == MagickFail)
                    status=MagickFail;
                }
              }
          }
        Swap(page.width,page.height);
        Swap(page.x,page.y);
        page.x=(long) (page.width-rotate_image->columns-page.x);
        break;
      }
    case 2:
      {
        /*
          Rotate 180 degrees.
        */
        long
          y;

        unsigned long
          row_count=0;

        (void) strlcpy(message,"[%s] Rotate: 180 degrees...",sizeof(message));
#if defined(IntegralRotateImageUseOpenMP)
#  if defined(HAVE_OPENMP)
#    pragma omp parallel for schedule(static,8) shared(row_count, status)
#  endif
#endif
        for (y=0; y < (long) image->rows; y++)
          {
            register const PixelPacket
              *p;

            register PixelPacket
              *q;

            register const IndexPacket
              *indexes;
        
            IndexPacket
              *rotate_indexes;

            register long
              x;

            MagickPassFail
              thread_status;

            thread_status=status;
            if (thread_status == MagickFail)
              continue;

            p=AcquireImagePixels(image,0,y,image->columns,1,exception);
            q=SetImagePixelsEx(rotate_image,0,(long) (image->rows-y-1),
                               image->columns,1,exception);
            if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
              thread_status=MagickFail;
            if (thread_status != MagickFail)
              {
                q+=image->columns;
                indexes=AccessImmutableIndexes(image);
                rotate_indexes=AccessMutableIndexes(rotate_image);
                if ((indexes != (IndexPacket *) NULL) &&
                    (rotate_indexes != (IndexPacket *) NULL))
                  for (x=0; x < (long) image->columns; x++)
                    rotate_indexes[image->columns-x-1]=indexes[x];
                for (x=0; x < (long) image->columns; x++)
                  *--q=(*p++);
                if (!SyncImagePixelsEx(rotate_image,exception))
                  thread_status=MagickFail;
              }
#if defined(IntegralRotateImageUseOpenMP)
#  if defined(HAVE_OPENMP)
#    pragma omp critical (GM_IntegralRotateImage)
#  endif
#endif
            {
              row_count++;
              if (QuantumTick(row_count,image->rows))
                if (!MagickMonitorFormatted(row_count,image->rows,exception,
                                            message,image->filename))
                  thread_status=MagickFail;
                  
              if (thread_status == MagickFail)
                status=MagickFail;
            }
          }
        page.x=(long) (page.width-rotate_image->columns-page.x);
        page.y=(long) (page.height-rotate_image->rows-page.y);
        break;
      }
    case 3:
      {
        /*
          Rotate 270 degrees.
        */

        magick_int64_t
          tile;

        magick_uint64_t
          total_tiles;

        long
          tile_y;

        (void) strlcpy(message,"[%s] Rotate: 270 degrees...",sizeof(message));
        total_tiles=(((image->rows/tile_height_max)+1)*
                     ((image->columns/tile_width_max)+1));
        tile=0;
#if defined(IntegralRotateImageUseOpenMP)
#  if defined(HAVE_OPENMP)
#    pragma omp parallel for schedule(static,1) shared(status, tile)
#  endif
#endif
        for (tile_y=0; tile_y < (long) image->rows; tile_y+=tile_height_max)
          {
            long
              tile_x;

            MagickPassFail
              thread_status;

            thread_status=status;
            if (thread_status == MagickFail)
              continue;

            for (tile_x=0; tile_x < (long) image->columns; tile_x+=tile_width_max)
              {
                long
                  tile_width,
                  tile_height;

                long
                  dest_tile_x,
                  dest_tile_y;

                long
                  y;

                const PixelPacket
                  *tile_pixels;
                    
                /*
                  Compute image region corresponding to tile.
                */
                if ((unsigned long) tile_x+tile_width_max > image->columns)
                  tile_width=(tile_width_max-(tile_x+tile_width_max-image->columns));
                else
                  tile_width=tile_width_max;
                if ((unsigned long) tile_y+tile_height_max > image->rows)
                  tile_height=(tile_height_max-(tile_y+tile_height_max-image->rows));
                else
                  tile_height=tile_height_max;
                /*
                  Acquire tile
                */
                tile_pixels=AcquireImagePixels(image,tile_x,tile_y,
                                               tile_width,tile_height,exception);
                if (tile_pixels == (const PixelPacket *) NULL)
                  {
                    thread_status=MagickFail;
                    break;
                  }
                /*
                  Compute destination tile coordinates.
                */
                dest_tile_x=tile_y;
                dest_tile_y=rotate_image->rows-(tile_x+tile_width);
                /*
                  Rotate tile
                */
                for (y=0; y < tile_width; y++)
                  {
                    register const PixelPacket
                      *p;
                    
                    register PixelPacket
                      *q;

                    register const IndexPacket
                      *indexes;

                    register long
                      x;

                    IndexPacket
                      *rotate_indexes;

                    q=SetImagePixelsEx(rotate_image,dest_tile_x,dest_tile_y+y,
                                       tile_height,1,exception);
                    if (q == (PixelPacket *) NULL)
                      {
                        thread_status=MagickFail;
                        break;
                      }
                    /*
                      DirectClass pixels
                    */
                    p=tile_pixels+(tile_width-1-y);
                    for (x=tile_height; x != 0; x--)
                      {
                        *q = *p;
                        q++;
                        p += tile_width;
                      }
                    /*
                      Indexes
                    */
                    indexes=AccessImmutableIndexes(image);
                    if (indexes != (IndexPacket *) NULL)
                      {
                        rotate_indexes=AccessMutableIndexes(rotate_image);
                        if (rotate_indexes != (IndexPacket *) NULL)
                          {
                            register IndexPacket
                              *iq;
                            
                            register const IndexPacket
                              *ip;

                            iq=rotate_indexes;
                            ip=indexes+(tile_width-1-y);
                            for (x=tile_height; x != 0; x--)
                              {
                                *iq = *ip;
                                iq++;
                                ip += tile_width;
                              }
                          }
                      }
                    if (!SyncImagePixelsEx(rotate_image,exception))
                      {
                        thread_status=MagickFail;
                        break;
                      }
                  }

#if defined(IntegralRotateImageUseOpenMP)
#  if defined(HAVE_OPENMP)
#    pragma omp critical (GM_IntegralRotateImage)
#  endif
#endif
                {
                  tile++;
                  if (QuantumTick(tile,total_tiles))
                    if (!MagickMonitorFormatted(tile,total_tiles,exception,
                                                message,image->filename))
                      thread_status=MagickFail;
                }

                if (thread_status == MagickFail)
                  {
                    status=MagickFail;
                    break;
                  }
              }
          }
        Swap(page.width,page.height);
        Swap(page.x,page.y);
        page.y=(long) (page.height-rotate_image->rows-page.y);
        break;
      }
    }

  rotate_image->page=page;
  rotate_image->is_grayscale=image->is_grayscale;
  rotate_image->is_monochrome=image->is_monochrome;
  return(rotate_image);
}