Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
home:majun
arachne
image.c
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File image.c of Package arachne
/* image.c Author: Hayden Walles Date: 17 September 2007 A little image wrapper implementation. */ /* Copyright (C) 2007, 2008 Hayden Walles This file is part of Arachne. Arachne is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. Arachne is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include <tiffio.h> #include <stdlib.h> #include <stdio.h> #include <string.h> #include <setjmp.h> #include <jpeglib.h> #include "image.h" #ifndef MIN #define MIN(a,b) (((a)<(b)) ? (a): (b)) #endif /*This is used to store an error string, but only for the JPEG library at the moment.*/ static char *LastJpegErrorString=NULL; IMAGE *newImage(int width,int height,int *error){ IMAGE *new; if(LastJpegErrorString!=NULL){ free(LastJpegErrorString); LastJpegErrorString=NULL; } if((new=malloc(sizeof(IMAGE)+width*height*4))==NULL){ if(error!=NULL) *error=IMAGE_E_MEMORY; return NULL; } new->width=width; new->height=height; new->pixels=((unsigned char *)new)+sizeof(IMAGE); return new; } void deleteImage(IMAGE *image){ free(image); } void setPixel(IMAGE *image,int row, int col, int r, int g, int b){ image->pixels[(row*image->width+col)*4]=r; image->pixels[(row*image->width+col)*4+1]=g; image->pixels[(row*image->width+col)*4+2]=b; } struct custom_error_mgr { struct jpeg_error_mgr lib; jmp_buf jump_buffer; }; void customJpegExit(j_common_ptr cinfo){ struct custom_error_mgr *cerr=(struct custom_error_mgr *) cinfo->err; char *msg; if(LastJpegErrorString!=NULL){ free(LastJpegErrorString); LastJpegErrorString=NULL; } msg=malloc(JMSG_LENGTH_MAX); if(msg!=NULL){ (*cerr->lib.format_message)(cinfo,msg); LastJpegErrorString=msg; } longjmp(cerr->jump_buffer,1); } int saveJPEGImage(char *filename,IMAGE *image, int *error){ struct jpeg_compress_struct cinfo; struct custom_error_mgr cerr; FILE *file; JSAMPLE *scanline; int i,j; /*NB If we knew that the input image was greyscale we could write a greyscale image here. Something to consider later.*/ file=fopen(filename,"wb"); if(file==NULL){ *error=IMAGE_E_FILE; return 0; } cinfo.err=jpeg_std_error((struct jpeg_error_mgr *)&cerr); cerr.lib.error_exit=&customJpegExit; if(setjmp(cerr.jump_buffer)!=0){ if(scanline!=NULL) free(scanline); fclose(file); jpeg_abort_compress(&cinfo); jpeg_destroy_compress(&cinfo); *error=IMAGE_E_DECODE; return 0; } jpeg_create_compress(&cinfo); jpeg_stdio_dest(&cinfo,file); cinfo.image_width=cinfo.image_width=imageWidth(image); cinfo.image_height=cinfo.image_height=imageHeight(image); cinfo.input_components=3; cinfo.in_color_space=JCS_RGB; jpeg_set_defaults(&cinfo); jpeg_start_compress(&cinfo,TRUE); scanline=malloc(sizeof(JSAMPLE)*3*imageWidth(image)); if(scanline==NULL){ // deleteImage(image); jpeg_abort_compress(&cinfo); jpeg_destroy_compress(&cinfo); fclose(file); *error=IMAGE_E_MEMORY; return 0; } while(cinfo.next_scanline<cinfo.image_height){ /*Transcode from 32 bit to 24bit.*/ #if 0 if(cinfo.output_components==1){ for(j=0;j<cinfo.image_width;j++) /*This feels quite slow.*/ setPixel(image,i,j,scanline[j],scanline[j],scanline[j]); } else { #endif /*Assume rgb.*/ for(j=0;j<cinfo.image_width;j++){ /*This feels quite slow.*/ scanline[j*3]=getRed(image,cinfo.next_scanline,j); scanline[j*3+1]=getGreen(image,cinfo.next_scanline,j); scanline[j*3+2]=getBlue(image,cinfo.next_scanline,j); } #if 0 } #endif jpeg_write_scanlines(&cinfo,&scanline,1); } jpeg_finish_compress(&cinfo); jpeg_destroy_compress(&cinfo); fclose(file); free(scanline); *error=IMAGE_E_OK; return 1; } IMAGE *loadJPEGImage(char *filename, int *error){ IMAGE *image=NULL; struct jpeg_decompress_struct cinfo; struct custom_error_mgr cerr; FILE *file; JSAMPLE *scanline=NULL; int i,j; file=fopen(filename,"rb"); if(file==NULL){ *error=IMAGE_E_FILE; return NULL; } cinfo.err=jpeg_std_error((struct jpeg_error_mgr *)&cerr); cerr.lib.error_exit=&customJpegExit; if(setjmp(cerr.jump_buffer)!=0){ if(image!=NULL) deleteImage(image); if(scanline!=NULL) free(scanline); fclose(file); jpeg_abort_decompress(&cinfo); jpeg_destroy_decompress(&cinfo); *error=IMAGE_E_DECODE; return NULL; } jpeg_create_decompress(&cinfo); jpeg_stdio_src(&cinfo,file); jpeg_read_header(&cinfo,TRUE); image=newImage(cinfo.image_width,cinfo.image_height,error); if(image==NULL){ jpeg_abort_decompress(&cinfo); jpeg_destroy_decompress(&cinfo); fclose(file); return NULL; } jpeg_start_decompress(&cinfo); scanline=malloc(sizeof(JSAMPLE)*cinfo.image_width*cinfo.output_components); if(scanline==NULL){ deleteImage(image); jpeg_abort_decompress(&cinfo); jpeg_destroy_decompress(&cinfo); fclose(file); *error=IMAGE_E_MEMORY; return NULL; } i=0; do { if(jpeg_read_scanlines(&cinfo,&scanline,1)>0){ /*Transcode from 24 bit to 32bit.*/ if(cinfo.output_components==1){ for(j=0;j<cinfo.image_width;j++) /*This feels quite slow.*/ setPixel(image,i,j,scanline[j],scanline[j],scanline[j]); } else { /*Assume rgb.*/ for(j=0;j<cinfo.image_width;j++) /*This feels quite slow.*/ setPixel(image,i,j,scanline[j*3],scanline[j*3+1],scanline[j*3+2]); } i++; } } while(i<cinfo.output_height); jpeg_finish_decompress(&cinfo); jpeg_destroy_decompress(&cinfo); fclose(file); free(scanline); *error=IMAGE_E_OK; return image; } IMAGE *loadTIFFImage(char *filename, int *error){ IMAGE *image; TIFF *tif; int width,height; int i,j,k,x; int z; FILE *temp; /*First try to open the file with the TIFF library*/ tif=TIFFOpen(filename,"r"); if(tif==NULL){ if(error!=NULL) *error=IMAGE_E_FILE; return NULL; } /*Next, obtain the width and height*/ TIFFGetField(tif,TIFFTAG_IMAGEWIDTH,&width); TIFFGetField(tif,TIFFTAG_IMAGELENGTH,&height); /*Grab an IMAGE ADT to hold the image. Now I'm going to be a bit sneaky here: the TIFF library will read in a pixel map with each pixel represented by a single 32 bit number, divided into byte-size fields. I will then want to unshuffle these values to create three planes of consecutive bytes. This is a bit messy memory-wise, but it lets the ADTs work happily, and I don't feel like delving too far into the TIFF library at the moment. Lets go.*/ image=newImage(width,height,error); /*4 bands, R, G, B and alpha*/ if(image==NULL){ TIFFClose(tif); return NULL; } /*And if all that went OK, we can try to load the image. The TIFF library has a function to do this in one go. This function might be only available in newer versions, though. Perhaps it would be wise to do it using a row-oriented version sometime.*/ if(!TIFFReadRGBAImageOriented(tif,width,height,(uint32 *)image->pixels,ORIENTATION_TOPLEFT,1)){ deleteImage(image); TIFFClose(tif); if(error!=NULL) *error=IMAGE_E_DECODE; return NULL; } /*And we're done*/ TIFFClose(tif); if(error!=NULL) *error=IMAGE_E_OK; return image; } /*This, and saveImage below, should probably also take an optional explicit type to override the guessing. Or maybe I should just export the various loadXXXXImage functions for that purpose. Something to think about.*/ IMAGE *loadImage(char *name,int *error){ int len; char *dotptr; if(LastJpegErrorString!=NULL){ free(LastJpegErrorString); LastJpegErrorString=NULL; } /*Guess the file type from the extension. Perhaps in future we could also try magic number detection.*/ dotptr=strrchr(name,'.'); if((dotptr!=NULL)&&(strcasecmp(dotptr,".tif")==0)) return loadTIFFImage(name,error); else if((dotptr!=NULL)&&((strcasecmp(dotptr,".jpg")==0)||(strcasecmp(dotptr,".jpeg")==0))) return loadJPEGImage(name,error); else { *error=IMAGE_E_DECODE; //could do with a better error code here. More specific. return NULL; } } /*saveImage produces an image file on disk corresponding to the given image. The image must have a known structure (eg RGB). The file will be saved in portable pixmap (PPM) format. Returns nonzero on success, zero on error. If error is non-NULL then an error value is returned in *error.*/ int savePPMImage(char *name, IMAGE *image,int *error){ int i,j; FILE *temp; temp=fopen(name,"w"); if(temp==NULL){ if(error!=NULL) *error=IMAGE_E_IO; return 0; } fprintf(temp,"P6\n%d\n%d\n255\n",imageCols(image),imageRows(image)); for(i=0;i<imageRows(image);i++){ for(j=0;j<imageCols(image);j++){ fputc(getRed(image,i,j),temp); fputc(getGreen(image,i,j),temp); fputc(getBlue(image,i,j),temp); } } if(ferror(temp)){ if(error!=NULL) *error=IMAGE_E_IO; fclose(temp); return 0; } fclose(temp); if(error!=NULL) *error=IMAGE_E_OK; return 1; } /*outputImage produces an image file on disk corresponding to the given image. The image must have a known structure (eg RGB). The file will be saved in portable pixmap (PPM) format. Returns nonzero on success, zero on error. If error is non-NULL then an error value is returned in *error.*/ int saveTIFFImage(char *name, IMAGE *image,int *error){ int s,i,j,b; TIFF *temp; unsigned char *strip; strip=malloc(imageCols(image)*10*3); if(strip==NULL){ if(error!=NULL) *error=IMAGE_E_MEMORY; return 0; } temp=TIFFOpen(name,"w"); if(temp==NULL){ free(strip); if(error!=NULL) *error=IMAGE_E_IO; return 0; } TIFFSetField(temp,TIFFTAG_PHOTOMETRIC,2); TIFFSetField(temp,TIFFTAG_COMPRESSION,32773); TIFFSetField(temp,TIFFTAG_PLANARCONFIG,1); TIFFSetField(temp,TIFFTAG_IMAGELENGTH,imageRows(image)); TIFFSetField(temp,TIFFTAG_IMAGEWIDTH,imageCols(image)); TIFFSetField(temp,TIFFTAG_ROWSPERSTRIP,10); TIFFSetField(temp,TIFFTAG_XRESOLUTION,1.0); TIFFSetField(temp,TIFFTAG_YRESOLUTION,1.0); TIFFSetField(temp,TIFFTAG_RESOLUTIONUNIT,1); TIFFSetField(temp,TIFFTAG_BITSPERSAMPLE,8,8,8); TIFFSetField(temp,TIFFTAG_SAMPLESPERPIXEL,3); /*That sets up the file. Now go through and compose the strips as we go.*/ for(s=0;s<imageRows(image);s+=10){ b=0; for(i=0;i<MIN(10,imageRows(image)-s);i++){ for(j=0;j<imageCols(image);j++){ strip[b++]=getRed(image,s+i,j); strip[b++]=getGreen(image,s+i,j); strip[b++]=getBlue(image,s+i,j); } } TIFFWriteEncodedStrip(temp,s/10,strip,imageCols(image)*10*3); } TIFFClose(temp); free(strip); if(error!=NULL) *error=IMAGE_E_OK; return 1; } int saveImage(char *name, IMAGE *image,int *error){ char *dotptr; int len; if(LastJpegErrorString!=NULL){ free(LastJpegErrorString); LastJpegErrorString=NULL; } /*Guess the file type from the extension. Perhaps in future we could also try magic number detection.*/ dotptr=strrchr(name,'.'); if((dotptr!=NULL)&&(strcasecmp(dotptr,".tif")==0)) return saveTIFFImage(name,image,error); else if((dotptr!=NULL)&&((strcasecmp(dotptr,".jpg")==0)||(strcasecmp(dotptr,".jpeg")==0))) return saveJPEGImage(name,image,error); else { *error=IMAGE_E_DECODE; //could do with a better error code here. More specific. return 0; } } char *lastImageErrorString(void){ return LastJpegErrorString; }
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor