bool ScImgDataLoader_GMagick::readCMYK(Image *input, RawImage *output, int width, int height) { /* Mapping: red: cyan green: magenta blue: yellow opacity: black index: alpha */ //Copied from GraphicsMagick header and modified #define GetCyanSample(p) (p.red) #define GetMagentaSample(p) (p.green) #define GetYellowSample(p) (p.blue) #define GetCMYKBlackSample(p) (p.opacity) #define GetAlphaSample(p) (p) bool hasAlpha = input->matte; if (!output->create(width, height, hasAlpha ? 5 : 4)) return false; ExceptionInfo exception; GetExceptionInfo(&exception); const PixelPacket *pixels = AcquireImagePixels(input, 0, 0, width, height, &exception); if (exception.severity != UndefinedException) CatchException(&exception); if (!pixels) { qCritical() << QObject::tr("Could not get pixel data!"); return false; } const IndexPacket *alpha = 0; if (hasAlpha) { alpha = AccessImmutableIndexes(input); if (!alpha) { qCritical() << QObject::tr("Could not get alpha channel data!"); return false; } } unsigned char *buffer = output->bits(); if (!buffer) { qCritical() << QObject::tr("Could not allocate output buffer!"); return false; } int i; for (i = 0; i < width*height; i++) { *buffer++ = ScaleQuantumToChar(GetCyanSample(pixels[i])); *buffer++ = ScaleQuantumToChar(GetMagentaSample(pixels[i])); *buffer++ = ScaleQuantumToChar(GetYellowSample(pixels[i])); *buffer++ = ScaleQuantumToChar(GetCMYKBlackSample(pixels[i])); if (hasAlpha) { *buffer++ = 255 - ScaleQuantumToChar(GetAlphaSample(alpha[i])); } } return true; }
/* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % % P i x e l I t e r a t e T r i p l e M o d i f y % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % PixelIterateTripleModify() iterates through pixel regions of three images % and invokes a user-provided callback function (of type % PixelIteratorTripleModifyCallback) for each row of pixels. The first two % images are read-only, while the third image is read-write for update. % Access of the first two images is done lock-step using the same coordinates. % This is useful to support operations such as image differencing. % % The format of the PixelIterateTripleModify method is: % % MagickPassFail PixelIterateTripleModify( % PixelIteratorTripleModifyCallback call_back, % const PixelIteratorOptions *options, % const char *description, % void *mutable_data, % const void *immutable_data, % const unsigned long columns, % const unsigned long rows, % const Image *source1_image, % const Image *source2_image, % const long source_x, % const long source_y, % Image *update_image, % const long update_x, % const long update_y, % ExceptionInfo *exception) % % A description of each parameter follows: % % o call_back: A user-provided C callback function which reads from % a region of source pixels and updates a region of destination pixels. % % o options: Pixel iterator execution options (may be NULL). % % o description: textual description of operation being performed. % % o mutable_data: User-provided mutable context data. % % o immutable_data: User-provided immutable context data. % % o columns: Width of pixel region % % o rows: Height of pixel region % % o source1_image: The address of the constant source 1 Image. % % o source2_image: The address of the constant source 2 Image. % % o source_x: The horizontal ordinate of the top left corner of the source regions. % % o source_y: The vertical ordinate of the top left corner of the source regions. % % o update_image: The address of the update Image. % % o update_x: The horizontal ordinate of the top left corner of the update region. % % o update_y: The vertical ordinate of the top left corner of the update region. % % o exception: If an error is reported, this argument is updated with the reason. % */ static MagickPassFail PixelIterateTripleImplementation(PixelIteratorTripleModifyCallback call_back, const PixelIteratorOptions *options, const char *description, void *mutable_data, const void *immutable_data, const unsigned long columns, const unsigned long rows, const Image *source1_image, const Image *source2_image, const long source_x, const long source_y, Image *update_image, const long update_x, const long update_y, ExceptionInfo *exception, MagickBool set) { MagickPassFail status = MagickPass; register long row; unsigned long row_count=0; int max_threads; max_threads=omp_get_max_threads(); (void) SetRegionThreads(max_threads,options,columns,rows); #if defined(HAVE_OPENMP) # pragma omp parallel for schedule(static,1) shared(row_count, status) #endif for (row=0; row < (long) rows; row++) { MagickBool thread_status; const PixelPacket *source1_pixels, *source2_pixels; const IndexPacket *source1_indexes, *source2_indexes; PixelPacket *update_pixels; IndexPacket *update_indexes; long source_row, update_row; thread_status=status; if (thread_status == MagickFail) continue; source_row=source_y+row; update_row=update_y+row; /* First image (read only). */ source1_pixels=AcquireImagePixels(source1_image, source_x, source_row, columns, 1, exception); if (!source1_pixels) thread_status=MagickFail; source1_indexes=AccessImmutableIndexes(source1_image); /* Second image (read only). */ source2_pixels=AcquireImagePixels(source2_image, source_x, source_row, columns, 1, exception); if (!source2_pixels) thread_status=MagickFail; source2_indexes=AccessImmutableIndexes(source2_image); /* Third image (read/write). */ if (set) update_pixels=SetImagePixelsEx(update_image, update_x, update_row, columns, 1, exception); else update_pixels=GetImagePixelsEx(update_image, update_x, update_row, columns, 1, exception); if (!update_pixels) { thread_status=MagickFail; CopyException(exception,&update_image->exception); } update_indexes=AccessMutableIndexes(update_image); if (thread_status != MagickFail) status=(call_back)(mutable_data,immutable_data, source1_image,source1_pixels,source1_indexes, source2_image,source2_pixels,source2_indexes, update_image,update_pixels,update_indexes, columns,exception); if (!SyncImagePixelsEx(update_image,exception)) thread_status=MagickFail; #if defined(HAVE_OPENMP) # pragma omp critical (GM_PixelIterateTripleImplementation) #endif { row_count++; if (QuantumTick(row_count,rows)) if (!MagickMonitorFormatted(row_count,rows,exception,description, source1_image->filename, source2_image->filename, update_image->filename)) thread_status=MagickFail; if (thread_status == MagickFail) status=MagickFail; } } omp_set_num_threads(max_threads); return (status); }
/* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % % P i x e l I t e r a t e D u a l R e a d % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % PixelIterateDualRead() iterates through pixel regions of two images and % invokes a user-provided callback function (of type % PixelIteratorDualReadCallback) for each row of pixels. This is useful to % support operations such as image comparison. % % The format of the PixelIterateDualModify method is: % % MagickPassFail PixelIterateDualRead( % PixelIteratorDualReadCallback call_back, % const PixelIteratorOptions *options, % const char *description, % void *mutable_data, % const void *immutable_data, % const unsigned long columns, % const unsigned long rows, % const Image *first_image, % const long first_x, % const long first_y, % const Image *second_image, % const long second_x, % const long second_y, % ExceptionInfo *exception); % % A description of each parameter follows: % % o call_back: A user-provided C callback function which is passed the % address of pixels from each image. % % o options: Pixel iterator execution options (may be NULL). % % o description: textual description of operation being performed. % % o mutable_data: User-provided mutable context data. % % o immutable_data: User-provided immutable context data. % % o columns: Width of pixel region % % o rows: Height of pixel region % % o first_image: The address of the first Image. % % o first_x: The horizontal ordinate of the top left corner of the first region. % % o first_y: The vertical ordinate of the top left corner of the first region. % % o second_image: The address of the second Image. % % o second_x: The horizontal ordinate of the top left corner of the second region. % % o second_y: The vertical ordinate of the top left corner of the second region. % % o exception: If an error is reported, this argument is updated with the reason. % */ MagickExport MagickPassFail PixelIterateDualRead(PixelIteratorDualReadCallback call_back, const PixelIteratorOptions *options, const char *description, void *mutable_data, const void *immutable_data, const unsigned long columns, const unsigned long rows, const Image *first_image, const long first_x, const long first_y, const Image *second_image, const long second_x, const long second_y, ExceptionInfo *exception) { MagickPassFail status = MagickPass; register long row; unsigned long row_count=0; int max_threads; max_threads=omp_get_max_threads(); (void) SetRegionThreads(max_threads,options,columns,rows); #if defined(HAVE_OPENMP) # pragma omp parallel for schedule(static,1) shared(row_count, status) #endif for (row=0; row < (long) rows; row++) { MagickBool thread_status; long first_row, second_row; const PixelPacket *first_pixels, *second_pixels; const IndexPacket *first_indexes, *second_indexes; thread_status=status; if (thread_status == MagickFail) continue; first_row=first_y+row; second_row=second_y+row; first_pixels=AcquireImagePixels(first_image, first_x, first_row, columns, 1, exception); if (!first_pixels) thread_status=MagickFail; first_indexes=AccessImmutableIndexes(first_image); second_pixels=AcquireImagePixels(second_image, second_x, second_row, columns, 1, exception); if (!second_pixels) thread_status=MagickFail; second_indexes=AccessImmutableIndexes(second_image); if (thread_status != MagickFail) thread_status=(call_back)(mutable_data,immutable_data, first_image,first_pixels,first_indexes, second_image,second_pixels,second_indexes, columns, exception); #if defined(HAVE_OPENMP) # pragma omp critical (GM_PixelIterateDualRead) #endif { row_count++; if (QuantumTick(row_count,rows)) if (!MagickMonitorFormatted(row_count,rows,exception, description,first_image->filename, second_image->filename)) thread_status=MagickFail; if (thread_status == MagickFail) status=MagickFail; } } omp_set_num_threads(max_threads); return (status); }
/* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % % P i x e l I t e r a t e M o n o R e a d % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % PixelIterateMonoRead() iterates through a region of an image and invokes a % user-provided callback function (of type PixelRowIteratorMonoReadCallback) % for a row of pixels. This is useful to support simple operations such as % statistics computation. % % The format of the PixelIterateMonoRead method is: % % MagickPassFail PixelIterateMonoRead( % PixelIteratorMonoReadCallback call_back, % const PixelIteratorOptions *options, % const char *description, % void *mutable_data, % const void *immutable_data, % const long x, % const long y, % const unsigned long columns, % const unsigned long rows, % const Image *image, % ExceptionInfo *exception) % % A description of each parameter follows: % % o call_back: A user-provided C callback function which is passed the % address of pixels from each image. % % o options: Pixel iterator execution options (may be NULL). % % o description: textual description of operation being performed. % % o mutable_data: User-provided mutable context data. % % o immutable_data: User-provided immutable context data. % % o x: The horizontal ordinate of the top left corner of the region. % % o y: The vertical ordinate of the top left corner of the region. % % o columns: Width of pixel region % % o rows: Height of pixel region % % o image: The address of the Image. % % o exception: If an error is reported, this argument is updated with the reason. % */ MagickExport MagickPassFail PixelIterateMonoRead(PixelIteratorMonoReadCallback call_back, const PixelIteratorOptions *options, const char *description, void *mutable_data, const void *immutable_data, const long x, const long y, const unsigned long columns, const unsigned long rows, const Image *image, ExceptionInfo *exception) { MagickPassFail status = MagickPass; register long row; unsigned long row_count=0; int max_threads=1; max_threads=omp_get_max_threads(); (void) SetRegionThreads(max_threads,options,columns,rows); #if defined(HAVE_OPENMP) # pragma omp parallel for schedule(static,1) shared(row_count, status) #endif for (row=y; row < (long) (y+rows); row++) { MagickPassFail thread_status; const PixelPacket *pixels; const IndexPacket *indexes; thread_status=status; if (thread_status == MagickFail) continue; pixels=AcquireImagePixels(image,x, row, columns, 1, exception); if (!pixels) thread_status=MagickFail; indexes=AccessImmutableIndexes(image); if (thread_status != MagickFail) thread_status=(call_back)(mutable_data,immutable_data,image,pixels,indexes,columns,exception); #if defined(HAVE_OPENMP) # pragma omp critical (GM_PixelIterateMonoRead) #endif { row_count++; if (QuantumTick(row_count,rows)) if (!MagickMonitorFormatted(row_count,rows,exception, description,image->filename)) thread_status=MagickFail; if (thread_status == MagickFail) status=MagickFail; } } omp_set_num_threads(max_threads); return (status); }
/* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % % W r i t e P C L I m a g e % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % Method WritePCLImage writes an image in the Page Control Language encoded % image format. % % The format of the WritePCLImage method is: % % unsigned int WritePCLImage(const ImageInfo *image_info,Image *image) % % A description of each parameter follows. % % o status: Method WritePCLImage return True if the image is written. % False is returned is there is a memory shortage or if the image file % fails to write. % % o image_info: Specifies a pointer to a ImageInfo structure. % % o image: A pointer to an Image structure. % % % */ static unsigned int WritePCLImage(const ImageInfo *image_info,Image *image) { char buffer[MaxTextExtent]; long sans, y; register const PixelPacket *p; register const IndexPacket *indexes; register long i, x; register unsigned char *q; unsigned char *pixels, *last_row_pixels, *output_row; unsigned int status; long zero_rows; unsigned long bytes_to_write, scene, density, bytes_per_line; unsigned char bits_per_pixel; ImageCharacteristics characteristics; PCL_CompressionType compression, last_row_compression; /* Open output image file. */ assert(image_info != (const ImageInfo *) NULL); assert(image_info->signature == MagickSignature); assert(image != (Image *) NULL); assert(image->signature == MagickSignature); status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception); if (status == False) ThrowWriterException(FileOpenError,UnableToOpenFile,image); (void) GetGeometry("75x75",&sans,&sans,&density,&density); if (image_info->density != (char *) NULL) (void) GetGeometry(image_info->density,&sans,&sans,&density,&density); scene = 0; output_row = (unsigned char *) NULL; last_row_pixels = (unsigned char *) NULL; do { /* Ensure that image is in an RGB space. */ (void) TransformColorspace(image,RGBColorspace); /* Analyze image to be written. */ if (!GetImageCharacteristics(image,&characteristics, (OptimizeType == image_info->type), &image->exception)) { CloseBlob(image); return MagickFail; } /* Initialize the printer */ (void) WriteBlobString(image,"\033E"); /* printer reset */ (void) WriteBlobString(image,"\033*r3F"); /* set presentation mode */ /* define columns and rows in image */ FormatString(buffer,"\033*r%lus%luT",image->columns,image->rows); (void) WriteBlobString(image,buffer); FormatString(buffer,"\033*t%luR",density); /* set resolution */ (void) WriteBlobString(image,buffer); (void) WriteBlobString(image,"\033&l0E"); /* top margin 0 */ /* Determine output type and initialize further accordingly */ if (image->storage_class == DirectClass) { /* Full color */ bits_per_pixel=24; (void) WriteBlobString(image,"\033*v6W"); /* set color mode... */ (void) WriteBlobByte(image,0); /* RGB */ (void) WriteBlobByte(image,3); /* direct by pixel */ (void) WriteBlobByte(image,0); /* bits per index (ignored) */ (void) WriteBlobByte(image,8); /* bits per red component */ (void) WriteBlobByte(image,8); /* bits per green component */ (void) WriteBlobByte(image,8); /* bits per blue component */ } else if (characteristics.monochrome) { /* Use default printer monochrome setup - NB white = 0, black = 1 */ bits_per_pixel=1; } else { /* PseudoClass */ bits_per_pixel=8; (void) WriteBlobString(image,"\033*v6W"); /* set color mode... */ (void) WriteBlobByte(image,0); /* RGB */ (void) WriteBlobByte(image,1); /* indexed by pixel */ (void) WriteBlobByte(image,bits_per_pixel); /* bits per index */ (void) WriteBlobByte(image,8); /* bits per red component (implicit) */ (void) WriteBlobByte(image,8); /* bits per green component (implicit) */ (void) WriteBlobByte(image,8); /* bits per blue component (implicit) */ /* Write colormap to file. */ for (i=0; i < (long)(image->colors); i++) { FormatString(buffer,"\033*v%da%db%dc%ldI", ScaleQuantumToChar(image->colormap[i].red), ScaleQuantumToChar(image->colormap[i].green), ScaleQuantumToChar(image->colormap[i].blue), i); WriteBlobString(image,buffer); } /* Initialize rest of palette with empty entries */ for ( ; i < (1L << bits_per_pixel); i++) { FormatString(buffer,"\033*v%luI",i); /* set index to current component values */ (void) WriteBlobString(image,buffer); } } /* Start raster image */ if ((AccessDefinition(image_info,"pcl","fit-to-page") != NULL) || (AccessDefinition(image_info,"pcl","fit_to_page") != NULL)) (void) WriteBlobString(image,"\033*r3A"); /* start raster graphics with scaling */ else (void) WriteBlobString(image,"\033*r1A"); /* start raster graphics */ (void) WriteBlobString(image,"\033*b0Y"); /* set y offset */ /* Assign row buffer */ bytes_per_line=(image->columns*bits_per_pixel+7)/8; pixels=MagickAllocateMemory(unsigned char *,bytes_per_line); if (pixels == (unsigned char *) NULL) ThrowWriterException(ResourceLimitError,MemoryAllocationFailed,image); /* Set up for compression if desired */ last_row_compression = PCL_UndefinedCompression; if (image_info->compression != NoCompression) { MagickFreeMemory(last_row_pixels); last_row_pixels=MagickAllocateMemory(unsigned char *,bytes_per_line); if (last_row_pixels == (unsigned char *) NULL) { MagickFreeMemory(pixels); ThrowWriterException(ResourceLimitError,MemoryAllocationFailed,image); } MagickFreeMemory(output_row); output_row=MagickAllocateMemory(unsigned char *,bytes_per_line); if (output_row == (unsigned char *) NULL) { MagickFreeMemory(pixels); MagickFreeMemory(last_row_pixels); ThrowWriterException(ResourceLimitError,MemoryAllocationFailed,image); } memset(last_row_pixels,0,bytes_per_line); } /* Convert MIFF to PCL raster pixels. */ zero_rows=0; for (y=0; y < (long) image->rows; y++) { p=AcquireImagePixels(image,0,y,image->columns,1,&image->exception); if (p == (const PixelPacket *) NULL) break; q=pixels; if (characteristics.monochrome) { register unsigned char bit, byte; int blk_ind; /* Monochrome row */ blk_ind = ((image->colormap == NULL) || (image->colormap[0].red == 0)) ? 0 : 1; indexes=AccessImmutableIndexes(image); bit=0; byte=0; for (x=0; x < (long) image->columns; x++) { byte<<=1; if (indexes[x] == blk_ind) byte |= 1; bit++; if (bit == 8) { *q++=byte; bit=0; byte=0; } } if (bit != 0) *q++=byte << (8-bit); } else if (bits_per_pixel == 8) { /* 8 bit PseudoClass row */ indexes=AccessImmutableIndexes(image); for (x=0; x < (long) image->columns; x++) { *q++=indexes[x]; } } else if ((bits_per_pixel == 24) || (bits_per_pixel == 32)) { /* DirectClass/RGB row */ for (x=0; x < (long) image->columns; x++) { *q++=ScaleQuantumToChar(p->red); *q++=ScaleQuantumToChar(p->green); *q++=ScaleQuantumToChar(p->blue); p++; } } if (image_info->compression == NoCompression) { FormatString(buffer,"\033*b%luW",bytes_per_line); /* send row */ (void) WriteBlobString(image,buffer); (void) WriteBlob(image,bytes_per_line,pixels); } else { compression=PCL_ChooseCompression(bytes_per_line,pixels,last_row_pixels); if (compression == PCL_ZeroRowCompression) { zero_rows++; } else { /* Skip any omitted zero rows now */ if (zero_rows > 0) { i = 32767; do { if (zero_rows < i) i=zero_rows; FormatString(buffer,"\033*b%ldY",i); /* Y Offset */ (void) WriteBlobString(image,buffer); zero_rows -= i; } while (zero_rows > 0); } switch (compression) { case PCL_DeltaCompression: { if (compression != last_row_compression) { FormatString(buffer,"\033*b3M"); /* delta compression */ (void) WriteBlobString(image,buffer); last_row_compression=compression; } bytes_to_write=PCL_DeltaCompress(bytes_per_line,pixels, last_row_pixels,output_row); FormatString(buffer,"\033*b%luW",bytes_to_write); (void) WriteBlobString(image,buffer); WriteBlob(image,bytes_to_write,output_row); break; } case PCL_TiffRLECompression: { if (compression != last_row_compression) { FormatString(buffer,"\033*b2M"); /* Tiff RLE compression */ (void) WriteBlobString(image,buffer); last_row_compression=compression; } bytes_to_write=PCL_TiffRLECompress(bytes_per_line,pixels,output_row); FormatString(buffer,"\033*b%luW",bytes_to_write); (void) WriteBlobString(image,buffer); WriteBlob(image,bytes_to_write,output_row); break; } case PCL_RLECompression: { if (compression != last_row_compression) { FormatString(buffer,"\033*b1M"); /* RLE compression */ (void) WriteBlobString(image,buffer); last_row_compression=compression; } bytes_to_write=PCL_RLECompress(bytes_per_line,pixels,output_row); FormatString(buffer,"\033*b%luW",bytes_to_write); (void) WriteBlobString(image,buffer); WriteBlob(image,bytes_to_write,output_row); break; } case PCL_RepeatedRowCompression: { compression=PCL_DeltaCompression; if (compression != last_row_compression) { FormatString(buffer,"\033*b3M"); /* delta row compression */ (void) WriteBlobString(image,buffer); last_row_compression=compression; } FormatString(buffer,"\033*b0W"); /* no data -> replicate row */ (void) WriteBlobString(image,buffer); break; } case PCL_NoCompression: { if (compression != last_row_compression) { FormatString(buffer,"\033*b0M"); /* no compression */ (void) WriteBlobString(image,buffer); last_row_compression=compression; } FormatString(buffer,"\033*b%luW",bytes_per_line); /* send row */ (void) WriteBlobString(image,buffer); (void) WriteBlob(image,bytes_per_line,pixels); break; } case PCL_ZeroRowCompression: { break; } case PCL_UndefinedCompression: { break; } } } /* Swap row with last row */ q=last_row_pixels; last_row_pixels=pixels; pixels=q; } if (image->previous == (Image *) NULL) if (QuantumTick(y,image->rows)) if (!MagickMonitorFormatted(y,image->rows,&image->exception, SaveImageText,image->filename, image->columns,image->rows)) break; } (void) WriteBlobString(image,"\033*rB"); /* end graphics */ MagickFreeMemory(pixels); MagickFreeMemory(last_row_pixels); MagickFreeMemory(output_row); if (image->next == (Image *) NULL) break; image=SyncNextImageInList(image); if ((status &= MagickMonitorFormatted(scene++, GetImageListLength(image), &image->exception, SaveImagesText, image->filename)) == MagickFail) break; } while (image_info->adjoin);
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); }