///////////////////////////////////////////////////////////////////////////// // Rev 11/12/2003 // // // JPEG2JPEG.C // ----------- // // // Sylvain MARECHAL - sylvain.marechal1@libertysurf.fr ///////////////////////////////////////////////////////////////////////////// // // Convert a jpeg file to another jpeg file // Quality and width can be specified // should be linked with : // -the jpeglib-6b (http://www.ijg.org/) // -dcpjpeg.c // // Usage : // jpeg2jpeg // // // // // ///////////////////////////////////////////////////////////////////////////// #ifdef _WIN32 #include #else #define O_BINARY 0 #endif #include #include #include #include #include #include #include "parcoursdir.h" #include "dcpjpeg.h" #include "jpeg2jpeg.h" // Structure utilisee pour la lecture typedef struct tagReadJpeg { int hFile; char *pBuffer; int cbBuffer; } ReadJpeg; // Structure pour l'ecriture typedef struct tagWriteJpeg { int hFile; } WriteJpeg; // Callbacks static int ReadJpegFile( void *, char ** ppBuffer, int * pcbBuffer ); static int WriteJpegFile( void *, char * pBuffer, int cbBuffer ); static void ErrorMessage( void *, char * pszBuffer ); #define MAIN #ifdef MAIN // The test program int main( int argc, char * argv[] ) { if( argc < 4 ) { printf( "Usage : %s \n" ); return 1; } Jpeg2Jpeg( argv[1], argv[2], atoi(argv[3]), atoi(argv[4]) ); return 0; } #endif ///////////////////////////////////////////////////////////////////////////// // // JPEG2JPEG ///////////////////////////////////////////////////////////////////////////// // // DESCRIPTION // --Jpeg2Jpeg-- // // Utilisation des structures DcpJpeg et CpJpeg. // On decompresse 1 jpeg puis on le recompresse a la // volee en changeant la qualite et l'echelle // // ARGUMENTS // Argument1: char *pszFileSource // Argument2: char *pszFileDest // Argument3: int nWidth // Argument4: int nQuality // RETOUR/RESULTAT // void // REMARQUE // Rev 11/12/2003 ////////////////////////////////////////////////////////////////////////////// void Jpeg2Jpeg( char *pszFileSource, char *pszFileDest, int nWidth, int nQuality ) { int fFirst = TRUE; ReadJpeg rj; WriteJpeg wj; DcpJpeg * pDcpJpeg = DcpJpegInit( ReadJpegFile, (void * )&rj, ErrorMessage ); CpJpeg * pCpJpeg = CpJpegInit( WriteJpegFile, (void * )&wj, ErrorMessage ); // Changement d'echelle if( nWidth > 0 ) DcpJpegInitScale( pDcpJpeg, 0, 0, nWidth ); rj.pBuffer = (char *)malloc(1024); rj.cbBuffer = 1024; if( ! rj.pBuffer ) { DcpJpegDestroy( pDcpJpeg ); CpJpegDestroy( pCpJpeg ); return; } /* Fichier source */ rj.hFile = open( pszFileSource, O_RDONLY | O_BINARY, 0666 ); if( rj.hFile == -1 ) { DcpJpegDestroy( pDcpJpeg ); CpJpegDestroy( pCpJpeg ); return; } /* Fichier de destination : Si NULL, Sortie standard */ if( pszFileDest == NULL ) { wj.hFile = 1; #ifdef _WIN32 _setmode ( 1, O_BINARY ); #endif } else { wj.hFile = open( pszFileDest, O_CREAT | O_TRUNC | O_BINARY | O_RDWR , 0666 ); if( wj.hFile == -1 ) { close( rj.hFile ); DcpJpegDestroy( pDcpJpeg ); CpJpegDestroy( pCpJpeg ); return; } } /* Ecriture ds fichier de destination */ for(;;) { int err; char *pDecompress; int cbDecompress; err = DcpJpegDecode( pDcpJpeg, &pDecompress, &cbDecompress ); if( cbDecompress > 0 ) { if( fFirst ) { unsigned int image_width; unsigned int image_height; int input_components; int in_color_space; DcpJpegGetParam( pDcpJpeg, &image_width, &image_height, &input_components, &in_color_space ); CpJpegSetParam( pCpJpeg, image_width, image_height, input_components, in_color_space, nQuality ); fFirst = FALSE; } CpJpegEncode( pCpJpeg, pDecompress, cbDecompress ); } if( err < 0 ) break; } /* Liberation memoire et fermeture fichiers */ DcpJpegDestroy( pDcpJpeg ); CpJpegDestroy( pCpJpeg ); close( rj.hFile ); free( rj.pBuffer ); if( wj.hFile != 1 ) close( wj.hFile ); } ///////////////////////////////////////////////////////////////////////////// // // READJPEGFILE ///////////////////////////////////////////////////////////////////////////// // // DESCRIPTION // --ReadJpegFile-- // ARGUMENTS // Argument1: void * lParam // Argument2: char **ppBuffer // Argument3: int *pcbBuffer // RETOUR/RESULTAT // int // REMARQUE // Rev 11/12/2003 ////////////////////////////////////////////////////////////////////////////// int ReadJpegFile( void * lParam, char **ppBuffer, int *pcbBuffer ) { ReadJpeg *prj = (ReadJpeg *)lParam; int nRet; nRet = read( prj->hFile, prj->pBuffer, prj->cbBuffer ); *ppBuffer = (nRet <= 0 ? NULL : prj->pBuffer); *pcbBuffer = (nRet <= 0 ? 0 : nRet); if( nRet <= 0 ) { nRet = -1; } return nRet; } ///////////////////////////////////////////////////////////////////////////// // // WRITEJPEGFILE ///////////////////////////////////////////////////////////////////////////// // // DESCRIPTION // --WriteJpegFile-- // // Ecriture dans fichier de destination // // ARGUMENTS // Argument1: void * lParam // Argument2: char * pBuffer // Argument3: int cbBuffer // RETOUR/RESULTAT // int // REMARQUE // Rev 11/12/2003 ////////////////////////////////////////////////////////////////////////////// int WriteJpegFile( void * lParam, char * pBuffer, int cbBuffer ) { WriteJpeg *pwj = (WriteJpeg*)lParam; write( pwj->hFile, pBuffer, cbBuffer ); return 0; } /*--------------------------------------------------------------------------- ** ERRORMESSAGE **--------------------------------------------------------------------------- ** --ErrorMessage-- ** ** La fonction pour afficher les erreurs ** ** Rev 17/04/2000 **--------------------------------------------------------------------------*/ void ErrorMessage( void * lParam, char * pszBuffer ) { //printf( pszBuffer ); } /**********************************************************************/ /* GROS COPIER-COLLER depuis example.c pour recuperer les dimensions d'un jpeg */ /* Here's the extended error handler struct: */ struct my_error_mgr { struct jpeg_error_mgr pub; /* "public" fields */ jmp_buf setjmp_buffer; /* for return to caller */ }; typedef struct my_error_mgr * my_error_ptr; /* * Here's the routine that will replace the standard error_exit method: */ METHODDEF(void) my_error_exit (j_common_ptr cinfo) { /* cinfo->err really points to a my_error_mgr struct, so coerce pointer */ my_error_ptr myerr = (my_error_ptr) cinfo->err; /* Always display the message. */ /* We could postpone this until after returning, if we chose. */ (*cinfo->err->output_message) (cinfo); /* Return control to the setjmp point */ longjmp(myerr->setjmp_buffer, 1); } ///////////////////////////////////////////////////////////////////////////// // // GETJPEGSIZE ///////////////////////////////////////////////////////////////////////////// // // DESCRIPTION // --GetJpegSize-- // // Recuperation de la taille de l'image Jpeg // // // ARGUMENTS // Argument1: char * filename [IN] File // Argument2: int * pWidth [OUT] Width // Argument3: int * pHeight [OUT] Height // RETOUR/RESULTAT // int // REMARQUE // Rev 11/12/2003 ////////////////////////////////////////////////////////////////////////////// int GetJpegSize(char * filename, int * pWidth, int * pHeight ) { /* This struct contains the JPEG decompression parameters and pointers to * working space (which is allocated as needed by the JPEG library). */ struct jpeg_decompress_struct cinfo; /* We use our private extension JPEG error handler. * Note that this struct must live as long as the main JPEG parameter * struct, to avoid dangling-pointer problems. */ struct my_error_mgr jerr; /* More stuff */ FILE * infile; /* source file */ #if 0 JSAMPARRAY buffer; /* Output row buffer */ int row_stride; /* physical row width in output buffer */ #endif /* In this example we want to open the input file before doing anything else, * so that the setjmp() error recovery below can assume the file is open. * VERY IMPORTANT: use "b" option to fopen() if you are on a machine that * requires it in order to read binary files. */ if ((infile = fopen(filename, "rb")) == NULL) { fprintf(stderr, "can't open %s\n", filename); return 0; } /* Step 1: allocate and initialize JPEG decompression object */ /* We set up the normal JPEG error routines, then override error_exit. */ cinfo.err = jpeg_std_error(&jerr.pub); jerr.pub.error_exit = my_error_exit; /* Establish the setjmp return context for my_error_exit to use. */ if (setjmp(jerr.setjmp_buffer)) { /* If we get here, the JPEG code has signaled an error. * We need to clean up the JPEG object, close the input file, and return. */ jpeg_destroy_decompress(&cinfo); fclose(infile); return 0; } /* Now we can initialize the JPEG decompression object. */ jpeg_create_decompress(&cinfo); /* Step 2: specify data source (eg, a file) */ jpeg_stdio_src(&cinfo, infile); /* Step 3: read file parameters with jpeg_read_header() */ (void) jpeg_read_header(&cinfo, TRUE); /* We can ignore the return value from jpeg_read_header since * (a) suspension is not possible with the stdio data source, and * (b) we passed TRUE to reject a tables-only JPEG file as an error. * See libjpeg.doc for more info. */ /* On veut juste la taille ... */ *pWidth = cinfo.image_width; *pHeight = cinfo.image_height; #if 0 /* Step 4: set parameters for decompression */ /* In this example, we don't need to change any of the defaults set by * jpeg_read_header(), so we do nothing here. */ /* Step 5: Start decompressor */ (void) jpeg_start_decompress(&cinfo); /* We can ignore the return value since suspension is not possible * with the stdio data source. */ /* We may need to do some setup of our own at this point before reading * the data. After jpeg_start_decompress() we have the correct scaled * output image dimensions available, as well as the output colormap * if we asked for color quantization. * In this example, we need to make an output work buffer of the right size. */ /* JSAMPLEs per row in output buffer */ row_stride = cinfo.output_width * cinfo.output_components; /* Make a one-row-high sample array that will go away when done with image */ buffer = (*cinfo.mem->alloc_sarray) ((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1); /* Step 6: while (scan lines remain to be read) */ /* jpeg_read_scanlines(...); */ /* Here we use the library's state variable cinfo.output_scanline as the * loop counter, so that we don't have to keep track ourselves. */ while (cinfo.output_scanline < cinfo.output_height) { /* jpeg_read_scanlines expects an array of pointers to scanlines. * Here the array is only one element long, but you could ask for * more than one scanline at a time if that's more convenient. */ (void) jpeg_read_scanlines(&cinfo, buffer, 1); /* Assume put_scanline_someplace wants a pointer and sample count. */ put_scanline_someplace(buffer[0], row_stride); } /* Step 7: Finish decompression */ (void) jpeg_finish_decompress(&cinfo); /* We can ignore the return value since suspension is not possible * with the stdio data source. */ /* Step 8: Release JPEG decompression object */ /* This is an important step since it will release a good deal of memory. */ jpeg_destroy_decompress(&cinfo); #endif /*0*/ /* After finish_decompress, we can close the input file. * Here we postpone it until after no more JPEG errors are possible, * so as to simplify the setjmp error logic above. (Actually, I don't * think that jpeg_destroy can do an error exit, but why assume anything...) */ fclose(infile); /* At this point you may want to check to see whether any corrupt-data * warnings occurred (test whether jerr.pub.num_warnings is nonzero). */ /* And we're done! */ return 1; }