// part of this being separated allows for us to play nicely with the setjmp of libpng bool ImageSourcePng::loadHeader() { bool success = true; if( setjmp( png_jmpbuf(mPngPtr) ) ) { success = false; } else { png_read_info( mPngPtr, mInfoPtr ); png_uint_32 width, height; int bitDepth, colorType, interlaceType, compressionType, filterMethod; if( ! png_get_IHDR( mPngPtr, mInfoPtr, &width, &height, &bitDepth, &colorType, &interlaceType, &compressionType, &filterMethod ) ) { png_destroy_read_struct( &mPngPtr, &mInfoPtr, (png_infopp)NULL ); mPngPtr = 0; return false; } setSize( width, height ); setDataType( ( bitDepth == 16 ) ? ImageIo::UINT16 : ImageIo::UINT8 ); #ifdef CINDER_LITTLE_ENDIAN png_set_swap( mPngPtr ); #endif switch( colorType ) { case PNG_COLOR_TYPE_GRAY: setColorModel( ImageIo::CM_GRAY ); setChannelOrder( ImageIo::Y ); break; case PNG_COLOR_TYPE_GRAY_ALPHA: setColorModel( ImageIo::CM_GRAY ); setChannelOrder( ImageIo::YA ); break; case PNG_COLOR_TYPE_RGB: case PNG_COLOR_TYPE_PALETTE: setColorModel( ImageIo::CM_RGB ); setChannelOrder( ImageIo::RGB ); break; case PNG_COLOR_TYPE_RGB_ALPHA: setColorModel( ImageIo::CM_RGB ); setChannelOrder( ImageIo::RGBA ); break; default: throw ImageSourcePngException( "Unexpected png color type." ); } png_set_expand_gray_1_2_4_to_8( mPngPtr ); png_set_palette_to_rgb( mPngPtr ); png_set_tRNS_to_alpha( mPngPtr ); png_read_update_info( mPngPtr, mInfoPtr ); } return success; }
ImageTargetGWorld::ImageTargetGWorld( ImageSourceRef imageSource ) : ImageTarget(), mGWorld( 0 ), mPixMap( 0 ) { setSize( (size_t)imageSource->getWidth(), (size_t)imageSource->getHeight() ); OSType formatType; // for now all we support is 8 bit RGBA setDataType( ImageIo::UINT8 ); formatType = k32ARGBPixelFormat; setChannelOrder( ImageIo::ARGB ); setColorModel( ImageIo::CM_RGB ); ::Rect boundsRect; boundsRect.left = boundsRect.top = 0; boundsRect.right = (short)imageSource->getWidth(); boundsRect.bottom = (short)imageSource->getHeight(); if( ::QTNewGWorld( &mGWorld, formatType, &boundsRect, NULL, NULL, 0 ) != noErr ) throw ImageIoException(); mPixMap = ::GetGWorldPixMap( mGWorld ); if( ! ::LockPixels( mPixMap ) ) { ::DisposeGWorld( mGWorld ); throw ImageIoException(); } #if defined( CINDER_MSW ) mData = reinterpret_cast<uint8_t*>( (**mPixMap).baseAddr ); mRowBytes = ( (**mPixMap).rowBytes ) & 0x3FFF; #else mData = reinterpret_cast<uint8_t*>( ::GetPixBaseAddr( mPixMap ) ); mRowBytes = ::GetPixRowBytes( mPixMap ); #endif }
ImageSourceChannel( const ChannelT<T> &channel ) : ImageSource() { mWidth = channel.getWidth(); mHeight = channel.getHeight(); setColorModel( ImageIo::CM_GRAY ); setChannelOrder( ImageIo::Y ); if( channel.getIncrement() != 1 ) setCustomPixelInc( channel.getIncrement() ); if( boost::is_same<T,uint8_t>::value ) { setDataType( ImageIo::UINT8 ); mChannel8u = *reinterpret_cast<const Channel8u*>( &channel ); // register reference to 'channel' } else if( boost::is_same<T,uint16_t>::value ) { setDataType( ImageIo::UINT16 ); mChannel16u = *reinterpret_cast<const Channel16u*>( &channel ); // register reference to 'channel' } else if( boost::is_same<T,float>::value ) { setDataType( ImageIo::FLOAT32 ); mChannel32f = *reinterpret_cast<const Channel32f*>( &channel ); // register reference to 'channel' } else throw; // this channel seems to be a type we've never met mRowBytes = channel.getRowBytes(); mData = reinterpret_cast<const uint8_t*>( channel.getData() ); }
ImageTargetCvPixelBuffer::ImageTargetCvPixelBuffer( ImageSourceRef imageSource, bool convertToYpCbCr ) : ImageTarget(), mPixelBufferRef( 0 ), mConvertToYpCbCr( convertToYpCbCr ) { setSize( (size_t)imageSource->getWidth(), (size_t)imageSource->getHeight() ); //http://developer.apple.com/mac/library/qa/qa2006/qa1501.html // if we're converting to YCbCr, we'll load all of the data as RGB in terms of ci::ImageIo // but we run color space conversion over it later in the finalize method OSType formatType; if( ! mConvertToYpCbCr ) { switch( imageSource->getDataType() ) { // for now all we support is 8 bit RGB(A) case ImageIo::UINT16: case ImageIo::FLOAT32: case ImageIo::UINT8: setDataType( ImageIo::UINT8 ); if( imageSource->hasAlpha () ) { formatType = k32ARGBPixelFormat; setChannelOrder( ImageIo::ARGB ); } else { formatType = k24RGBPixelFormat; setChannelOrder( ImageIo::RGB ); } setColorModel( ImageIo::CM_RGB ); break; default: throw ImageIoException(); } } else { formatType = 'v408';/*k4444YpCbCrA8PixelFormat;*/ setDataType( ImageIo::UINT8 ); setChannelOrder( ImageIo::RGBA ); setColorModel( ImageIo::CM_RGB ); } if( ::CVPixelBufferCreate( kCFAllocatorDefault, imageSource->getWidth(), imageSource->getHeight(), formatType, NULL, &mPixelBufferRef ) != kCVReturnSuccess ) throw ImageIoException(); if( ::CVPixelBufferLockBaseAddress( mPixelBufferRef, 0 ) != kCVReturnSuccess ) throw ImageIoException(); mData = reinterpret_cast<uint8_t*>( ::CVPixelBufferGetBaseAddress( mPixelBufferRef ) ); mRowBytes = ::CVPixelBufferGetBytesPerRow( mPixelBufferRef ); }
ImageSourceOpenNIUserMask( uint8_t *buffer, int w, int h, shared_ptr<UserTracker::Obj> ownerObj ) : ImageSource(), mData( buffer ), mOwnerObj( ownerObj ) { setSize( w, h ); setColorModel( ImageIo::CM_GRAY ); setChannelOrder( ImageIo::Y ); setDataType( ImageIo::UINT8 ); }
void ImageSourceFileRadiance::loadStream( IStreamRef stream ) { setDataType( ImageIo::FLOAT32 ); setColorModel( ImageIo::CM_RGB ); setChannelOrder( ImageIo::RGB ); char str[200]; stream->readData( str, 10 ); if( memcmp( str, "#?RADIANCE", 10 ) ) throw ImageSourceFileRadianceException( "Invalid header" ); stream->seekRelative( 1 ); char cmd[200]; int i = 0; char c = 0, oldc; while( true ) { oldc = c; stream->read( &c ); if( c == 0xa && oldc == 0xa ) break; cmd[i++] = c; } char resolution[200]; i = 0; while( true ) { stream->read( &c ); resolution[i++] = c; if( c == 0xa ) break; } int width, height; #if defined( CINDER_WINRT ) if( ! sscanf_s( resolution, "-Y %d +X %d", &height, &width ) ) #else if( ! sscanf( resolution, "-Y %d +X %d", &height, &width ) ) #endif throw ImageSourceFileRadianceException( "Unable to parse size" ); setSize( width, height ); mRgbData = std::unique_ptr<float[]>( new float[width * height * 3] ); std::unique_ptr<RgbePixel[]> scanline( new RgbePixel[width] ); // convert image float *cols = mRgbData.get(); for( int y = height - 1; y >= 0; y-- ) { if( ! decrunchScanline( scanline.get(), width, stream.get() ) ) break; workOnRgbeScanline( scanline.get(), width, cols ); cols += width * 3; } }
ImageTargetSurface<T>::ImageTargetSurface( SurfaceT<T> *aSurface ) : ImageTarget(), mSurface( aSurface ) { if( boost::is_same<T,float>::value ) setDataType( ImageIo::FLOAT32 ); else if( boost::is_same<T,uint16_t>::value ) setDataType( ImageIo::UINT16 ); else if( boost::is_same<T,uint8_t>::value ) setDataType( ImageIo::UINT8 ); else throw; // what is this? setColorModel( ImageIo::CM_RGB ); // set the target's ChannelT order based on the SurfaceT's switch ( mSurface->getChannelOrder().getCode() ) { case SurfaceChannelOrder::RGBA: setChannelOrder( ImageIo::RGBA ); break; case SurfaceChannelOrder::BGRA: setChannelOrder( ImageIo::BGRA ); break; case SurfaceChannelOrder::ARGB: setChannelOrder( ImageIo::ARGB ); break; case SurfaceChannelOrder::ABGR: setChannelOrder( ImageIo::ABGR ); break; case SurfaceChannelOrder::RGBX: setChannelOrder( ImageIo::RGBX ); break; case SurfaceChannelOrder::BGRX: setChannelOrder( ImageIo::BGRX ); break; case SurfaceChannelOrder::XRGB: setChannelOrder( ImageIo::XRGB ); break; case SurfaceChannelOrder::XBGR: setChannelOrder( ImageIo::XBGR ); break; case SurfaceChannelOrder::RGB: setChannelOrder( ImageIo::RGB ); break; case SurfaceChannelOrder::BGR: setChannelOrder( ImageIo::BGR ); break; default: setChannelOrder( ImageIo::CUSTOM ); // in case we don't find a match break; } }
ImageTargetFileTinyExr::ImageTargetFileTinyExr( DataTargetRef dataTarget, ImageSourceRef imageSource, ImageTarget::Options options, const std::string & /*extensionData*/ ) { if( ! dataTarget->providesFilePath() ) { throw ImageIoExceptionFailedWrite( "ImageTargetFileTinyExr only supports writing to files." ); } mFilePath = dataTarget->getFilePath(); setSize( imageSource->getWidth(), imageSource->getHeight() ); ImageIo::ColorModel cm = options.isColorModelDefault() ? imageSource->getColorModel() : options.getColorModel(); switch( cm ) { case ImageIo::ColorModel::CM_RGB: mNumComponents = ( imageSource->hasAlpha() ) ? 4 : 3; setColorModel( ImageIo::ColorModel::CM_RGB ); setChannelOrder( ( mNumComponents == 3 ) ? ImageIo::ChannelOrder::BGR : ImageIo::ChannelOrder::ABGR ); if( mNumComponents == 3 ) mChannelNames = { "G", "B", "R" }; else mChannelNames = { "A", "G", "B", "R" }; break; case ImageIo::ColorModel::CM_GRAY: mNumComponents = ( imageSource->hasAlpha() ) ? 2 : 1; setColorModel( ImageIo::ColorModel::CM_GRAY ); setChannelOrder( ( mNumComponents == 2 ) ? ImageIo::ChannelOrder::YA : ImageIo::ChannelOrder::Y ); if( mNumComponents == 2 ) mChannelNames = { "Y", "A" }; else mChannelNames = { "Y" }; break; default: throw ImageIoExceptionIllegalColorModel(); } // TODO: consider supporting half float and uint types as well setDataType( ImageIo::DataType::FLOAT32 ); mData.resize( mHeight * imageSource->getWidth() * mNumComponents ); }
ImageTargetFileStbImage::ImageTargetFileStbImage( DataTargetRef dataTarget, ImageSourceRef imageSource, ImageTarget::Options options, const std::string &extensionData ) { if( ! dataTarget->providesFilePath() ) { throw ImageIoExceptionFailedWrite( "ImageTargetFileStbImage only supports writing to files." ); } mFilePath = dataTarget->getFilePath(); setSize( imageSource->getWidth(), imageSource->getHeight() ); ImageIo::ColorModel cm = options.isColorModelDefault() ? imageSource->getColorModel() : options.getColorModel(); switch( cm ) { case ImageIo::ColorModel::CM_RGB: mNumComponents = ( imageSource->hasAlpha() ) ? 4 : 3; setColorModel( ImageIo::ColorModel::CM_RGB ); setChannelOrder( ( mNumComponents == 4 ) ? ImageIo::ChannelOrder::RGBA : ImageIo::ChannelOrder::RGB ); break; case ImageIo::ColorModel::CM_GRAY: mNumComponents = ( imageSource->hasAlpha() ) ? 2 : 1; setColorModel( ImageIo::ColorModel::CM_GRAY ); setChannelOrder( ( mNumComponents == 2 ) ? ImageIo::ChannelOrder::YA : ImageIo::ChannelOrder::Y ); break; default: throw ImageIoExceptionIllegalColorModel(); } mExtension = extensionData; if( mExtension == "hdr" ) { // Radiance files are always float* setDataType( ImageIo::DataType::FLOAT32 ); mRowBytes = mNumComponents * imageSource->getWidth() * sizeof(float); } else { setDataType( ImageIo::DataType::UINT8 ); mRowBytes = mNumComponents * imageSource->getWidth() * sizeof(float); } mData = std::unique_ptr<uint8_t[]>( new uint8_t[mWidth * mRowBytes] ); }
ImageTargetChannel( ChannelT<T> *channel ) : mChannel( channel ) { if( boost::is_same<T,float>::value ) setDataType( ImageIo::FLOAT32 ); else if( boost::is_same<T,uint16_t>::value ) setDataType( ImageIo::UINT16 ); else if( boost::is_same<T,uint8_t>::value ) setDataType( ImageIo::UINT8 ); else throw; // what is this? setColorModel( ImageIo::CM_GRAY ); setChannelOrder( ImageIo::Y ); }
ImageSourceSurface( const SurfaceT<T> &surface ) : ImageSource() { mWidth = surface.getWidth(); mHeight = surface.getHeight(); setColorModel( ImageIo::CM_RGB ); setChannelOrder( ImageIo::ChannelOrder( surface.getChannelOrder().getImageIoChannelOrder() ) ); if( boost::is_same<T,uint8_t>::value ) { setDataType( ImageIo::UINT8 ); mSurface8u = *reinterpret_cast<const Surface8u*>( &surface ); // register reference to 'surface' } else if( boost::is_same<T,uint16_t>::value ) { setDataType( ImageIo::UINT16 ); mSurface16u = *reinterpret_cast<const Surface16u*>( &surface ); // register reference to 'surface' } else if( boost::is_same<T,float>::value ) { setDataType( ImageIo::FLOAT32 ); mSurface32f = *reinterpret_cast<const Surface32f*>( &surface ); // register reference to 'surface' } else throw; // this surface seems to be a type we've never met mRowBytes = surface.getRowBytes(); mData = reinterpret_cast<const uint8_t*>( surface.getData() ); }
ImageSourceFileTinyExr::ImageSourceFileTinyExr( DataSourceRef dataSource, ImageSource::Options /*options*/ ) { mExrImage.reset( new EXRImage ); const char *error; InitEXRImage( mExrImage.get() ); int status = 0; if( dataSource->isFilePath() ) { status = ParseMultiChannelEXRHeaderFromFile( mExrImage.get(), dataSource->getFilePath().string().c_str(), &error ); if( status != 0 ) throw ImageIoExceptionFailedLoadTinyExr( string( "Failed to parse OpenEXR header; Error message: " ) + error ); status = LoadMultiChannelEXRFromFile( mExrImage.get(), dataSource->getFilePath().string().c_str(), &error ); if( status != 0 ) throw ImageIoExceptionFailedLoadTinyExr( string( "Failed to parse OpenEXR file; Error message: " ) + error ); } else { BufferRef buffer = dataSource->getBuffer(); status = ParseMultiChannelEXRHeaderFromMemory( mExrImage.get(), (const unsigned char*)buffer->getData(), &error ); if( status != 0 ) throw ImageIoExceptionFailedLoadTinyExr( string( "Failed to parse OpenEXR header; Error message: " ) + error ); status = LoadMultiChannelEXRFromMemory( mExrImage.get(), (const unsigned char*)buffer->getData(), &error ); if( status != 0 ) throw ImageIoExceptionFailedLoadTinyExr( string( "Failed to parse OpenEXR file; Error message: " ) + error ); } // verify that the channels are all the same size; currently we don't support variably sized channels int pixelType = mExrImage->pixel_types[0]; for( int c = 1; c < mExrImage->num_channels; ++c ) { if( pixelType != mExrImage->pixel_types[c] ) throw ImageIoExceptionFailedLoadTinyExr( "TinyExr: heterogneous channel data types not supported" ); } switch( pixelType ) { case TINYEXR_PIXELTYPE_HALF: setDataType( ImageIo::FLOAT16 ); break; case TINYEXR_PIXELTYPE_FLOAT: setDataType( ImageIo::FLOAT32 ); break; default: throw ImageIoExceptionFailedLoadTinyExr( "TinyExr: Unknown data type" ); break; } setSize( mExrImage->width, mExrImage->height ); switch( mExrImage->num_channels ) { case 3: setColorModel( ImageIo::CM_RGB ); setChannelOrder( ImageIo::ChannelOrder::RGB ); break; case 4: setColorModel( ImageIo::CM_RGB ); setChannelOrder( ImageIo::ChannelOrder::RGBA ); break; default: throw ImageIoExceptionFailedLoadTinyExr( "TinyExr: Unsupported number of channels (" + to_string( mExrImage->num_channels ) + ")" ); } }
void ImageTargetFileWic::setupPixelFormat( const GUID &guid ) { if( guid == GUID_WICPixelFormat24bppBGR ) { setChannelOrder( ImageIo::BGR ); setColorModel( ImageIo::CM_RGB ); setDataType( ImageIo::UINT8 ); } else if( guid == GUID_WICPixelFormat24bppRGB ) { setChannelOrder( ImageIo::RGB ); setColorModel( ImageIo::CM_RGB ); setDataType( ImageIo::UINT8 ); } else if( guid == GUID_WICPixelFormat32bppBGR ) { setChannelOrder( ImageIo::BGRX ); setColorModel( ImageIo::CM_RGB ); setDataType( ImageIo::UINT8 ); } else if( guid == GUID_WICPixelFormat32bppBGRA ) { setChannelOrder( ImageIo::BGRA ); setColorModel( ImageIo::CM_RGB ); setDataType( ImageIo::UINT8 ); } else if( guid == GUID_WICPixelFormat32bppPBGRA ) { setChannelOrder( ImageIo::BGRA ); setColorModel( ImageIo::CM_RGB ); setDataType( ImageIo::UINT8 );// mIsPremultipliedAlpha = true; } else if( guid == GUID_WICPixelFormat48bppRGB ) { setChannelOrder( ImageIo::RGB ); setColorModel( ImageIo::CM_RGB ); setDataType( ImageIo::UINT16 ); } else if( guid == GUID_WICPixelFormat64bppRGBA ) { setChannelOrder( ImageIo::RGBA ); setColorModel( ImageIo::CM_RGB ); setDataType( ImageIo::UINT16 ); } else if( guid == GUID_WICPixelFormat64bppPRGBA ) { setChannelOrder( ImageIo::RGBA ); setColorModel( ImageIo::CM_RGB ); setDataType( ImageIo::UINT16 ); // mIsPremultipliedAlpha = true; } else if( guid == GUID_WICPixelFormat128bppRGBFloat ) { setChannelOrder( ImageIo::RGB ); setColorModel( ImageIo::CM_RGB ); setDataType( ImageIo::FLOAT32 ); } else if( guid == GUID_WICPixelFormat8bppGray ) { setChannelOrder( ImageIo::Y ); setColorModel( ImageIo::CM_GRAY ); setDataType( ImageIo::UINT8 ); } else if( guid == GUID_WICPixelFormat16bppGray ) { setChannelOrder( ImageIo::Y ); setColorModel( ImageIo::CM_GRAY ); setDataType( ImageIo::UINT16 ); } else if( guid == GUID_WICPixelFormat32bppGrayFloat ) { setChannelOrder( ImageIo::Y ); setColorModel( ImageIo::CM_GRAY ); setDataType( ImageIo::FLOAT32 ); } else throw ImageIoExceptionFailedLoad(); int32_t bitsPerComponent; bool writingAlpha = hasAlpha(); bool isFloat = true; switch( getDataType() ) { case ImageIo::UINT8: bitsPerComponent = 8; isFloat = false; break; case ImageIo::UINT16: bitsPerComponent = 16; isFloat = false; break; default: bitsPerComponent = 32; isFloat = true; } uint8_t numChannels; switch( getColorModel() ) { case ImageIo::CM_GRAY: numChannels = ( writingAlpha ) ? 2 : 1; break; default: numChannels = ( writingAlpha ) ? 4 : 3; } int32_t bitsPerPixel = numChannels * bitsPerComponent; mRowBytes = ( mWidth * ( bitsPerPixel / 8 ) + 3 ) & ~3; return; }
HMMDquant::HMMDquant() : ColorHistogram() { setColorModel(Pixel::HMMD); // We set some pointless quantization just so that it adds up to 184 setColorQuantization(23,8,0,0); // Only two components participate in histogram }
// returns true if we need conversion bool ImageSourceFileWic::processFormat( const ::GUID &guid, ::GUID *convertGUID ) { if( ( guid == GUID_WICPixelFormat1bppIndexed ) || ( guid == GUID_WICPixelFormat2bppIndexed ) || ( guid == GUID_WICPixelFormat4bppIndexed ) || ( guid == GUID_WICPixelFormat8bppIndexed ) || ( guid == GUID_WICPixelFormat16bppBGR555 ) || ( guid == GUID_WICPixelFormat16bppBGR565 ) ) { setChannelOrder( ImageIo::RGB ); setColorModel( ImageIo::CM_RGB ); setDataType( ImageIo::UINT8 ); *convertGUID = GUID_WICPixelFormat24bppRGB; return true; } else if( guid == GUID_WICPixelFormat24bppBGR ) { setChannelOrder( ImageIo::BGR ); setColorModel( ImageIo::CM_RGB ); setDataType( ImageIo::UINT8 ); } else if( guid == GUID_WICPixelFormat24bppRGB ) { setChannelOrder( ImageIo::RGB ); setColorModel( ImageIo::CM_RGB ); setDataType( ImageIo::UINT8 ); } else if( guid == GUID_WICPixelFormat32bppBGR ) { setChannelOrder( ImageIo::BGRX ); setColorModel( ImageIo::CM_RGB ); setDataType( ImageIo::UINT8 ); } else if( guid == GUID_WICPixelFormat32bppBGRA ) { setChannelOrder( ImageIo::BGRA ); setColorModel( ImageIo::CM_RGB ); setDataType( ImageIo::UINT8 ); } else if( guid == GUID_WICPixelFormat32bppPBGRA ) { setChannelOrder( ImageIo::BGRA ); setColorModel( ImageIo::CM_RGB ); setDataType( ImageIo::UINT8 ); setPremultiplied( true ); } else if( guid == GUID_WICPixelFormat48bppRGB ) { setChannelOrder( ImageIo::RGB ); setColorModel( ImageIo::CM_RGB ); setDataType( ImageIo::UINT16 ); } else if( guid == GUID_WICPixelFormat64bppRGBA ) { setChannelOrder( ImageIo::RGBA ); setColorModel( ImageIo::CM_RGB ); setDataType( ImageIo::UINT16 ); } else if( guid == GUID_WICPixelFormat64bppPRGBA ) { setChannelOrder( ImageIo::RGBA ); setColorModel( ImageIo::CM_RGB ); setDataType( ImageIo::UINT16 ); setPremultiplied( true ); } else if( guid == GUID_WICPixelFormat128bppRGBFloat ) { setChannelOrder( ImageIo::RGB ); setColorModel( ImageIo::CM_RGB ); setDataType( ImageIo::FLOAT32 ); } else if( guid == GUID_WICPixelFormat8bppGray ) { setChannelOrder( ImageIo::Y ); setColorModel( ImageIo::CM_GRAY ); setDataType( ImageIo::UINT8 ); } else if( guid == GUID_WICPixelFormat16bppGray ) { setChannelOrder( ImageIo::Y ); setColorModel( ImageIo::CM_GRAY ); setDataType( ImageIo::UINT16 ); } else if( guid == GUID_WICPixelFormat32bppGrayFloat ) { setChannelOrder( ImageIo::Y ); setColorModel( ImageIo::CM_GRAY ); setDataType( ImageIo::FLOAT32 ); } return false; }
bool StAVImage::load(const StString& theFilePath, ImageType theImageType, uint8_t* theDataPtr, int theDataSize) { // reset current data StImage::nullify(); setState(); close(); myMetadata.clear(); switch(theImageType) { case ST_TYPE_PNG: case ST_TYPE_PNS: { myCodec = avcodec_find_decoder_by_name("png"); break; } case ST_TYPE_JPEG: case ST_TYPE_MPO: case ST_TYPE_JPS: { myCodec = avcodec_find_decoder_by_name("mjpeg"); break; } case ST_TYPE_EXR: { myCodec = avcodec_find_decoder_by_name("exr"); break; } case ST_TYPE_WEBP: case ST_TYPE_WEBPLL: { myCodec = avcodec_find_decoder_by_name("webp"); break; } default: { break; } } if(theImageType == ST_TYPE_NONE || (theDataPtr == NULL && !StFileNode::isFileExists(theFilePath))) { // open image file and detect its type, its could be non local file! #if(LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(53, 2, 0)) int avErrCode = avformat_open_input(&myFormatCtx, theFilePath.toCString(), myImageFormat, NULL); #else int avErrCode = av_open_input_file (&myFormatCtx, theFilePath.toCString(), myImageFormat, 0, NULL); #endif if(avErrCode != 0 || myFormatCtx->nb_streams < 1 || myFormatCtx->streams[0]->codec->codec_id == 0) { if(myFormatCtx != NULL) { #if(LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(53, 17, 0)) avformat_close_input(&myFormatCtx); #else av_close_input_file(myFormatCtx); myFormatCtx = NULL; #endif } #if(LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(53, 2, 0)) avErrCode = avformat_open_input(&myFormatCtx, theFilePath.toCString(), NULL, NULL); #else avErrCode = av_open_input_file(&myFormatCtx, theFilePath.toCString(), NULL, 0, NULL); #endif } if(avErrCode != 0 || myFormatCtx->nb_streams < 1) { setState(StString("AVFormat library, couldn't open image file. Error: ") + stAV::getAVErrorDescription(avErrCode)); close(); return false; } // find the decoder for the video stream myCodecCtx = myFormatCtx->streams[0]->codec; if(theImageType == ST_TYPE_NONE) { myCodec = avcodec_find_decoder(myCodecCtx->codec_id); } } if(myCodec == NULL) { setState("AVCodec library, video codec not found"); close(); return false; } else if(myFormatCtx == NULL) { // use given image type to load decoder #if(LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(53, 8, 0)) myCodecCtx = avcodec_alloc_context3(myCodec); #else myCodecCtx = avcodec_alloc_context(); #endif } // stupid check if(myCodecCtx == NULL) { setState("AVCodec library, codec context is NULL"); close(); return false; } // open VIDEO codec #if(LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(53, 8, 0)) if(avcodec_open2(myCodecCtx, myCodec, NULL) < 0) { #else if(avcodec_open(myCodecCtx, myCodec) < 0) { #endif setState("AVCodec library, could not open video codec"); close(); return false; } // read one packet or file StRawFile aRawFile(theFilePath); StAVPacket anAvPkt; if(theDataPtr != NULL && theDataSize != 0) { anAvPkt.getAVpkt()->data = theDataPtr; anAvPkt.getAVpkt()->size = theDataSize; } else { if(myFormatCtx != NULL) { if(av_read_frame(myFormatCtx, anAvPkt.getAVpkt()) < 0) { setState("AVFormat library, could not read first packet"); close(); return false; } } else { if(!aRawFile.readFile()) { setState("StAVImage, could not read the file"); close(); return false; } anAvPkt.getAVpkt()->data = (uint8_t* )aRawFile.getBuffer(); anAvPkt.getAVpkt()->size = (int )aRawFile.getSize(); } } anAvPkt.setKeyFrame(); // decode one frame int isFrameFinished = 0; #if(LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(52, 23, 0)) avcodec_decode_video2(myCodecCtx, myFrame.Frame, &isFrameFinished, anAvPkt.getAVpkt()); #else avcodec_decode_video(myCodecCtx, myFrame.Frame, &isFrameFinished, theDataPtr, theDataSize); #endif if(isFrameFinished == 0) { // thats not an image!!! try to decode more packets??? setState("AVCodec library, input file is not an Image!"); close(); return false; } // check frame size if(myCodecCtx->width <= 0 || myCodecCtx->height <= 0) { setState("AVCodec library, codec returns wrong frame size"); close(); return false; } // read aspect ratio if(myCodecCtx->sample_aspect_ratio.num == 0 || myCodecCtx->sample_aspect_ratio.den == 0) { setPixelRatio(1.0f); } else { const GLfloat aRatio = GLfloat(myCodecCtx->sample_aspect_ratio.num) / GLfloat(myCodecCtx->sample_aspect_ratio.den); if(aRatio > 70.0f) { ST_DEBUG_LOG("AVCodec library, igning wrong PAR " + myCodecCtx->sample_aspect_ratio.num + ":" + myCodecCtx->sample_aspect_ratio.den); setPixelRatio(1.0f); } else { setPixelRatio(aRatio); } } #ifdef ST_AV_NEWSTEREO // currently it is unlikelly... but maybe in future? AVFrameSideData* aSideData = av_frame_get_side_data(myFrame.Frame, AV_FRAME_DATA_STEREO3D); if(aSideData != NULL) { AVStereo3D* aStereo = (AVStereo3D* )aSideData->data; mySrcFormat = stAV::stereo3dAvToSt(aStereo->type); if(aStereo->flags & AV_STEREO3D_FLAG_INVERT) { mySrcFormat = st::formatReversed(mySrcFormat); } } else { mySrcFormat = StFormat_AUTO; } #endif // it is unlikely that there would be any metadata from format... // but lets try if(myFormatCtx != NULL) { for(stAV::meta::Tag* aTag = stAV::meta::findTag(myFormatCtx->metadata, "", NULL, stAV::meta::SEARCH_IGNORE_SUFFIX); aTag != NULL; aTag = stAV::meta::findTag(myFormatCtx->metadata, "", aTag, stAV::meta::SEARCH_IGNORE_SUFFIX)) { myMetadata.add(StDictEntry(aTag->key, aTag->value)); } for(stAV::meta::Tag* aTag = stAV::meta::findTag(myFormatCtx->streams[0]->metadata, "", NULL, stAV::meta::SEARCH_IGNORE_SUFFIX); aTag != NULL; aTag = stAV::meta::findTag(myFormatCtx->streams[0]->metadata, "", aTag, stAV::meta::SEARCH_IGNORE_SUFFIX)) { myMetadata.add(StDictEntry(aTag->key, aTag->value)); } } // collect metadata from the frame stAV::meta::Dict* aFrameMetadata = stAV::meta::getFrameMetadata(myFrame.Frame); for(stAV::meta::Tag* aTag = stAV::meta::findTag(aFrameMetadata, "", NULL, stAV::meta::SEARCH_IGNORE_SUFFIX); aTag != NULL; aTag = stAV::meta::findTag(aFrameMetadata, "", aTag, stAV::meta::SEARCH_IGNORE_SUFFIX)) { myMetadata.add(StDictEntry(aTag->key, aTag->value)); } stAV::dimYUV aDimsYUV; if(myCodecCtx->pix_fmt == stAV::PIX_FMT::RGB24) { setColorModel(StImage::ImgColor_RGB); changePlane(0).initWrapper(StImagePlane::ImgRGB, myFrame.getPlane(0), myCodecCtx->width, myCodecCtx->height, myFrame.getLineSize(0)); } else if(myCodecCtx->pix_fmt == stAV::PIX_FMT::BGR24) { setColorModel(StImage::ImgColor_RGB); changePlane(0).initWrapper(StImagePlane::ImgBGR, myFrame.getPlane(0), myCodecCtx->width, myCodecCtx->height, myFrame.getLineSize(0)); } else if(myCodecCtx->pix_fmt == stAV::PIX_FMT::RGBA32) { setColorModel(StImage::ImgColor_RGBA); changePlane(0).initWrapper(StImagePlane::ImgRGBA, myFrame.getPlane(0), myCodecCtx->width, myCodecCtx->height, myFrame.getLineSize(0)); } else if(myCodecCtx->pix_fmt == stAV::PIX_FMT::BGRA32) { setColorModel(StImage::ImgColor_RGBA); changePlane(0).initWrapper(StImagePlane::ImgBGRA, myFrame.getPlane(0), myCodecCtx->width, myCodecCtx->height, myFrame.getLineSize(0)); } else if(myCodecCtx->pix_fmt == stAV::PIX_FMT::GRAY8) { setColorModel(StImage::ImgColor_GRAY); changePlane(0).initWrapper(StImagePlane::ImgGray, myFrame.getPlane(0), myCodecCtx->width, myCodecCtx->height, myFrame.getLineSize(0)); } else if(myCodecCtx->pix_fmt == stAV::PIX_FMT::GRAY16) { setColorModel(StImage::ImgColor_GRAY); changePlane(0).initWrapper(StImagePlane::ImgGray16, myFrame.getPlane(0), myCodecCtx->width, myCodecCtx->height, myFrame.getLineSize(0)); } else if(myCodecCtx->pix_fmt == stAV::PIX_FMT::RGB48) { setColorModel(StImage::ImgColor_RGB); changePlane(0).initWrapper(StImagePlane::ImgRGB48, myFrame.getPlane(0), myCodecCtx->width, myCodecCtx->height, myFrame.getLineSize(0)); } else if(myCodecCtx->pix_fmt == stAV::PIX_FMT::RGBA64) { setColorModel(StImage::ImgColor_RGBA); changePlane(0).initWrapper(StImagePlane::ImgRGBA64, myFrame.getPlane(0), myCodecCtx->width, myCodecCtx->height, myFrame.getLineSize(0)); } else if(stAV::isFormatYUVPlanar(myCodecCtx, aDimsYUV)) { #if(LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(52, 29, 0)) if(myCodecCtx->color_range == AVCOL_RANGE_JPEG) { aDimsYUV.isFullScale = true; } #endif setColorModel(StImage::ImgColor_YUV); setColorScale(aDimsYUV.isFullScale ? StImage::ImgScale_Full : StImage::ImgScale_Mpeg); StImagePlane::ImgFormat aPlaneFrmt = StImagePlane::ImgGray; if(aDimsYUV.bitsPerComp == 9) { aPlaneFrmt = StImagePlane::ImgGray16; setColorScale(aDimsYUV.isFullScale ? StImage::ImgScale_Jpeg9 : StImage::ImgScale_Mpeg9); } else if(aDimsYUV.bitsPerComp == 10) { aPlaneFrmt = StImagePlane::ImgGray16; setColorScale(aDimsYUV.isFullScale ? StImage::ImgScale_Jpeg10 : StImage::ImgScale_Mpeg10); } else if(aDimsYUV.bitsPerComp == 16) { aPlaneFrmt = StImagePlane::ImgGray16; } changePlane(0).initWrapper(aPlaneFrmt, myFrame.getPlane(0), size_t(aDimsYUV.widthY), size_t(aDimsYUV.heightY), myFrame.getLineSize(0)); changePlane(1).initWrapper(aPlaneFrmt, myFrame.getPlane(1), size_t(aDimsYUV.widthU), size_t(aDimsYUV.heightU), myFrame.getLineSize(1)); changePlane(2).initWrapper(aPlaneFrmt, myFrame.getPlane(2), size_t(aDimsYUV.widthV), size_t(aDimsYUV.heightV), myFrame.getLineSize(2)); } else { ///ST_DEBUG_LOG("StAVImage, perform conversion from Pixel format '" + avcodec_get_pix_fmt_name(myCodecCtx->pix_fmt) + "' to RGB"); // initialize software scaler/converter SwsContext* pToRgbCtx = sws_getContext(myCodecCtx->width, myCodecCtx->height, myCodecCtx->pix_fmt, // source myCodecCtx->width, myCodecCtx->height, stAV::PIX_FMT::RGB24, // destination SWS_BICUBIC, NULL, NULL, NULL); if(pToRgbCtx == NULL) { setState("SWScale library, failed to create SWScaler context"); close(); return false; } // initialize additional buffer for converted RGB data setColorModel(StImage::ImgColor_RGB); changePlane(0).initTrash(StImagePlane::ImgRGB, myCodecCtx->width, myCodecCtx->height); uint8_t* rgbData[4]; stMemZero(rgbData, sizeof(rgbData)); int rgbLinesize[4]; stMemZero(rgbLinesize, sizeof(rgbLinesize)); rgbData[0] = changePlane(0).changeData(); rgbLinesize[0] = (int )changePlane(0).getSizeRowBytes(); sws_scale(pToRgbCtx, myFrame.Frame->data, myFrame.Frame->linesize, 0, myCodecCtx->height, rgbData, rgbLinesize); // reset original data closeAvCtx(); sws_freeContext(pToRgbCtx); } // set debug information StString aDummy, aFileName; StFileNode::getFolderAndFile(theFilePath, aDummy, aFileName); setState(StString("AVCodec library, loaded image '") + aFileName + "' " + getDescription()); // we should not close the file because decoded image data is in codec context cache return true; } bool StAVImage::save(const StString& theFilePath, ImageType theImageType, StFormat theSrcFormat) { close(); setState(); if(isNull()) { return false; } PixelFormat aPFormatAV = (PixelFormat )getAVPixelFormat(*this); StImage anImage; switch(theImageType) { case ST_TYPE_PNG: case ST_TYPE_PNS: { myCodec = avcodec_find_encoder_by_name("png"); if(myCodec == NULL) { setState("AVCodec library, video codec 'png' not found"); close(); return false; } if(aPFormatAV == stAV::PIX_FMT::RGB24 || aPFormatAV == stAV::PIX_FMT::RGBA32 || aPFormatAV == stAV::PIX_FMT::GRAY8) { anImage.initWrapper(*this); } else { // convert to compatible pixel format anImage.changePlane().initTrash(StImagePlane::ImgRGB, getSizeX(), getSizeY(), getAligned(getSizeX() * 3)); PixelFormat aPFrmtTarget = stAV::PIX_FMT::RGB24; if(!convert(*this, aPFormatAV, anImage, aPFrmtTarget)) { setState("SWScale library, failed to create SWScaler context"); close(); return false; } aPFormatAV = aPFrmtTarget; } #if(LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(53, 8, 0)) myCodecCtx = avcodec_alloc_context3(myCodec); #else myCodecCtx = avcodec_alloc_context(); #endif // setup encoder myCodecCtx->pix_fmt = aPFormatAV; myCodecCtx->width = (int )anImage.getSizeX(); myCodecCtx->height = (int )anImage.getSizeY(); myCodecCtx->compression_level = 9; // 0..9 break; } case ST_TYPE_JPEG: case ST_TYPE_MPO: case ST_TYPE_JPS: { myCodec = avcodec_find_encoder_by_name("mjpeg"); if(myCodec == NULL) { setState("AVCodec library, video codec 'mjpeg' not found"); close(); return false; } if(aPFormatAV == stAV::PIX_FMT::YUVJ420P || aPFormatAV == stAV::PIX_FMT::YUVJ422P //|| aPFormatAV == stAV::PIX_FMT::YUVJ444P not supported by FFmpeg... yet? //|| aPFormatAV == stAV::PIX_FMT::YUVJ440P ) { anImage.initWrapper(*this); } else { // convert to compatible pixel format PixelFormat aPFrmtTarget = aPFormatAV == stAV::PIX_FMT::YUV420P ? stAV::PIX_FMT::YUVJ420P : stAV::PIX_FMT::YUVJ422P; anImage.setColorModel(StImage::ImgColor_YUV); anImage.setColorScale(StImage::ImgScale_Mpeg); anImage.changePlane(0).initTrash(StImagePlane::ImgGray, getSizeX(), getSizeY(), getAligned(getSizeX())); stMemSet(anImage.changePlane(0).changeData(), '\0', anImage.getPlane(0).getSizeBytes()); anImage.changePlane(1).initTrash(StImagePlane::ImgGray, getSizeX(), getSizeY(), getAligned(getSizeX())); stMemSet(anImage.changePlane(1).changeData(), '\0', anImage.getPlane(1).getSizeBytes()); anImage.changePlane(2).initTrash(StImagePlane::ImgGray, getSizeX(), getSizeY(), getAligned(getSizeX())); stMemSet(anImage.changePlane(2).changeData(), '\0', anImage.getPlane(2).getSizeBytes()); if(!convert(*this, aPFormatAV, anImage, aPFrmtTarget)) { setState("SWScale library, failed to create SWScaler context"); close(); return false; } aPFormatAV = aPFrmtTarget; } #if(LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(53, 8, 0)) myCodecCtx = avcodec_alloc_context3(myCodec); #else myCodecCtx = avcodec_alloc_context(); #endif myCodecCtx->pix_fmt = aPFormatAV; myCodecCtx->width = (int )anImage.getSizeX(); myCodecCtx->height = (int )anImage.getSizeY(); myCodecCtx->time_base.num = 1; myCodecCtx->time_base.den = 1; myCodecCtx->qmin = myCodecCtx->qmax = 5; // quality factor - lesser is better break; } case ST_TYPE_NONE: default: close(); return false; } // open VIDEO codec #if(LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(53, 8, 0)) if(avcodec_open2(myCodecCtx, myCodec, NULL) < 0) { #else if(avcodec_open(myCodecCtx, myCodec) < 0) { #endif setState("AVCodec library, could not open video codec"); close(); return false; } // wrap own data into AVFrame myFrame.Frame->format = myCodecCtx->pix_fmt; myFrame.Frame->width = myCodecCtx->width; myFrame.Frame->height = myCodecCtx->height; fillPointersAV(anImage, myFrame.Frame->data, myFrame.Frame->linesize); #ifdef ST_AV_NEWSTEREO bool isReversed = false; AVStereo3DType anAvStereoType = stAV::stereo3dStToAv(theSrcFormat, isReversed); if(anAvStereoType != (AVStereo3DType )-1) { AVStereo3D* aStereo = av_stereo3d_create_side_data(myFrame.Frame); if(aStereo != NULL) { aStereo->type = anAvStereoType; if(isReversed) { aStereo->flags |= AV_STEREO3D_FLAG_INVERT; } } } #endif StJpegParser aRawFile(theFilePath); if(!aRawFile.openFile(StRawFile::WRITE)) { setState("Can not open the file for writing"); close(); return false; } // allocate the buffer, large enough (stupid formula copied from ffmpeg.c) int aBuffSize = int(getSizeX() * getSizeY() * 10); aRawFile.initBuffer(aBuffSize); // encode the image StAVPacket aPacket; aPacket.getAVpkt()->data = (uint8_t* )aRawFile.changeBuffer(); aPacket.getAVpkt()->size = aBuffSize; #if(LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(54, 2, 100)) int isGotPacket = 0; int anEncSize = avcodec_encode_video2(myCodecCtx, aPacket.getAVpkt(), myFrame.Frame, &isGotPacket); if(anEncSize == 0 && isGotPacket != 0) { anEncSize = aPacket.getSize(); } #else int anEncSize = avcodec_encode_video(myCodecCtx, aPacket.changeData(), aPacket.getSize(), myFrame.Frame); #endif if(anEncSize <= 0) { setState("AVCodec library, fail to encode the image"); close(); return false; } aRawFile.setDataSize((size_t )anEncSize); // save metadata when possible if(theImageType == ST_TYPE_JPEG || theImageType == ST_TYPE_JPS) { if(aRawFile.parse()) { if(theSrcFormat != StFormat_AUTO) { aRawFile.setupJps(theSrcFormat); } } else { ST_ERROR_LOG("AVCodec library, created JPEG can not be parsed!"); } } // store current content aRawFile.writeFile(); // and finally close the file handle aRawFile.closeFile(); close(); // set debug information StString aDummy, aFileName; StFileNode::getFolderAndFile(theFilePath, aDummy, aFileName); setState(StString("AVCodec library, saved image '") + aFileName + "' " + getDescription()); return true; }