/* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % % W r i t e Y U V I m a g e % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % Method WriteYUVImage writes an image to a file in the digital YUV % (CCIR 601 4:1:1) format. % % The format of the WriteYUVImage method is: % % unsigned int WriteYUVImage(const ImageInfo *image_info,Image *image) % % A description of each parameter follows. % % o status: Method WriteYUVImage 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 an ImageInfo structure. % % o image: A pointer to a Image structure. % % */ Export unsigned int WriteYUVImage(const ImageInfo *image_info,Image *image) { Image *chroma_image, *yuv_image; int y; register int x; register PixelPacket *p; unsigned int height, scene, status, width; if (image_info->interlace != PartitionInterlace) { /* Open output image file. */ status=OpenBlob(image_info,image,WriteBinaryType); if (status == False) WriterExit(FileOpenWarning,"Unable to open file",image); } if (image_info->interlace == PartitionInterlace) { AppendImageFormat("Y",image->filename); status=OpenBlob(image_info,image,WriteBinaryType); if (status == False) WriterExit(FileOpenWarning,"Unable to open file",image); } scene=0; do { /* Sample image to an even width and height. */ TransformRGBImage(image,RGBColorspace); width=image->columns+(image->columns & 0x01); height=image->rows+(image->rows & 0x01); image->orphan=True; yuv_image=SampleImage(image,width,height); if (yuv_image == (Image *) NULL) WriterExit(ResourceLimitWarning,"Unable to zoom image",image); RGBTransformImage(yuv_image,YCbCrColorspace); /* Initialize Y channel. */ for (y=0; y < (int) yuv_image->rows; y++) { p=GetPixelCache(yuv_image,0,y,yuv_image->columns,1); if (p == (PixelPacket *) NULL) break; for (x=0; x < (int) yuv_image->columns; x++) { (void) WriteByte(image,DownScale(p->red)); p++; } if (image->previous == (Image *) NULL) if (QuantumTick(y,image->rows)) ProgressMonitor(SaveImageText,y,image->rows); } DestroyImage(yuv_image); /* Downsample image. */ image->orphan=True; chroma_image=SampleImage(image,width/2,height/2); if (chroma_image == (Image *) NULL) WriterExit(ResourceLimitWarning,"Unable to zoom image",image); RGBTransformImage(chroma_image,YCbCrColorspace); /* Initialize U channel. */ if (image_info->interlace == PartitionInterlace) { CloseBlob(image); AppendImageFormat("U",image->filename); status=OpenBlob(image_info,image,WriteBinaryType); if (status == False) WriterExit(FileOpenWarning,"Unable to open file",image); } for (y=0; y < (int) chroma_image->rows; y++) { p=GetPixelCache(chroma_image,0,y,chroma_image->columns,1); if (p == (PixelPacket *) NULL) break; for (x=0; x < (int) chroma_image->columns; x++) { (void) WriteByte(image,DownScale(p->green)); p++; } } /* Initialize V channel. */ if (image_info->interlace == PartitionInterlace) { CloseBlob(image); AppendImageFormat("V",image->filename); status=OpenBlob(image_info,image,WriteBinaryType); if (status == False) WriterExit(FileOpenWarning,"Unable to open file",image); } for (y=0; y < (int) chroma_image->rows; y++) { p=GetPixelCache(chroma_image,0,y,chroma_image->columns,1); if (p == (PixelPacket *) NULL) break; for (x=0; x < (int) chroma_image->columns; x++) { (void) WriteByte(image,DownScale(p->blue)); p++; } } DestroyImage(chroma_image); if (image_info->interlace == PartitionInterlace) (void) strcpy(image->filename,image_info->filename); if (image->next == (Image *) NULL) break; image=GetNextImage(image); ProgressMonitor(SaveImagesText,scene++,GetNumberScenes(image)); } while (image_info->adjoin); if (image_info->adjoin) while (image->previous != (Image *) NULL) image=image->previous; CloseBlob(image); return(True); }
/* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % % R e a d Y U V I m a g e % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % Method ReadYUVImage reads an image with digital YUV (CCIR 601 4:1:1) bytes % and returns it. It allocates the memory necessary for the new Image % structure and returns a pointer to the new image. % % The format of the ReadYUVImage method is: % % Image *ReadYUVImage(const ImageInfo *image_info) % % A description of each parameter follows: % % o image: Method ReadYUVImage 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 an ImageInfo structure. % % */ Export Image *ReadYUVImage(const ImageInfo *image_info) { Image *chroma_image, *image, *zoom_image; int count, y; register int i, x; register PixelPacket *q, *r; register unsigned char *p; unsigned char *scanline; unsigned int status; /* Allocate image structure. */ image=AllocateImage(image_info); if (image == (Image *) NULL) return((Image *) NULL); if ((image->columns == 0) || (image->rows == 0)) ReaderExit(OptionWarning,"Must specify image size",image); image->depth=8; if (image_info->interlace != PartitionInterlace) { /* Open image file. */ status=OpenBlob(image_info,image,ReadBinaryType); if (status == False) ReaderExit(FileOpenWarning,"Unable to open file",image); for (i=0; i < image->offset; i++) (void) ReadByte(image); } /* Allocate memory for a scanline. */ scanline=(unsigned char *) AllocateMemory(image->columns*sizeof(unsigned char)); if (scanline == (unsigned char *) NULL) ReaderExit(ResourceLimitWarning,"Memory allocation failed",image); do { /* Convert raster image to pixel packets. */ if (image_info->interlace == PartitionInterlace) { AppendImageFormat("Y",image->filename); status=OpenBlob(image_info,image,ReadBinaryType); if (status == False) ReaderExit(FileOpenWarning,"Unable to open file",image); } for (y=0; y < (int) image->rows; y++) { if ((y > 0) || (image->previous == (Image *) NULL)) (void) ReadBlob(image,image->columns,scanline); p=scanline; q=SetPixelCache(image,0,y,image->columns,1); if (q == (PixelPacket *) NULL) break; for (x=0; x < (int) image->columns; x++) { q->red=UpScale(*p++); q->green=0; q->blue=0; q++; } if (!SyncPixelCache(image)) break; if (image->previous == (Image *) NULL) ProgressMonitor(LoadImageText,y,image->rows); } if (image_info->interlace == PartitionInterlace) { CloseBlob(image); AppendImageFormat("U",image->filename); status=OpenBlob(image_info,image,ReadBinaryType); if (status == False) ReaderExit(FileOpenWarning,"Unable to open file",image); } chroma_image=CloneImage(image,image->columns/2,image->rows/2,True); if (chroma_image == (Image *) NULL) ReaderExit(ResourceLimitWarning,"Memory allocation failed",image); for (y=0; y < (int) chroma_image->rows; y++) { (void) ReadBlob(image,chroma_image->columns,scanline); p=scanline; q=SetPixelCache(chroma_image,0,y,chroma_image->columns,1); if (q == (PixelPacket *) NULL) break; for (x=0; x < (int) chroma_image->columns; x++) { q->red=0; q->green=UpScale(*p++); q->blue=0; q++; } if (!SyncPixelCache(chroma_image)) break; } if (image_info->interlace == PartitionInterlace) { CloseBlob(image); AppendImageFormat("V",image->filename); status=OpenBlob(image_info,image,ReadBinaryType); if (status == False) ReaderExit(FileOpenWarning,"Unable to open file",image); } for (y=0; y < (int) chroma_image->rows; y++) { (void) ReadBlob(image,chroma_image->columns,scanline); p=scanline; q=GetPixelCache(chroma_image,0,y,chroma_image->columns,1); if (q == (PixelPacket *) NULL) break; for (x=0; x < (int) chroma_image->columns; x++) { q->blue=UpScale(*p++); q++; } if (!SyncPixelCache(chroma_image)) break; } /* Scale image. */ chroma_image->orphan=True; zoom_image=SampleImage(chroma_image,image->columns,image->rows); DestroyImage(chroma_image); if (zoom_image == (Image *) NULL) ReaderExit(ResourceLimitWarning,"Memory allocation failed",image); for (y=0; y < (int) image->rows; y++) { q=GetPixelCache(image,0,y,image->columns,1); r=GetPixelCache(zoom_image,0,y,zoom_image->columns,1); if ((q == (PixelPacket *) NULL) || (r == (PixelPacket *) NULL)) break; for (x=0; x < (int) image->columns; x++) { q->green=r->green; q->blue=r->blue; r++; q++; } if (!SyncPixelCache(image)) break; } DestroyImage(zoom_image); TransformRGBImage(image,YCbCrColorspace); if (image_info->interlace == PartitionInterlace) (void) strcpy(image->filename,image_info->filename); /* Proceed to next image. */ if (image_info->subrange != 0) if (image->scene >= (image_info->subimage+image_info->subrange-1)) break; count=ReadBlob(image,image->columns,(char *) scanline); if (count > 0) { /* Allocate next image structure. */ AllocateNextImage(image_info,image); if (image->next == (Image *) NULL) { DestroyImages(image); return((Image *) NULL); } image=image->next; ProgressMonitor(LoadImagesText,TellBlob(image),image->filesize); } } while (count > 0); FreeMemory(scanline); while (image->previous != (Image *) NULL) image=image->previous; CloseBlob(image); return(image); }
/* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % N o r m a l i z e I m a g e % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % Method NormalizeImage normalizes the pixel values to span the full % range of color values. This is a contrast enhancement technique. % % The format of the NormalizeImage method is: % % void NormalizeImage(Image *image) % % A description of each parameter follows: % % o image: The address of a structure of type Image; returned from % ReadImage. % % */ Export void NormalizeImage(Image *image) { #define NormalizeImageText " Normalizing image... " int *histogram, threshold_intensity, y; Quantum gray_value, *normalize_map; register int i, intensity, x; register PixelPacket *p, *q; unsigned int high, low; /* Allocate histogram and normalize map. */ assert(image != (Image *) NULL); histogram=(int *) AllocateMemory((MaxRGB+1)*sizeof(int)); normalize_map=(Quantum *) AllocateMemory((MaxRGB+1)*sizeof(Quantum)); if ((histogram == (int *) NULL) || (normalize_map == (Quantum *) NULL)) { MagickWarning(ResourceLimitWarning,"Unable to normalize image", "Memory allocation failed"); return; } /* Form histogram. */ for (i=0; i <= MaxRGB; i++) histogram[i]=0; for (y=0; y < (int) image->rows; y++) { p=GetPixelCache(image,0,y,image->columns,1); if (p == (PixelPacket *) NULL) break; for (x=0; x < (int) image->columns; x++) { gray_value=Intensity(*p); histogram[gray_value]++; p++; } } /* Find the histogram boundaries by locating the 1 percent levels. */ threshold_intensity=(image->columns*image->rows)/100; intensity=0; for (low=0; low < MaxRGB; low++) { intensity+=histogram[low]; if (intensity > threshold_intensity) break; } intensity=0; for (high=MaxRGB; high != 0; high--) { intensity+=histogram[high]; if (intensity > threshold_intensity) break; } if (low == high) { /* Unreasonable contrast; use zero threshold to determine boundaries. */ threshold_intensity=0; intensity=0; for (low=0; low < MaxRGB; low++) { intensity+=histogram[low]; if (intensity > threshold_intensity) break; } intensity=0; for (high=MaxRGB; high != 0; high--) { intensity+=histogram[high]; if (intensity > threshold_intensity) break; } if (low == high) return; /* zero span bound */ } /* Stretch the histogram to create the normalized image mapping. */ for (i=0; i <= MaxRGB; i++) if (i < (int) low) normalize_map[i]=0; else if (i > (int) high) normalize_map[i]=MaxRGB; else normalize_map[i]=(MaxRGB-1)*(i-low)/(high-low); /* Normalize the image. */ switch (image->class) { case DirectClass: default: { /* Normalize DirectClass image. */ for (y=0; y < (int) image->rows; y++) { q=GetPixelCache(image,0,y,image->columns,1); if (q == (PixelPacket *) NULL) break; for (x=0; x < (int) image->columns; x++) { q->red=normalize_map[q->red]; q->green=normalize_map[q->green]; q->blue=normalize_map[q->blue]; q++; } if (!SyncPixelCache(image)) break; if (QuantumTick(y,image->rows)) ProgressMonitor(NormalizeImageText,y,image->rows); } break; } case PseudoClass: { /* Normalize PseudoClass image. */ for (i=0; i < (int) image->colors; i++) { image->colormap[i].red=normalize_map[image->colormap[i].red]; image->colormap[i].green=normalize_map[image->colormap[i].green]; image->colormap[i].blue=normalize_map[image->colormap[i].blue]; } SyncImage(image); break; } } FreeMemory(normalize_map); FreeMemory(histogram); }
/* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % C o n t r a s t I m a g e % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % Method ContrastImage enhances the intensity differences between the % lighter and darker elements of the image. % % The format of the ContrastImage method is: % % void ContrastImage(Image *image,const unsigned int sharpen) % % A description of each parameter follows: % % o image: The address of a structure of type Image; returned from % ReadImage. % % o sharpen: If True, the intensity is increased otherwise it is % decreased. % % */ Export void ContrastImage(Image *image,const unsigned int sharpen) { #define DullContrastImageText " Dulling image contrast... " #define SharpenContrastImageText " Sharpening image contrast... " int sign, y; register int i, x; register PixelPacket *q; assert(image != (Image *) NULL); sign=sharpen ? 1 : -1; switch (image->class) { case DirectClass: default: { /* Contrast enhance DirectClass image. */ for (y=0; y < (int) image->rows; y++) { q=GetPixelCache(image,0,y,image->columns,1); if (q == (PixelPacket *) NULL) break; for (x=0; x < (int) image->columns; x++) { Contrast(sign,&q->red,&q->green,&q->blue); q++; } if (!SyncPixelCache(image)) break; if (QuantumTick(y,image->rows)) { if (sharpen) ProgressMonitor(SharpenContrastImageText,y,image->rows); else ProgressMonitor(DullContrastImageText,y,image->rows); } } break; } case PseudoClass: { Quantum blue, green, red; /* Contrast enhance PseudoClass image. */ for (i=0; i < (int) image->colors; i++) { red=image->colormap[i].red; green=image->colormap[i].green; blue=image->colormap[i].blue; Contrast(sign,&red,&green,&blue); image->colormap[i].red=red; image->colormap[i].green=green; image->colormap[i].blue=blue; } SyncImage(image); break; } } }
/* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % M o d u l a t e I m a g e % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % Method ModulateImage modulates the hue, saturation, and brightness of an % image. % % The format of the ModulateImage method is: % % void ModulateImage(Image *image,const char *modulate) % % A description of each parameter follows: % % o image: The address of a structure of type Image; returned from % ReadImage. % % o modulate: A character string indicating the percent change in brightness, % saturation, and hue in floating point notation separated by commas % (e.g. 10.1,0.0,3.1). % % */ Export void ModulateImage(Image *image,const char *modulate) { #define ModulateImageText " Modulating image... " double percent_brightness, percent_hue, percent_saturation; int y; register int i, x; register PixelPacket *q; /* Initialize gamma table. */ assert(image != (Image *) NULL); if (modulate == (char *) NULL) return; percent_hue=0.0; percent_brightness=0.0; percent_saturation=0.0; (void) sscanf(modulate,"%lf,%lf,%lf",&percent_brightness,&percent_saturation, &percent_hue); (void) sscanf(modulate,"%lf/%lf/%lf",&percent_brightness,&percent_saturation, &percent_hue); switch (image->class) { case DirectClass: default: { /* Modulate the color for a DirectClass image. */ for (y=0; y < (int) image->rows; y++) { q=GetPixelCache(image,0,y,image->columns,1); if (q == (PixelPacket *) NULL) break; for (x=0; x < (int) image->columns; x++) { Modulate(percent_hue,percent_saturation,percent_brightness, &q->red,&q->green,&q->blue); q++; } if (!SyncPixelCache(image)) break; if (QuantumTick(y,image->rows)) ProgressMonitor(ModulateImageText,y,image->rows); } break; } case PseudoClass: { Quantum blue, green, red; /* Modulate the color for a PseudoClass image. */ for (i=0; i < (int) image->colors; i++) { red=image->colormap[i].red; green=image->colormap[i].green; blue=image->colormap[i].blue; Modulate(percent_hue,percent_saturation,percent_brightness, &red,&green,&blue); image->colormap[i].red=red; image->colormap[i].green=green; image->colormap[i].blue=blue; } SyncImage(image); break; } } }
/* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % N e g a t e I m a g e % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % Method NegateImage negates the colors in the reference image. The % Grayscale option means that only grayscale values within the image are % negated. % % The format of the NegateImage method is: % % void NegateImage(Image *image,const unsigned int grayscale) % % A description of each parameter follows: % % o image: The address of a structure of type Image; returned from % ReadImage. % % */ Export void NegateImage(Image *image,const unsigned int grayscale) { #define NegateImageText " Negating the image colors... " int y; register int i, x; register PixelPacket *q; assert(image != (Image *) NULL); switch (image->class) { case DirectClass: default: { /* Negate DirectClass packets. */ for (y=0; y < (int) image->rows; y++) { q=GetPixelCache(image,0,y,image->columns,1); if (q == (PixelPacket *) NULL) break; for (x=0; x < (int) image->columns; x++) { if (grayscale) if ((q->red != q->green) || (q->green != q->blue)) { q++; continue; } q->red=(~q->red); q->green=(~q->green); q->blue=(~q->blue); q->opacity=(~q->opacity); q++; } if (!SyncPixelCache(image)) break; if (QuantumTick(y,image->rows)) ProgressMonitor(NegateImageText,y,image->rows); } break; } case PseudoClass: { /* Negate PseudoClass packets. */ for (i=0; i < (int) image->colors; i++) { if (grayscale) if ((image->colormap[i].red != image->colormap[i].green) || (image->colormap[i].green != image->colormap[i].blue)) continue; image->colormap[i].red=(Quantum) (~image->colormap[i].red); image->colormap[i].green=(Quantum) (~image->colormap[i].green); image->colormap[i].blue=(Quantum) (~image->colormap[i].blue); } SyncImage(image); break; } } }
/* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % G a m m a I m a g e % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % Method GammaImage converts the reference image to gamma corrected colors. % % The format of the GammaImage method is: % % void GammaImage(Image *image,const char *gamma) % % A description of each parameter follows: % % o image: The address of a structure of type Image; returned from % ReadImage. % % o gamma: A character string indicating the level of gamma correction. % % */ Export void GammaImage(Image *image,const char *gamma) { #define GammaImageText " Gamma correcting the image... " double blue_gamma, green_gamma, opacity_gamma, red_gamma; int count, y; register int i, x; register PixelPacket *q; PixelPacket *gamma_map; assert(image != (Image *) NULL); if (gamma == (char *) NULL) return; red_gamma=1.0; green_gamma=1.0; blue_gamma=1.0; opacity_gamma=1.0; count=sscanf(gamma,"%lf,%lf,%lf,%lf",&red_gamma,&green_gamma,&blue_gamma, &opacity_gamma); count=sscanf(gamma,"%lf/%lf/%lf/%lf",&red_gamma,&green_gamma,&blue_gamma, &opacity_gamma); if (count == 1) { if (red_gamma == 1.0) return; green_gamma=red_gamma; blue_gamma=red_gamma; } /* Allocate and initialize gamma maps. */ gamma_map=(PixelPacket *) AllocateMemory((MaxRGB+1)*sizeof(PixelPacket)); if (gamma_map == (PixelPacket *) NULL) { MagickWarning(ResourceLimitWarning,"Unable to gamma correct image", "Memory allocation failed"); return; } for (i=0; i <= MaxRGB; i++) { gamma_map[i].red=0; gamma_map[i].green=0; gamma_map[i].blue=0; gamma_map[i].opacity=0; } /* Initialize gamma table. */ for (i=0; i <= MaxRGB; i++) { if (red_gamma != 0.0) gamma_map[i].red=(Quantum) ((pow((double) i/MaxRGB,1.0/red_gamma)*MaxRGB)+0.5); if (green_gamma != 0.0) gamma_map[i].green=(Quantum) ((pow((double) i/MaxRGB,1.0/green_gamma)*MaxRGB)+0.5); if (blue_gamma != 0.0) gamma_map[i].blue=(Quantum) ((pow((double) i/MaxRGB,1.0/blue_gamma)*MaxRGB)+0.5); if (opacity_gamma != 0.0) gamma_map[i].opacity=(Quantum) ((pow((double) i/MaxRGB,1.0/opacity_gamma)*MaxRGB)+0.5); } switch (image->class) { case DirectClass: default: { /* Gamma-correct DirectClass image. */ for (y=0; y < (int) image->rows; y++) { q=GetPixelCache(image,0,y,image->columns,1); if (q == (PixelPacket *) NULL) break; for (x=0; x < (int) image->columns; x++) { q->red=gamma_map[q->red].red; q->green=gamma_map[q->green].green; q->blue=gamma_map[q->blue].blue; q->opacity=gamma_map[q->opacity].opacity; q++; } if (!SyncPixelCache(image)) break; if (QuantumTick(y,image->rows)) ProgressMonitor(GammaImageText,y,image->rows); } break; } case PseudoClass: { /* Gamma-correct PseudoClass image. */ for (i=0; i < (int) image->colors; i++) { image->colormap[i].red=gamma_map[image->colormap[i].red].red; image->colormap[i].green=gamma_map[image->colormap[i].green].green; image->colormap[i].blue=gamma_map[image->colormap[i].blue].blue; } SyncImage(image); break; } } if (image->gamma != 0.0) image->gamma*=(red_gamma+green_gamma+blue_gamma)/3.0; FreeMemory(gamma_map); }
/* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % E q u a l i z e I m a g e % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % Method EqualizeImage performs histogram equalization on the reference % image. % % The format of the EqualizeImage method is: % % void EqualizeImage(Image *image) % % A description of each parameter follows: % % o image: The address of a structure of type Image; returned from % ReadImage. % % */ Export void EqualizeImage(Image *image) { #define EqualizeImageText " Equalizing image... " int j, y; Quantum *equalize_map; register int i, x; register PixelPacket *p, *q; unsigned int high, *histogram, low, *map; /* Allocate and initialize histogram arrays. */ assert(image != (Image *) NULL); histogram=(unsigned int *) AllocateMemory((MaxRGB+1)*sizeof(unsigned int)); map=(unsigned int *) AllocateMemory((MaxRGB+1)*sizeof(unsigned int)); equalize_map=(Quantum *) AllocateMemory((MaxRGB+1)*sizeof(Quantum)); if ((histogram == (unsigned int *) NULL) || (map == (unsigned int *) NULL) || (equalize_map == (Quantum *) NULL)) { MagickWarning(ResourceLimitWarning,"Unable to equalize image", "Memory allocation failed"); return; } /* Form histogram. */ for (i=0; i <= MaxRGB; i++) histogram[i]=0; for (y=0; y < (int) image->rows; y++) { p=GetPixelCache(image,0,y,image->columns,1); if (p == (PixelPacket *) NULL) break; for (x=0; x < (int) image->columns; x++) { histogram[Intensity(*p)]++; p++; } } /* Integrate the histogram to get the equalization map. */ j=0; for (i=0; i <= MaxRGB; i++) { j+=histogram[i]; map[i]=j; } FreeMemory(histogram); if (map[MaxRGB] == 0) { FreeMemory(equalize_map); FreeMemory(map); return; } /* Equalize. */ low=map[0]; high=map[MaxRGB]; for (i=0; i <= MaxRGB; i++) equalize_map[i]=(Quantum) ((((double) (map[i]-low))*MaxRGB)/Max(high-low,1)); FreeMemory(map); /* Stretch the histogram. */ switch (image->class) { case DirectClass: default: { /* Equalize DirectClass packets. */ for (y=0; y < (int) image->rows; y++) { q=GetPixelCache(image,0,y,image->columns,1); if (q == (PixelPacket *) NULL) break; for (x=0; x < (int) image->columns; x++) { q->red=equalize_map[q->red]; q->green=equalize_map[q->green]; q->blue=equalize_map[q->blue]; q++; } if (!SyncPixelCache(image)) break; if (QuantumTick(y,image->rows)) ProgressMonitor(EqualizeImageText,y,image->rows); } break; } case PseudoClass: { /* Equalize PseudoClass packets. */ for (i=0; i < (int) image->colors; i++) { image->colormap[i].red=equalize_map[image->colormap[i].red]; image->colormap[i].green=equalize_map[image->colormap[i].green]; image->colormap[i].blue=equalize_map[image->colormap[i].blue]; } SyncImage(image); break; } } FreeMemory(equalize_map); }
Export Image *MontageImages(const Image *images,const MontageInfo *montage_info) { #define MontageImageText " Creating visual image directory... " #define TileImageText " Creating image tiles... " AnnotateInfo *annotate_info; char geometry[MaxTextExtent]; FrameInfo frame_info; Image *image, **image_list, **master_list, *montage_image, *texture, *tiled_image; ImageInfo *local_info; int x, x_offset, y, y_offset; MonitorHandler handler; register int i; register PixelPacket *q; RectangleInfo bounding_box, tile_info; unsigned int border_width, bevel_width, concatenate, count, font_height, height, images_per_page, max_height, number_images, number_lines, tile, tiles, tiles_per_column, tiles_per_row, tiles_per_page, title_offset, total_tiles, width; assert(images != (Image *) NULL); assert(montage_info != (MontageInfo *) NULL); /* Convert image list to an image group. */ image_list=ListToGroupImage(images,&number_images); if (image_list == (Image **) NULL) { MagickWarning(ResourceLimitWarning,"Unable to montage image_list", "Memory allocation failed"); return((Image *) NULL); } master_list=image_list; /* Create image tiles. */ for (tile=0; tile < number_images; tile++) { handler=SetMonitorHandler((MonitorHandler) NULL); width=image_list[tile]->columns; height=image_list[tile]->rows; x=0; y=0; (void) ParseImageGeometry(montage_info->geometry,&x,&y,&width,&height); image_list[tile]->orphan=True; tiled_image=ZoomImage(image_list[tile],width,height); if (tiled_image == (Image *) NULL) { for (i=0; i < (int) tile; i++) DestroyImage(image_list[i]); (void) SetMonitorHandler(handler); return((Image *) NULL); } image_list[tile]=tiled_image; (void) SetMonitorHandler(handler); ProgressMonitor(TileImageText,tile,number_images); } /* Sort image_list by increasing tile number. */ for (tile=0; tile < number_images; tile++) if (image_list[tile]->scene == 0) break; if (tile == number_images) qsort((void *) image_list,number_images,sizeof(Image *), (int (*)(const void *, const void *)) SceneCompare); /* Determine tiles per row and column. */ tiles_per_row=1; tiles_per_column=1; while ((tiles_per_row*tiles_per_column) < number_images) { tiles_per_row++; tiles_per_column++; } if (montage_info->tile != (char *) NULL) { tiles_per_column=number_images; x=0; y=0; (void) ParseGeometry(montage_info->tile,&x,&y,&tiles_per_row, &tiles_per_column); } /* Determine tile sizes. */ border_width=montage_info->border_width; bevel_width=0; if (montage_info->frame != (char *) NULL) { int flags; frame_info.width=0; frame_info.height=0; frame_info.outer_bevel=0; frame_info.inner_bevel=0; flags=ParseGeometry(montage_info->frame,&frame_info.outer_bevel, &frame_info.inner_bevel,&frame_info.width,&frame_info.height); if ((flags & HeightValue) == 0) frame_info.height=frame_info.width; if ((flags & XValue) == 0) frame_info.outer_bevel=(frame_info.width >> 2)+1; if ((flags & YValue) == 0) frame_info.inner_bevel=frame_info.outer_bevel; frame_info.x=frame_info.width; frame_info.y=frame_info.height; bevel_width=Max(frame_info.inner_bevel,frame_info.outer_bevel); border_width=Max(frame_info.width,frame_info.height); }
/* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % % R e a d S C T I m a g e % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % Method ReadSCTImage reads a Scitex image file and returns it. It allocates % the memory necessary for the new Image structure and returns a pointer to % the new image. % % The format of the ReadSCTImage method is: % % Image *ReadSCTImage(const ImageInfo *image_info) % % A description of each parameter follows: % % o image: Method ReadSCTImage 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 an ImageInfo structure. % % */ Export Image *ReadSCTImage(const ImageInfo *image_info) { char buffer[768], magick[2]; Image *image; int y; register int x; register PixelPacket *q; unsigned int status; /* Allocate image structure. */ image=AllocateImage(image_info); if (image == (Image *) NULL) return((Image *) NULL); /* Open image file. */ status=OpenBlob(image_info,image,ReadBinaryType); if (status == False) ReaderExit(FileOpenWarning,"Unable to open file",image); /* Read control block. */ (void) ReadBlob(image,80,(char *) buffer); (void) ReadBlob(image,2,(char *) magick); if ((strncmp((char *) magick,"CT",2) != 0) && (strncmp((char *) magick,"LW",2) != 0) && (strncmp((char *) magick,"BM",2) != 0) && (strncmp((char *) magick,"PG",2) != 0) && (strncmp((char *) magick,"TX",2) != 0)) ReaderExit(CorruptImageWarning,"Not a SCT image file",image); if ((strncmp((char *) magick,"LW",2) == 0) || (strncmp((char *) magick,"BM",2) == 0) || (strncmp((char *) magick,"PG",2) == 0) || (strncmp((char *) magick,"TX",2) == 0)) ReaderExit(CorruptImageWarning,"only Continuous Tone Picture supported", image); (void) ReadBlob(image,174,(char *) buffer); (void) ReadBlob(image,768,(char *) buffer); /* Read paramter block. */ (void) ReadBlob(image,32,(char *) buffer); (void) ReadBlob(image,14,(char *) buffer); image->rows=atoi(buffer); (void) ReadBlob(image,14,(char *) buffer); image->columns=atoi(buffer); (void) ReadBlob(image,196,(char *) buffer); (void) ReadBlob(image,768,(char *) buffer); if (image_info->ping) { CloseBlob(image); return(image); } /* Convert SCT raster image to pixel packets. */ image->colorspace=CMYKColorspace; for (y=0; y < (int) image->rows; y++) { q=SetPixelCache(image,0,y,image->columns,1); if (q == (PixelPacket *) NULL) break; for (x=0; x < (int) image->columns; x++) { q->red=MaxRGB-UpScale(ReadByte(image)); q++; } if ((image->columns % 2) != 0) (void) ReadByte(image); /* pad */ q=GetPixelCache(image,0,y,image->columns,1); if (q == (PixelPacket *) NULL) break; for (x=0; x < (int) image->columns; x++) { q->green=MaxRGB-UpScale(ReadByte(image)); q++; } if ((image->columns % 2) != 0) (void) ReadByte(image); /* pad */ q=GetPixelCache(image,0,y,image->columns,1); if (q == (PixelPacket *) NULL) break; for (x=0; x < (int) image->columns; x++) { q->blue=MaxRGB-UpScale(ReadByte(image)); q++; } if ((image->columns % 2) != 0) (void) ReadByte(image); /* pad */ q=GetPixelCache(image,0,y,image->columns,1); if (q == (PixelPacket *) NULL) break; for (x=0; x < (int) image->columns; x++) { q->opacity=MaxRGB-UpScale(ReadByte(image)); q++; } if (!SyncPixelCache(image)) break; if ((image->columns % 2) != 0) (void) ReadByte(image); /* pad */ if (QuantumTick(y,image->rows)) ProgressMonitor(LoadImageText,y,image->rows); } return(image); }
/* The code of GIFEncodeImage is based on an early version of ImageMagick. */ static unsigned int GIFEncodeImage(GenBuffer::Writable& out, char const*ppbeg, register char const*ppend, const unsigned int data_size) { #define MaxCode(number_bits) ((1 << (number_bits))-1) #define MaxHashTable 5003 #define MaxGIFBits 12 #if defined(HasLZW) #define MaxGIFTable (1 << MaxGIFBits) #else #define MaxGIFTable max_code #endif #define GIFOutputCode(code) \ { \ /* \ Emit a code. \ */ \ if (bits > 0) \ datum|=((long) code << bits); \ else \ datum=(long) code; \ bits+=number_bits; \ while (bits >= 8) \ { \ /* \ Add a character to current packet. \ */ \ packet[byte_count++]=(unsigned char) (datum & 0xff); \ if (byte_count >= 254) \ { \ packet[-1]=byte_count; \ out.vi_write((char*)packet-1, byte_count+1); \ byte_count=0; \ } \ datum>>=8; \ bits-=8; \ } \ if (free_code > max_code) \ { \ number_bits++; \ if (number_bits == MaxGIFBits) \ max_code=MaxGIFTable; \ else \ max_code=MaxCode(number_bits); \ } \ } int bits, byte_count, i, next_pixel, number_bits; long datum; register int displacement, k; register char const*pp; short clear_code, end_of_information_code, free_code, *hash_code, *hash_prefix, index, max_code, waiting_code; unsigned char *packet, *hash_suffix; /* Allocate encoder tables. */ AALLOC(packet,257,unsigned char); AALLOC(hash_code,MaxHashTable,short); AALLOC(hash_prefix,MaxHashTable,short); AALLOC(hash_suffix,MaxHashTable,unsigned char); if ((packet == (unsigned char *) NULL) || (hash_code == (short *) NULL) || (hash_prefix == (short *) NULL) || (hash_suffix == (unsigned char *) NULL)) return(False); packet++; /* Now: packet-1 == place for byte_count */ /* Initialize GIF encoder. */ number_bits=data_size; max_code=MaxCode(number_bits); clear_code=((short) 1 << (data_size-1)); end_of_information_code=clear_code+1; free_code=clear_code+2; byte_count=0; datum=0; bits=0; for (i=0; i < MaxHashTable; i++) hash_code[i]=0; GIFOutputCode(clear_code); /* Encode pixels. */ /**** pts ****/ pp=ppbeg; waiting_code=*(unsigned char const*)pp++; /* unsigned char BUGFIX at Sun Dec 8 13:17:00 CET 2002 */ while (pp!=ppend) { /* Probe hash table. */ index=*(unsigned char const*)pp++; k=(int) ((int) index << (MaxGIFBits-8))+waiting_code; if (k >= MaxHashTable) k-=MaxHashTable; #if defined(HasLZW) if (hash_code[k] > 0) { if ((hash_prefix[k] == waiting_code) && (hash_suffix[k] == index)) { waiting_code=hash_code[k]; continue; } if (k == 0) displacement=1; else displacement=MaxHashTable-k; next_pixel=False; for ( ; ; ) { k-=displacement; if (k < 0) k+=MaxHashTable; if (hash_code[k] == 0) break; if ((hash_prefix[k] == waiting_code) && (hash_suffix[k] == index)) { waiting_code=hash_code[k]; next_pixel=True; break; } } if (next_pixel != False) /* pacify VC6.0 */ continue; } #endif GIFOutputCode(waiting_code); // printf("wc=%u\n", waiting_code); if (free_code < MaxGIFTable) { hash_code[k]=free_code++; hash_prefix[k]=waiting_code; hash_suffix[k]=index; } else { /* Fill the hash table with empty entries. */ for (k=0; k < MaxHashTable; k++) hash_code[k]=0; /* Reset compressor and issue a clear code. */ free_code=clear_code+2; GIFOutputCode(clear_code); number_bits=data_size; max_code=MaxCode(number_bits); } waiting_code=index; #if 0 /**** pts ****/ if (QuantumTick(i,image) && (image->previous == (Image2 *) NULL)) ProgressMonitor(SaveImageText,i,image->packets); #endif } /* Flush out the buffered code. */ GIFOutputCode(waiting_code); GIFOutputCode(end_of_information_code); if (bits > 0) { /* Add a character to current packet. */ packet[byte_count++]=(unsigned char) (datum & 0xff); if (byte_count >= 254) { packet[-1]=byte_count; out.vi_write((char*)packet-1, byte_count+1); byte_count=0; } } /* Flush accumulated data. */ if (byte_count > 0) { packet[-1]=byte_count; out.vi_write((char*)packet-1, byte_count+1); } /* Free encoder memory. */ AFREE(hash_suffix); AFREE(hash_prefix); AFREE(hash_code); AFREE(packet-1); return pp==ppend; }