// ---------------------------------------------------------------------------- // MODULE : CompressorJPEG.cpp // LANGUAGE : C++ // CREATOR : Yue Zhang // CREAT. DATE : Monday, March 25, 1996 // DESCRIPTION : // COMMENTS : // SCCSID : @(#)cp_jpeg.cpp 1.2 12:41:07 08 Jul 1997 // ---------------------------------------------------------------------------- // Copyright (c) 1999 Digital Imaging Group, Inc. // For conditions of distribution and use, see copyright notice // in Flashpix.h // ---------------------------------------------------------------------------- #ifdef macintosh #pragma segment CompressorJPEG #endif // ---------------------------------------------------------------------------- // ---------------------------------------------------------------------------- // Includes // -------- #include "debug.h" #include "common.h" #ifndef Memoire_h #include "b_memory.h" #endif #ifndef FlashPixUtils_h #include "fpxutils.h" #endif #include "ejpeg.h" // CHG_FILE_ERR - needed for error code mapping #include "cp_jpeg.h" // Constants // --------- // Variables // --------- // ---------------------------------------------------------------------------- // Internal Functions // ---------------------------------------------------------------------------- // ---------------------------------------------------------------------------- // Member Functions // ---------------------------------------------------------------------------- PCompressorJPEG::PCompressorJPEG () { int status = FPX_OK; // CHG_FILE_ERR - init to no error // At the begining, there is no encoder and decoder compresseurPresent = decompresseurPresent = FALSE; // At the begining, there is no header for encoder and decoder encoderHeaderPresent = decoderHeaderPresent = FALSE; // Initialize header size headerSize = 0; // At the begining, data buffer is not allocated dataBuffer = NULL; sizeOfBuffer = 0; // Assume pixel is 24-bit bytesPerPixel = 3; // Initialize compression options qualityFactor = 20; interleaveType = 0; chromaSubSample = 0; internalColorConv = 0; // Create a encoder status = eJPEG_Init((void**)&pEncoder); if ( !status ) { eJPEG_CreateHeader(pEncoder, DEFAULTJPEGHEADERSIZE, jpegHeader, (long *)&headerSize); compresseurPresent = TRUE; } // Create a decoder status = dJPEG_DecoderInit((void**)&pDecoder); if ( !status ) { decompresseurPresent = TRUE; dJPEG_DecodeTileHeader(jpegHeader, headerSize, pDecoder, CHEN_DCT); } } PCompressorJPEG::~PCompressorJPEG() { // Delete data buffer if it exists if ( dataBuffer ) delete[] dataBuffer; // Delete encoder and decoder if exist if ( compresseurPresent ) eJPEG_Shutdown(pEncoder); if ( decompresseurPresent ) dJPEG_DecoderFree(pDecoder, TRUE); } // Set parameters for jpeg compression. int PCompressorJPEG::SetCompressionParameters( unsigned char theInterleaveType, unsigned char theChromaSubSample, unsigned char theInternalColorConv, long compressionSubtype, unsigned char theQualityFactor, unsigned short theBytesPerPixel, unsigned char* theJpedHeader, unsigned long theHeaderSize, Boolean selector) { int status = FPX_OK; // CHG_FILE_ERR - init to no error // For encoder we use internal header, so headerSize is zero if ( selector ) { interleaveType = theInterleaveType; chromaSubSample = theChromaSubSample; internalColorConv = theInternalColorConv; bytesPerPixel = theBytesPerPixel; jpegTableIndex = GET_JPEGTablesIndex(compressionSubtype); // Create header for decoder memcpy(jpegHeader, theJpedHeader, theHeaderSize); headerSize = theHeaderSize; // Set subsampling option switch(chromaSubSample) { // no subsampling case 0: case 0x11: dJPEG_DisableUpsample(pDecoder); break; // 411 or 422 subsampling case 0x21: case 0x22: dJPEG_EnableUpsample(pDecoder); break; default: break; } // Set interleave type (1 for non-interleave and 0 for interleave) if ( interleaveType ) pDecoder->interleave_type = TRUE; else pDecoder->interleave_type = FALSE; // Set internal color conversion if ( !internalColorConv ) dJPEG_DisableColorConvert(pDecoder); else dJPEG_EnableColorConvert(pDecoder); // Set the tile size and number of channel status = dJPEG_SetTileSize(pDecoder, 64, 64, bytesPerPixel); if (status) return status; // Set jpeg subtype status = dJPEG_CopyJpegSubtype(pDecoder, compressionSubtype); decoderHeaderPresent = TRUE; } else if ( !encoderHeaderPresent || theQualityFactor != qualityFactor || theChromaSubSample != chromaSubSample || theInternalColorConv != internalColorConv || theBytesPerPixel != bytesPerPixel ) { // Set new compression options interleaveType = theInterleaveType; chromaSubSample = theChromaSubSample; internalColorConv = theInternalColorConv; bytesPerPixel = theBytesPerPixel; jpegTableIndex = GET_JPEGTablesIndex(compressionSubtype); // Set new quality factor qualityFactor = theQualityFactor; status = eJPEG_SetQFactor(pEncoder, qualityFactor); if (status) return status; // Set subsampling option switch(chromaSubSample) { // no subsampling case 0: case 0x11: { status = eJPEG_DisableInternalSubsampling(pEncoder); if (status) return status; break; } // 411 or 422 subsampling case 0x21: case 0x22: { status = eJPEG_SetSubsampling(pEncoder, chromaSubSample); if (status) return status; pEncoder->ssDisabled = FALSE; break; } default: break; } // Set interleave type ( 0 for interleave and 1 for non_interleave) if ( !interleaveType ) { status = eJPEG_EnableChannelInterleave(pEncoder); if (status) return status; } else { status = eJPEG_DisableChannelInterleave(pEncoder); if (status) return status; } // Set internal color conversion ( 0 for no color conversion and 1 for yes) if ( !internalColorConv ) { status = eJPEG_DisableInternalYCbCr(pEncoder); if (status) return status; } else { status = eJPEG_EnableInternalYCbCr(pEncoder); if (status) return status; } // Set the tile size and number of channel status = eJPEG_SetTileSize(pEncoder, 64, 64, bytesPerPixel); if (status) return status; // Create a jpeg header if ( jpegTableIndex ) status = eJPEG_CreateHeader(pEncoder, DEFAULTJPEGHEADERSIZE, jpegHeader, (long *)&headerSize); else status = eJPEG_ConcatenateHeader(pEncoder, jpegHeader, (long *)&headerSize); if (status) return status; encoderHeaderPresent = TRUE; } return status; } // Compress the data. Return false if error. int PCompressorJPEG::Compress(unsigned char * uncompressedData, short width, short height, unsigned char ** pcompressedData, long* sizeCompressed) { int status = FPX_OK; // CHG_FILE_ERR - init to no error register long numberofpixel = width * height; register long buflen = numberofpixel * bytesPerPixel; // Verify the parameters assert(uncompressedData != NULL); // Set the tile size and number of channel status = eJPEG_SetTileSize(pEncoder, width, height, bytesPerPixel); if (status) return status; // Allocate two data buffers if ( !AllocBuffer( buflen + DEFAULTJPEGHEADERSIZE ) ) return eJPEG_MEMORY_ERROR; // Perform JPEG compression *sizeCompressed = eJPEG_EncodeTile(pEncoder, uncompressedData, dataBuffer, buflen); // Set the compressed data buffer *pcompressedData = dataBuffer; if ( *sizeCompressed <= 0) status = eJPEG_MEMORY_ERROR; // CHG_FILE_ERR - inBuf was < outBuf in size return status; } // Decompress data. int PCompressorJPEG::Decompress(unsigned char* uncompressedData, short width, short height, unsigned char* compressedData, long sizeCompressed) { int status = FPX_OK; // CHG_FILE_ERR - init to no error register long numberofpixel = width * height; register long buflen = numberofpixel * bytesPerPixel; // Verify the parameters assert(uncompressedData != NULL); // Allocate the buffer for decompressed data if ( !AllocBuffer( buflen + DEFAULTJPEGHEADERSIZE ) ) return DJPEG_ERR_ALLOC_DECODER; // Set the tile size and number of channel status = dJPEG_SetTileSize(pDecoder, width, height, bytesPerPixel); if (status) return status; // Concatenate compressed data with header if jpeg table index is 0 if ( jpegTableIndex ) { memcpy(dataBuffer, jpegHeader, headerSize); memcpy(dataBuffer + headerSize, compressedData, sizeCompressed); // Perform JPEG decompression status = dJPEG_DecodeTile(uncompressedData, buflen, dataBuffer, sizeCompressed + headerSize, pDecoder, ENTROPY_AND_HEADER, WINOGRAD); } else { memcpy(dataBuffer, compressedData, sizeCompressed); // Perform JPEG decompression status = dJPEG_DecodeTile(uncompressedData, buflen, dataBuffer, sizeCompressed, pDecoder, ENTROPY_AND_HEADER, WINOGRAD); } // Perform JPEG decompression /*status = dJPEG_DecodeTile(uncompressedData, buflen, compressedData, sizeCompressed, pDecoder, ENTROPY_ONLY, WINOGRAD); */ dJPEG_DecoderFree(pDecoder, FALSE); return status; } // Allocate two buffers for compressor and decompressor Boolean PCompressorJPEG::AllocBuffer ( unsigned long size ) { // If the buffer previously allocated is too small if (size > sizeOfBuffer) { // Free the old buffer FastDeleteArray(dataBuffer, unsigned char); // Allocate the buffer FastAllocArray(dataBuffer, unsigned char, size); if ( dataBuffer ) { sizeOfBuffer = size; return TRUE; } else { sizeOfBuffer = 0; return FALSE; } } else return TRUE; } PCompressorSinColor::PCompressorSinColor () { // At the begining, data buffer is not allocated dataBufPresent = FALSE; // Set default channels to be 3 bytesPerPixel = 3; } PCompressorSinColor::~PCompressorSinColor() { // Delete data buffer if it exists if ( dataBufPresent ) delete dataBuffer; } void PCompressorSinColor::SetCompressionParameters(short numChannels) { bytesPerPixel = numChannels; } Boolean PCompressorSinColor::Compress(unsigned char * uncompressedData, short width, short height, unsigned char ** pcompressedData, long* sizeCompressed) { // Allocate the data buffer if it doesn't exist if ( !dataBufPresent ) { dataBuffer = new unsigned char[sizeof(Pixel)]; if (dataBuffer==NULL) { return FALSE; } dataBufPresent = TRUE; } if ( bytesPerPixel == 4 ) memcpy(dataBuffer, uncompressedData, bytesPerPixel); else memcpy(dataBuffer, uncompressedData + 1, bytesPerPixel); *pcompressedData = dataBuffer; // Set the compressed data size *sizeCompressed = bytesPerPixel; return TRUE; } Boolean PCompressorSinColor::Decompress(unsigned char* uncompressedData, short width, short height, unsigned char* compressedData, long sizeCompressed) { register long numberofpixel = width * height; unsigned char alphaValue = 0; if ( sizeCompressed == 4 ) { alphaValue = compressedData[0]; compressedData++; } // Rebuild the pixel buffer for ( register long i= 0; i< numberofpixel; i++ ) { uncompressedData[4*i] = alphaValue; uncompressedData[4*i + 1] = compressedData[0]; uncompressedData[4*i + 2] = compressedData[1]; uncompressedData[4*i + 3] = compressedData[2]; } return TRUE; } // ---------------------------------------------------------------------------- // External Functions // ---------------------------------------------------------------------------- // CHG_FILE_ERR - the following maps an error value returned by the JPEG subsystem // into a similar FPXStatus value. int jpegErrorToFPXerror( long djpegError) { FPXStatus err = FPX_INVALID_COMPRESSION_ERROR; switch( djpegError) { case eJPEG_NO_ERROR: // case DJPEG_NO_ERROR: err = FPX_OK; break; case DJPEG_ERR_ALLOC_DECODER: // These are errors from decoder err = FPX_MEMORY_ALLOCATION_FAILED; break; case DJPEG_ERR_BAD_INTERLEAVE: case DJPEG_ERR_BAD_SUBSAMPLE: err = FPX_INVALID_PIXEL_FORMAT; break; case DJPEG_ERR_BAD_COLOR_CONVERT: err = FPX_COLOR_CONVERSION_ERROR; break; case DJPEG_ERR_BAD_CHANNELS: break; case DJPEG_ERR_BAD_411: case DJPEG_ERR_BAD_422: break; case DJPEG_ERR_BAD_411CONVERT: case DJPEG_ERR_BAD_422CONVERT: case DJPEG_ERR_BAD_CONVERT: err = FPX_COLOR_CONVERSION_ERROR; break; case DJPEG_ERR_BAD_SWITCH: break; case DJPEG_ERR_BAD_4114: case DJPEG_ERR_BAD_4224: break; case DJPEG_ERR_BAD_4114CONVERT: case DJPEG_ERR_BAD_4224CONVERT: case DJPEG_ERR_BAD_111CONVERT: case DJPEG_ERR_BAD_1111CONVERT: err = FPX_COLOR_CONVERSION_ERROR; break; case eJPEG_SUBSAMPLING_NOT_SUPPORTED: // These are errors from encoder break; case eJPEG_INVALID_ENCODER: break; case eJPEG_UNSUPPORTED_SUBSAMPLING: case eJPEG_UNSUPPORTED_BYTES_PER_PIXEL: err = FPX_INVALID_PIXEL_FORMAT; break; case eJPEG_MEMORY_ERROR: err = FPX_MEMORY_ALLOCATION_FAILED; break; case eJPEG_BAD_HUFFMAN_TABLE: case eJPEG_BAD_QUANT_TABLE: err = FPX_INVALID_JPEG_TABLE; break; case EJPEG_ERROR_PARSER: // These are errors from encoder break; case EJPEG_ERROR_MEM: err = FPX_MEMORY_ALLOCATION_FAILED; break; case EJPEG_ERROR_EOF: break; case EJPEG_ERROR_FORMAT: err =FPX_INVALID_FORMAT_ERROR; break; } return err; } // - EOF ----------------------------------------------------------------------