framework2
1286 строк · 38.4 Кб
1#include "ofImage.h"2#include "ofAppRunner.h"3#include "ofPixels.h"4
5#include "FreeImage.h"6
7#include "ofURLFileLoader.h"8#include "uriparser/Uri.h"9
10#if defined(TARGET_ANDROID)11#include "ofxAndroidUtils.h"12#endif13
14
15//----------------------------------------------------------
16// static variable for freeImage initialization:
17void ofInitFreeImage(bool deinit=false){18// need a new bool to avoid c++ "deinitialization order fiasco":19// http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.1520static bool * bFreeImageInited = new bool(false);21if(!*bFreeImageInited && !deinit){22FreeImage_Initialise();23*bFreeImageInited = true;24}25if(*bFreeImageInited && deinit){26FreeImage_DeInitialise();27*bFreeImageInited = false;28}29}
30
31template <typename T>32FREE_IMAGE_TYPE getFreeImageType(const ofPixels_<T>& pix);33
34template <>35FREE_IMAGE_TYPE getFreeImageType(const ofPixels& pix) {36return FIT_BITMAP;37}
38
39template <>40FREE_IMAGE_TYPE getFreeImageType(const ofShortPixels& pix) {41switch(pix.getNumChannels()) {42case 1: return FIT_UINT16;43case 3: return FIT_RGB16;44case 4: return FIT_RGBA16;45default:46ofLogError("ofImage") << "getFreeImageType(): unknown FreeImage type for number of channels: " << pix.getNumChannels();47return FIT_UNKNOWN;48}49}
50template <>51FREE_IMAGE_TYPE getFreeImageType(const ofFloatPixels& pix) {52switch(pix.getNumChannels()) {53case 1: return FIT_FLOAT;54case 3: return FIT_RGBF;55case 4: return FIT_RGBAF;56default:57ofLogError("ofImage") << "getFreeImageType(): unknown FreeImage type for number of channels: " << pix.getNumChannels();58return FIT_UNKNOWN;59}60}
61
62//----------------------------------------------------
63template<typename PixelType>64FIBITMAP* getBmpFromPixels(const ofPixels_<PixelType> &pix){65const PixelType* pixels = pix.getData();66unsigned int width = pix.getWidth();67unsigned int height = pix.getHeight();68unsigned int bpp = pix.getBitsPerPixel();69
70FREE_IMAGE_TYPE freeImageType = getFreeImageType(pix);71FIBITMAP* bmp = FreeImage_AllocateT(freeImageType, width, height, bpp);72unsigned char* bmpBits = FreeImage_GetBits(bmp);73if(bmpBits != nullptr) {74int srcStride = width * pix.getBytesPerPixel();75int dstStride = FreeImage_GetPitch(bmp);76unsigned char* src = (unsigned char*) pixels;77unsigned char* dst = bmpBits;78if(srcStride != dstStride){79for(int i = 0; i < (int)height; i++) {80memcpy(dst, src, srcStride);81src += srcStride;82dst += dstStride;83}84}else{85memcpy(dst,src,dstStride*height);86}87} else {88ofLogError("ofImage") << "getBmpFromPixels(): unable to get FIBITMAP from ofPixels";89}90
91// ofPixels are top left, FIBITMAP is bottom left92FreeImage_FlipVertical(bmp);93
94return bmp;95}
96
97//----------------------------------------------------
98template<typename PixelType>99void putBmpIntoPixels(FIBITMAP * bmp, ofPixels_<PixelType>& pix, bool swapOnLittleEndian = true, bool bUsePassedPixelFormat = false) {100
101// convert to correct type depending on type of input bmp and PixelType102FIBITMAP* bmpConverted = nullptr;103FREE_IMAGE_TYPE imgType = FreeImage_GetImageType(bmp);104if(sizeof(PixelType)==1 &&105(FreeImage_GetColorType(bmp) == FIC_PALETTE || FreeImage_GetBPP(bmp) < 8106|| imgType!=FIT_BITMAP)) {107if(FreeImage_IsTransparent(bmp)) {108bmpConverted = FreeImage_ConvertTo32Bits(bmp);109} else {110bmpConverted = FreeImage_ConvertTo24Bits(bmp);111}112bmp = bmpConverted;113}else if(sizeof(PixelType)==2 && imgType!=FIT_UINT16 && imgType!=FIT_RGB16 && imgType!=FIT_RGBA16){114if(FreeImage_IsTransparent(bmp)) {115bmpConverted = FreeImage_ConvertToType(bmp,FIT_RGBA16);116} else {117bmpConverted = FreeImage_ConvertToType(bmp,FIT_RGB16);118}119bmp = bmpConverted;120}else if(sizeof(PixelType)==4 && imgType!=FIT_FLOAT && imgType!=FIT_RGBF && imgType!=FIT_RGBAF){121if(FreeImage_IsTransparent(bmp)) {122bmpConverted = FreeImage_ConvertToType(bmp,FIT_RGBAF);123} else {124bmpConverted = FreeImage_ConvertToType(bmp,FIT_RGBF);125}126bmp = bmpConverted;127}128
129unsigned int width = FreeImage_GetWidth(bmp);130unsigned int height = FreeImage_GetHeight(bmp);131unsigned int bpp = FreeImage_GetBPP(bmp);132unsigned int channels = (bpp / sizeof(PixelType)) / 8;133unsigned int pitch = FreeImage_GetPitch(bmp);134#ifdef TARGET_LITTLE_ENDIAN135bool swapRG = channels && swapOnLittleEndian && (bpp/channels == 8);136#else137bool swapRG = false;138#endif139
140
141ofPixelFormat pixFormat;142if( bUsePassedPixelFormat ){143pixFormat = pix.getPixelFormat();144}else{145if(channels==1) pixFormat=OF_PIXELS_GRAY;146if(swapRG){147if(channels==3) pixFormat=OF_PIXELS_BGR;148if(channels==4) pixFormat=OF_PIXELS_BGRA;149}else{150if(channels==3) pixFormat=OF_PIXELS_RGB;151if(channels==4) pixFormat=OF_PIXELS_RGBA;152}153}154
155// ofPixels are top left, FIBITMAP is bottom left156FreeImage_FlipVertical(bmp);157
158unsigned char* bmpBits = FreeImage_GetBits(bmp);159if(bmpBits != nullptr) {160pix.setFromAlignedPixels((PixelType*) bmpBits, width, height, pixFormat, pitch);161} else {162ofLogError("ofImage") << "putBmpIntoPixels(): unable to set ofPixels from FIBITMAP";163}164
165if(bmpConverted != nullptr) {166FreeImage_Unload(bmpConverted);167}168
169if(swapRG && channels >=3 ) {170pix.swapRgb();171}172}
173
174/// internal
175static int getJpegOptionFromImageLoadSetting(const ofImageLoadSettings &settings) {176int option = 0;177if(settings.accurate) option |= JPEG_ACCURATE;178if(settings.exifRotate) option |= JPEG_EXIFROTATE;179if(settings.grayscale) option |= JPEG_GREYSCALE;180if(settings.separateCMYK) option |= JPEG_CMYK;181return option;182}
183
184template<typename PixelType>185static bool loadImage(ofPixels_<PixelType> & pix, const of::filesystem::path& _fileName, const ofImageLoadSettings& settings){186ofInitFreeImage();187
188auto uriStr = _fileName.string();189UriUriA uri;190UriParserStateA state;191state.uri = &uri;192
193if(uriParseUriA(&state, uriStr.c_str())!=URI_SUCCESS){194const int bytesNeeded = 8 + 3 * strlen(uriStr.c_str()) + 1;195std::vector<char> absUri(bytesNeeded);196#ifdef TARGET_WIN32197uriWindowsFilenameToUriStringA(uriStr.c_str(), absUri.data());198#else199uriUnixFilenameToUriStringA(uriStr.c_str(), absUri.data());200#endif201if(uriParseUriA(&state, absUri.data())!=URI_SUCCESS){202ofLogError("ofImage") << "loadImage(): malformed uri when loading image from uri " << _fileName;203uriFreeUriMembersA(&uri);204return false;205}206}207std::string scheme(uri.scheme.first, uri.scheme.afterLast);208uriFreeUriMembersA(&uri);209
210if(scheme == "http" || scheme == "https"){211return ofLoadImage(pix, ofLoadURL(_fileName.string()).data);212}213
214auto fileName = ofToDataPath(_fileName, true);215bool bLoaded = false;216FIBITMAP * bmp = nullptr;217
218FREE_IMAGE_FORMAT fif = FIF_UNKNOWN;219fif = FreeImage_GetFileType(fileName.c_str(), 0);220if(fif == FIF_UNKNOWN) {221// or guess via filename222fif = FreeImage_GetFIFFromFilename(fileName.c_str());223}224if((fif != FIF_UNKNOWN) && FreeImage_FIFSupportsReading(fif)) {225if(fif == FIF_JPEG) {226int option = getJpegOptionFromImageLoadSetting(settings);227bmp = FreeImage_Load(fif, fileName.c_str(), option | settings.freeImageFlags);228} else {229bmp = FreeImage_Load(fif, fileName.c_str(), 0 | settings.freeImageFlags);230}231
232if (bmp != nullptr){233bLoaded = true;234}235}236
237//-----------------------------238
239if ( bLoaded ){240putBmpIntoPixels(bmp,pix);241}242
243if (bmp != nullptr){244FreeImage_Unload(bmp);245}246
247return bLoaded;248}
249
250template<typename PixelType>251static bool loadImage(ofPixels_<PixelType> & pix, const ofBuffer & buffer, const ofImageLoadSettings &settings){252ofInitFreeImage();253bool bLoaded = false;254FIBITMAP* bmp = nullptr;255FIMEMORY* hmem = nullptr;256
257hmem = FreeImage_OpenMemory((unsigned char*) buffer.getData(), buffer.size());258if (hmem == nullptr){259ofLogError("ofImage") << "loadImage(): couldn't load image from ofBuffer, opening FreeImage memory failed";260return false;261}262
263//get the file type!264FREE_IMAGE_FORMAT fif = FreeImage_GetFileTypeFromMemory(hmem);265if( fif == -1 ){266ofLogError("ofImage") << "loadImage(): couldn't load image from ofBuffer, unable to guess image format from memory";267FreeImage_CloseMemory(hmem);268return false;269}270
271
272//make the image!!273if(fif == FIF_JPEG) {274int option = getJpegOptionFromImageLoadSetting(settings);275bmp = FreeImage_LoadFromMemory(fif, hmem, option | settings.freeImageFlags);276} else {277bmp = FreeImage_LoadFromMemory(fif, hmem, settings.freeImageFlags);278}279
280if( bmp != nullptr ){281bLoaded = true;282}283
284//-----------------------------285
286if (bLoaded){287putBmpIntoPixels(bmp,pix);288}289
290if (bmp != nullptr){291FreeImage_Unload(bmp);292}293
294if( hmem != nullptr ){295FreeImage_CloseMemory(hmem);296}297
298return bLoaded;299}
300
301//----------------------------------------------------------------
302bool ofLoadImage(ofPixels & pix, const of::filesystem::path& path, const ofImageLoadSettings &settings) {303return loadImage(pix, path, settings);304}
305
306//----------------------------------------------------------------
307bool ofLoadImage(ofPixels & pix, const ofBuffer & buffer, const ofImageLoadSettings &settings) {308return loadImage(pix, buffer, settings);309}
310
311//----------------------------------------------------------------
312bool ofLoadImage(ofShortPixels & pix, const of::filesystem::path& path, const ofImageLoadSettings &settings) {313return loadImage(pix, path, settings);314}
315
316//----------------------------------------------------------------
317bool ofLoadImage(ofShortPixels & pix, const ofBuffer & buffer, const ofImageLoadSettings &settings) {318return loadImage(pix, buffer, settings);319}
320
321//----------------------------------------------------------------
322bool ofLoadImage(ofFloatPixels & pix, const of::filesystem::path& path, const ofImageLoadSettings &settings) {323return loadImage(pix, path, settings);324}
325
326//----------------------------------------------------------------
327bool ofLoadImage(ofFloatPixels & pix, const ofBuffer & buffer, const ofImageLoadSettings &settings) {328return loadImage(pix, buffer, settings);329}
330
331//----------------------------------------------------------------
332bool ofLoadImage(ofTexture & tex, const of::filesystem::path& path, const ofImageLoadSettings &settings){333ofPixels pixels;334bool loaded = ofLoadImage(pixels, path, settings);335if(loaded){336tex.allocate(pixels.getWidth(), pixels.getHeight(), ofGetGLInternalFormat(pixels));337tex.loadData(pixels);338}339return loaded;340}
341
342//----------------------------------------------------------------
343bool ofLoadImage(ofTexture & tex, const ofBuffer & buffer, const ofImageLoadSettings &settings){344ofPixels pixels;345bool loaded = ofLoadImage(pixels, buffer, settings);346if(loaded){347tex.allocate(pixels.getWidth(), pixels.getHeight(), ofGetGLInternalFormat(pixels));348tex.loadData(pixels);349}350return loaded;351}
352
353//----------------------------------------------------------------
354template<typename PixelType>355static bool saveImage(const ofPixels_<PixelType> & _pix, const of::filesystem::path& _fileName, ofImageQualityType qualityLevel) {356ofInitFreeImage();357if (_pix.isAllocated() == false){358ofLogError("ofImage") << "saveImage(): couldn't save \"" << _fileName << "\", pixels are not allocated";359return false;360}361
362ofFilePath::createEnclosingDirectory(_fileName);363auto fileName = ofToDataPath(_fileName);364FREE_IMAGE_FORMAT fif = FIF_UNKNOWN;365fif = FreeImage_GetFileType(fileName.c_str(), 0);366if(fif == FIF_UNKNOWN) {367// or guess via filename368fif = FreeImage_GetFIFFromFilename(fileName.c_str());369}370if(fif==FIF_JPEG && (_pix.getNumChannels()==4 || _pix.getBitsPerChannel() > 8)){371ofPixels pix3 = _pix;372if( pix3.getPixelFormat() == OF_PIXELS_BGRA ){373pix3.swapRgb();374}375pix3.setNumChannels(3);376return saveImage(pix3,_fileName,qualityLevel);377}378
379FIBITMAP * bmp = nullptr;380#ifdef TARGET_LITTLE_ENDIAN381if(sizeof(PixelType) == 1 && (_pix.getPixelFormat()==OF_PIXELS_RGB || _pix.getPixelFormat()==OF_PIXELS_RGBA)) { // Make a local copy.382ofPixels_<PixelType> pix = _pix;383pix.swapRgb();384bmp = getBmpFromPixels(pix);385}else{386#endif387
388bmp = getBmpFromPixels(_pix);389
390
391#ifdef TARGET_LITTLE_ENDIAN392}393#endif394
395bool retValue = false;396if((fif != FIF_UNKNOWN) && FreeImage_FIFSupportsReading(fif)) {397if(fif == FIF_JPEG) {398int quality = JPEG_QUALITYSUPERB;399switch(qualityLevel) {400case OF_IMAGE_QUALITY_WORST: quality = JPEG_QUALITYBAD; break;401case OF_IMAGE_QUALITY_LOW: quality = JPEG_QUALITYAVERAGE; break;402case OF_IMAGE_QUALITY_MEDIUM: quality = JPEG_QUALITYNORMAL; break;403case OF_IMAGE_QUALITY_HIGH: quality = JPEG_QUALITYGOOD; break;404case OF_IMAGE_QUALITY_BEST: quality = JPEG_QUALITYSUPERB; break;405}406retValue = FreeImage_Save(fif, bmp, fileName.c_str(), quality);407} else {408if(qualityLevel != OF_IMAGE_QUALITY_BEST) {409ofLogWarning("ofImage") << "saveImage(): ofImageCompressionType only applies to JPEGs,"410<< " ignoring value for \" "<< fileName << "\"";411}412
413if (fif == FIF_GIF) {414FIBITMAP* convertedBmp;415if(_pix.getImageType() == OF_IMAGE_COLOR_ALPHA) {416// this just converts the image to grayscale so it can save something417convertedBmp = FreeImage_ConvertTo8Bits(bmp);418} else {419// this will create a 256-color palette from the image420convertedBmp = FreeImage_ColorQuantize(bmp, FIQ_NNQUANT);421}422retValue = FreeImage_Save(fif, convertedBmp, fileName.c_str());423if (convertedBmp != nullptr){424FreeImage_Unload(convertedBmp);425}426} else {427retValue = FreeImage_Save(fif, bmp, fileName.c_str());428}429}430}431
432if (bmp != nullptr){433FreeImage_Unload(bmp);434}435
436return retValue;437}
438
439//----------------------------------------------------------------
440bool ofSaveImage(const ofPixels & pix, const of::filesystem::path& fileName, ofImageQualityType qualityLevel){441return saveImage(pix,fileName,qualityLevel);442}
443
444//----------------------------------------------------------------
445bool ofSaveImage(const ofFloatPixels & pix, const of::filesystem::path& fileName, ofImageQualityType qualityLevel) {446return saveImage(pix,fileName,qualityLevel);447}
448
449//----------------------------------------------------------------
450bool ofSaveImage(const ofShortPixels & pix, const of::filesystem::path& fileName, ofImageQualityType qualityLevel) {451return saveImage(pix,fileName,qualityLevel);452}
453
454//----------------------------------------------------------------
455template<typename PixelType>456static bool saveImage(const ofPixels_<PixelType> & _pix, ofBuffer & buffer, ofImageFormat format, ofImageQualityType qualityLevel) {457// thanks to alvaro casinelli for the implementation458
459ofInitFreeImage();460
461if (_pix.isAllocated() == false){462ofLogError("ofImage","saveImage(): couldn't save to ofBuffer, pixels are not allocated");463return false;464}465
466if(format==OF_IMAGE_FORMAT_JPEG && (_pix.getNumChannels()==4 || _pix.getBitsPerChannel() > 8)){467ofPixels pix3 = _pix;468if( pix3.getPixelFormat() == OF_PIXELS_BGRA ){469pix3.swapRgb();470}471pix3.setNumChannels(3);472return saveImage(pix3,buffer,format,qualityLevel);473}474
475
476FIBITMAP * bmp = nullptr;477#ifdef TARGET_LITTLE_ENDIAN478if(sizeof(PixelType) == 1 && (_pix.getPixelFormat()==OF_PIXELS_RGB || _pix.getPixelFormat()==OF_PIXELS_RGBA)) { // Make a local copy.479ofPixels_<PixelType> pix = _pix;480pix.swapRgb();481bmp = getBmpFromPixels(pix);482}else{483#endif484
485bmp = getBmpFromPixels(_pix);486
487
488#ifdef TARGET_LITTLE_ENDIAN489}490#endif491
492if (bmp) // bitmap successfully created493{494bool returnValue;495// (b) open a memory stream to compress the image onto mem_buffer:496//497FIMEMORY *hmem = FreeImage_OpenMemory();498// (c) encode and save the image to the memory (on dib FIBITMAP image):499//500if(FREE_IMAGE_FORMAT(format) == FIF_JPEG) {501int quality = JPEG_QUALITYSUPERB;502switch(qualityLevel) {503case OF_IMAGE_QUALITY_WORST: quality = JPEG_QUALITYBAD; break;504case OF_IMAGE_QUALITY_LOW: quality = JPEG_QUALITYAVERAGE; break;505case OF_IMAGE_QUALITY_MEDIUM: quality = JPEG_QUALITYNORMAL; break;506case OF_IMAGE_QUALITY_HIGH: quality = JPEG_QUALITYGOOD; break;507case OF_IMAGE_QUALITY_BEST: quality = JPEG_QUALITYSUPERB; break;508}509returnValue = FreeImage_SaveToMemory(FIF_JPEG, bmp, hmem, quality);510}else{511returnValue = FreeImage_SaveToMemory((FREE_IMAGE_FORMAT)format, bmp, hmem);512}513
514/*515
516NOTE: at this point, hmem contains the entire data in memory stored in fif format. the
517amount of space used by the memory is equal to file_size:
518long file_size = FreeImage_TellMemory(hmem);
519but can also be retrieved by FreeImage_AcquireMemory that retrieves both the
520length of the buffer, and the buffer memory address.
521*/
522#ifdef TARGET_WIN32523DWORD size_in_bytes = 0;524#else525std::uint32_t size_in_bytes = 0;526#endif527// Save compressed data on mem_buffer528// note: FreeImage_AquireMemory allocates space for aux_mem_buffer):529//530unsigned char *mem_buffer = nullptr;531if (!FreeImage_AcquireMemory(hmem, &mem_buffer, &size_in_bytes)){532ofLogError("ofImage") << "saveImage(): couldn't save to ofBuffer, aquiring compressed image from memory failed";533return false;534}535
536/*537Now, before closing the memory stream, copy the content of mem_buffer
538to an auxiliary buffer
539*/
540
541buffer.set((char*)mem_buffer,size_in_bytes);542
543// Finally, close the FIBITMAP object, or we will get a memory leak:544FreeImage_Unload(bmp);545
546// Close the memory stream (otherwise we may get a memory leak).547FreeImage_CloseMemory(hmem);548return returnValue;549}else{550return false;551}552}
553
554//----------------------------------------------------------------
555bool ofSaveImage(const ofPixels & pix, ofBuffer & buffer, ofImageFormat format, ofImageQualityType qualityLevel) {556return saveImage(pix,buffer,format,qualityLevel);557}
558
559bool ofSaveImage(const ofFloatPixels & pix, ofBuffer & buffer, ofImageFormat format, ofImageQualityType qualityLevel) {560return saveImage(pix,buffer,format,qualityLevel);561}
562
563bool ofSaveImage(const ofShortPixels & pix, ofBuffer & buffer, ofImageFormat format, ofImageQualityType qualityLevel) {564return saveImage(pix,buffer,format,qualityLevel);565}
566
567
568//----------------------------------------------------
569// freeImage based stuff:
570void ofCloseFreeImage(){571ofInitFreeImage(true);572}
573
574//-------------------------------------------------------------
575// implementation
576
577//----------------------------------------------------------
578template<typename PixelType>579ofImage_<PixelType>::ofImage_(){580
581width = 0;582height = 0;583bpp = 0;584type = OF_IMAGE_UNDEFINED;585bUseTexture = true; // the default is, yes, use a texture586
587//----------------------- init free image if necessary588ofInitFreeImage();589}
590
591//----------------------------------------------------------
592template<typename PixelType>593ofImage_<PixelType>::ofImage_(const ofPixels_<PixelType> & pix){594width = 0;595height = 0;596bpp = 0;597type = OF_IMAGE_UNDEFINED;598bUseTexture = true; // the default is, yes, use a texture599
600//----------------------- init free image if necessary601ofInitFreeImage();602
603
604setFromPixels(pix);605}
606
607template<typename PixelType>608ofImage_<PixelType>::ofImage_(const of::filesystem::path & fileName, const ofImageLoadSettings &settings){609width = 0;610height = 0;611bpp = 0;612type = OF_IMAGE_UNDEFINED;613bUseTexture = true; // the default is, yes, use a texture614
615//----------------------- init free image if necessary616ofInitFreeImage();617
618
619load(fileName, settings);620}
621
622//----------------------------------------------------------
623template<typename PixelType>624ofImage_<PixelType>& ofImage_<PixelType>::operator=(const ofImage_<PixelType>& mom) {625if(&mom==this) return *this;626clone(mom);627
628#if defined(TARGET_ANDROID)629ofAddListener(ofxAndroidEvents().unloadGL,this,&ofImage_<PixelType>::unloadTexture);630ofAddListener(ofxAndroidEvents().reloadGL,this,&ofImage_<PixelType>::update);631#endif632return *this;633}
634
635//----------------------------------------------------------
636template<typename PixelType>637ofImage_<PixelType>::ofImage_(const ofImage_<PixelType>& mom) {638clear();639clone(mom);640
641#if defined(TARGET_ANDROID)642ofAddListener(ofxAndroidEvents().unloadGL,this,&ofImage_<PixelType>::unloadTexture);643ofAddListener(ofxAndroidEvents().reloadGL,this,&ofImage_<PixelType>::update);644#endif645}
646
647//----------------------------------------------------------
648template<typename PixelType>649ofImage_<PixelType>::ofImage_(ofImage_<PixelType>&& mom){650pixels = std::move(mom.pixels);651tex = std::move(mom.tex);652
653bUseTexture = mom.bUseTexture;654width = mom.width;655height = mom.height;656bpp = mom.bpp;657type = mom.type;658
659mom.clear(); //clear remaining flags and sizes from the mom660
661#if defined(TARGET_ANDROID)662ofAddListener(ofxAndroidEvents().unloadGL,this,&ofImage_<PixelType>::unloadTexture);663ofAddListener(ofxAndroidEvents().reloadGL,this,&ofImage_<PixelType>::update);664#endif665}
666
667//----------------------------------------------------------
668template<typename PixelType>669ofImage_<PixelType>& ofImage_<PixelType>::operator=(ofImage_<PixelType>&& mom){670if(&mom==this) return *this;671
672pixels = std::move(mom.pixels);673tex = std::move(mom.tex);674
675bUseTexture = mom.bUseTexture;676width = mom.width;677height = mom.height;678bpp = mom.bpp;679type = mom.type;680
681mom.clear(); //clear remaining flags and sizes from the mom682
683#if defined(TARGET_ANDROID)684ofAddListener(ofxAndroidEvents().unloadGL,this,&ofImage_<PixelType>::unloadTexture);685ofAddListener(ofxAndroidEvents().reloadGL,this,&ofImage_<PixelType>::update);686#endif687
688return *this;689}
690
691//----------------------------------------------------------
692template<typename PixelType>693ofImage_<PixelType>::~ofImage_(){694clear();695}
696
697//----------------------------------------------------------
698template<typename PixelType>699bool ofImage_<PixelType>::loadImage(const ofFile & file){700return load(file);701}
702
703//----------------------------------------------------------
704template<typename PixelType>705bool ofImage_<PixelType>::load(const of::filesystem::path& fileName, const ofImageLoadSettings &settings){706#if defined(TARGET_ANDROID)707ofAddListener(ofxAndroidEvents().unloadGL,this,&ofImage_<PixelType>::unloadTexture);708ofAddListener(ofxAndroidEvents().reloadGL,this,&ofImage_<PixelType>::update);709#endif710bool bLoadedOk = ofLoadImage(pixels, fileName, settings);711if (!bLoadedOk) {712ofLogError("ofImage") << "loadImage(): couldn't load image from \"" << fileName << "\"";713clear();714return false;715}716update();717return bLoadedOk;718}
719
720//----------------------------------------------------------
721template<typename PixelType>722bool ofImage_<PixelType>::loadImage(const std::string& fileName){723return load(fileName);724}
725
726//----------------------------------------------------------
727template<typename PixelType>728bool ofImage_<PixelType>::load(const ofBuffer & buffer, const ofImageLoadSettings &settings){729#if defined(TARGET_ANDROID)730ofAddListener(ofxAndroidEvents().unloadGL,this,&ofImage_<PixelType>::unloadTexture);731ofAddListener(ofxAndroidEvents().reloadGL,this,&ofImage_<PixelType>::update);732#endif733bool bLoadedOk = ofLoadImage(pixels, buffer, settings);734if (!bLoadedOk) {735ofLogError("ofImage") << "loadImage(): couldn't load image from ofBuffer";736clear();737return false;738}739update();740return bLoadedOk;741}
742
743//----------------------------------------------------------
744template<typename PixelType>745bool ofImage_<PixelType>::loadImage(const ofBuffer & buffer){746return load(buffer);747}
748
749//----------------------------------------------------------
750template<typename PixelType>751bool ofImage_<PixelType>::save(const of::filesystem::path& fileName, ofImageQualityType qualityLevel) const {752return ofSaveImage(pixels, fileName, qualityLevel);753}
754
755//----------------------------------------------------------
756template<typename PixelType>757bool ofImage_<PixelType>::save(ofBuffer & buffer, ofImageFormat imageFormat, ofImageQualityType qualityLevel) const {758return ofSaveImage(pixels, buffer, imageFormat, qualityLevel);759}
760
761//----------------------------------------------------------
762template<typename PixelType>763void ofImage_<PixelType>::saveImage(const std::string& fileName, ofImageQualityType qualityLevel) const {764save(fileName, qualityLevel);765}
766
767//----------------------------------------------------------
768template<typename PixelType>769void ofImage_<PixelType>::saveImage(ofBuffer & buffer, ofImageQualityType qualityLevel) const {770save(buffer, OF_IMAGE_FORMAT_PNG, qualityLevel);771}
772
773//----------------------------------------------------------
774template<typename PixelType>775void ofImage_<PixelType>::saveImage(const ofFile & file, ofImageQualityType compressionLevel) const {776save(file,compressionLevel);777}
778
779// we could cap these values - but it might be more useful
780// to be able to set anchor points outside the image
781
782//----------------------------------------------------------
783template<typename PixelType>784void ofImage_<PixelType>::setAnchorPercent(float xPct, float yPct){785if (bUseTexture)tex.setAnchorPercent(xPct, yPct);786}
787
788//----------------------------------------------------------
789template<typename PixelType>790void ofImage_<PixelType>::setAnchorPoint(float x, float y){791if (bUseTexture)tex.setAnchorPoint(x, y);792}
793
794//----------------------------------------------------------
795template<typename PixelType>796void ofImage_<PixelType>::resetAnchor(){797if (bUseTexture)tex.resetAnchor();798}
799
800//------------------------------------
801template<typename PixelType>802void ofImage_<PixelType>::draw(float x, float y) const{803draw(x,y,0,getWidth(),getHeight());804}
805
806//------------------------------------
807template<typename PixelType>808void ofImage_<PixelType>::draw(float x, float y, float z) const{809draw(x,y,z,getWidth(),getHeight());810}
811
812
813//------------------------------------
814template<typename PixelType>815void ofImage_<PixelType>::draw(const glm::vec3 & pos) const{816draw(pos.x,pos.y,pos.z,getWidth(),getHeight());817}
818
819//------------------------------------
820template<typename PixelType>821void ofImage_<PixelType>::draw(float x, float y, float w, float h) const{822draw(x,y,0,w,h);823}
824
825//------------------------------------
826template<typename PixelType>827void ofImage_<PixelType>::draw(float x, float y, float z, float w, float h) const{828drawSubsection(x,y,z,w,h,0,0,getWidth(),getHeight());829}
830
831
832//------------------------------------
833template<typename PixelType>834void ofImage_<PixelType>::draw(const glm::vec3 & pos, float w, float h) const{835draw(pos.x,pos.y,pos.z,w,h);836}
837
838//------------------------------------
839template<typename PixelType>840void ofImage_<PixelType>::drawSubsection(float x, float y, float w, float h, float sx, float sy) const{841drawSubsection(x,y,0,w,h,sx,sy,w,h);842}
843
844//------------------------------------
845template<typename PixelType>846void ofImage_<PixelType>::drawSubsection(float x, float y, float w, float h, float sx, float sy, float _sw, float _sh) const{847drawSubsection(x,y,0,w,h,sx,sy,_sw,_sh);848}
849
850//------------------------------------
851template<typename PixelType>852void ofImage_<PixelType>::drawSubsection(float x, float y, float z, float w, float h, float sx, float sy) const{853drawSubsection(x,y,z,w,h,sx,sy,w,h);854}
855
856//------------------------------------
857template<typename PixelType>858void ofImage_<PixelType>::drawSubsection(float x, float y, float z, float w, float h, float sx, float sy, float sw, float sh) const{859ofGetCurrentRenderer()->draw(*this,x,y,z,w,h,sx,sy,sw,sh);860}
861
862//------------------------------------
863template<typename PixelType>864void ofImage_<PixelType>::allocate(int w, int h, ofImageType newType){865
866if (width == w && height == h && newType == type){867return;868}869#if defined(TARGET_ANDROID)870ofAddListener(ofxAndroidEvents().unloadGL,this,&ofImage_<PixelType>::unloadTexture);871ofAddListener(ofxAndroidEvents().reloadGL,this,&ofImage_<PixelType>::update);872#endif873pixels.allocate(w, h, newType);874
875// take care of texture allocation --876if (pixels.isAllocated() && bUseTexture){877tex.allocate(pixels);878}879
880width = pixels.getWidth();881height = pixels.getHeight();882bpp = pixels.getBitsPerPixel();883type = pixels.getImageType();884}
885
886
887//------------------------------------
888template<typename PixelType>889bool ofImage_<PixelType>::bAllocated(){890return pixels.isAllocated();891}
892
893//------------------------------------
894template<typename PixelType>895void ofImage_<PixelType>::clear(){896#if defined(TARGET_ANDROID)897ofRemoveListener(ofxAndroidEvents().unloadGL,this,&ofImage_<PixelType>::unloadTexture);898ofRemoveListener(ofxAndroidEvents().reloadGL,this,&ofImage_<PixelType>::update);899#endif900pixels.clear();901if(bUseTexture) tex.clear();902
903width = 0;904height = 0;905bpp = 0;906type = OF_IMAGE_UNDEFINED;907bUseTexture = true; // the default is, yes, use a texture908}
909
910//------------------------------------
911template<typename PixelType>912ofPixels_<PixelType> & ofImage_<PixelType>::getPixels(){913return pixels;914}
915
916//------------------------------------
917template<typename PixelType>918const ofPixels_<PixelType> & ofImage_<PixelType>::getPixels() const{919return pixels;920}
921
922//----------------------------------------------------------
923template<typename PixelType>924ofPixels_<PixelType> & ofImage_<PixelType>::getPixelsRef(){925return pixels;926}
927
928//----------------------------------------------------------
929template<typename PixelType>930const ofPixels_<PixelType> & ofImage_<PixelType>::getPixelsRef() const {931return pixels;932}
933
934//----------------------------------------------------------
935template<typename PixelType>936ofImage_<PixelType>::operator ofPixels_<PixelType>&(){937return pixels;938}
939
940//------------------------------------
941template<typename PixelType>942ofTexture & ofImage_<PixelType>::getTexture(){943return tex;944}
945
946//------------------------------------
947template<typename PixelType>948const ofTexture & ofImage_<PixelType>::getTexture() const{949return tex;950}
951
952//------------------------------------
953// for getting a reference to the texture
954template<typename PixelType>955ofTexture & ofImage_<PixelType>::getTextureReference(){956return getTexture();957}
958
959//------------------------------------
960template<typename PixelType>961const ofTexture & ofImage_<PixelType>::getTextureReference() const{962return getTexture();963}
964
965//----------------------------------------------------------
966template<typename PixelType>967void ofImage_<PixelType>::bind(int textureLocation) const{968if (bUseTexture && tex.isAllocated())969tex.bind(textureLocation);970}
971
972//----------------------------------------------------------
973template<typename PixelType>974void ofImage_<PixelType>::unbind(int textureLocation) const{975if (bUseTexture && tex.isAllocated())976tex.unbind(textureLocation);977}
978
979//------------------------------------
980template<typename PixelType>981ofColor_<PixelType> ofImage_<PixelType>::getColor(int x, int y) const {982return pixels.getColor(x, y);983}
984
985//------------------------------------
986template<typename PixelType>987ofColor_<PixelType> ofImage_<PixelType>::getColor(int index) const {988return pixels.getColor(index);989}
990
991//------------------------------------
992template<typename PixelType>993void ofImage_<PixelType>::setColor(int x, int y, const ofColor_<PixelType>& color) {994pixels.setColor(x, y, color);995}
996
997//------------------------------------
998template<typename PixelType>999void ofImage_<PixelType>::setColor(int index, const ofColor_<PixelType>& color) {1000pixels.setColor(index, color);1001}
1002
1003//------------------------------------
1004template<typename PixelType>1005void ofImage_<PixelType>::setColor(const ofColor_<PixelType>& color) {1006pixels.setColor(color);1007}
1008
1009//------------------------------------
1010template<typename PixelType>1011void ofImage_<PixelType>::setFromPixels(const PixelType * newPixels, int w, int h, ofImageType newType, bool bOrderIsRGB){1012
1013allocate(w, h, newType);1014pixels.setFromPixels(newPixels,w,h,newType);1015
1016if (!bOrderIsRGB && sizeof(PixelType) == 1){1017pixels.swapRgb();1018}1019
1020update();1021}
1022
1023//------------------------------------
1024template<typename PixelType>1025void ofImage_<PixelType>::setFromPixels(const ofPixels_<PixelType> & pixels){1026setFromPixels(pixels.getData(),pixels.getWidth(),pixels.getHeight(),pixels.getImageType());1027}
1028
1029//------------------------------------
1030template<typename PixelType>1031ofImage_<PixelType> & ofImage_<PixelType>::operator=(ofPixels_<PixelType> & pixels){1032setFromPixels(pixels);1033return *this;1034}
1035
1036//------------------------------------
1037template<typename PixelType>1038void ofImage_<PixelType>::update(){1039width = pixels.getWidth();1040height = pixels.getHeight();1041bpp = pixels.getBitsPerPixel();1042type = pixels.getImageType();1043if (pixels.isAllocated() && bUseTexture){1044int glInternalFormat = ofGetGLInternalFormat(pixels);1045if(!tex.isAllocated() || tex.getWidth() != width || tex.getHeight() != height || tex.getTextureData().glInternalFormat != glInternalFormat){1046tex.allocate(pixels);1047}else{1048tex.loadData(pixels);1049}1050}1051}
1052
1053//------------------------------------
1054template<typename PixelType>1055void ofImage_<PixelType>::setUseTexture(bool bUse){1056bUseTexture = bUse;1057}
1058
1059//------------------------------------
1060template<typename PixelType>1061bool ofImage_<PixelType>::isUsingTexture() const{1062return bUseTexture;1063}
1064
1065//------------------------------------
1066template<>1067void ofImage_<unsigned char>::grabScreen(int x, int y, int w, int h){1068std::shared_ptr<ofBaseGLRenderer> renderer = ofGetGLRenderer();1069if(renderer){1070renderer->saveScreen(x,y,w,h,pixels);1071update();1072}1073}
1074
1075//------------------------------------
1076template<typename PixelType>1077void ofGrabScreen(ofPixels_<PixelType> & pixels, int x, int y, int w, int h){1078ofPixels p;1079std::shared_ptr<ofBaseGLRenderer> renderer = ofGetGLRenderer();1080if(renderer){1081renderer->saveScreen(x,y,w,h,p);1082pixels = p;1083}1084}
1085
1086//------------------------------------
1087template<>1088void ofGrabScreen(ofPixels & p, int x, int y, int w, int h){1089std::shared_ptr<ofBaseGLRenderer> renderer = ofGetGLRenderer();1090if(renderer){1091renderer->saveScreen(x,y,w,h,p);1092}1093}
1094
1095//------------------------------------
1096template<typename PixelType>1097void ofImage_<PixelType>::grabScreen(int x, int y, int w, int h){1098ofGrabScreen(pixels,x,y,w,h);1099update();1100}
1101
1102//------------------------------------
1103template<typename PixelType>1104void ofImage_<PixelType>::setImageType(ofImageType newType){1105changeTypeOfPixels(pixels, newType);1106update();1107}
1108
1109//------------------------------------
1110template<typename PixelType>1111ofImageType ofImage_<PixelType>::getImageType() const{1112return type;1113}
1114
1115//------------------------------------
1116template<typename PixelType>1117void ofImage_<PixelType>::resize(int newWidth, int newHeight){1118if(newWidth == width && newHeight == height) return;1119
1120resizePixels(pixels, newWidth, newHeight);1121update();1122}
1123
1124
1125//------------------------------------
1126template<typename PixelType>1127void ofImage_<PixelType>::crop(int x, int y, int w, int h){1128w = glm::clamp(w,1,int(getWidth()));1129h = glm::clamp(h,1,int(getHeight()));1130
1131pixels.crop(x,y,w,h);1132update();1133}
1134
1135//------------------------------------
1136template<typename PixelType>1137void ofImage_<PixelType>::cropFrom(const ofImage_<PixelType> & otherImage, int x, int y, int w, int h){1138w = glm::clamp(w,1,int(otherImage.getWidth()));1139h = glm::clamp(h,1,int(otherImage.getHeight()));1140
1141otherImage.pixels.cropTo(pixels, x, y, w, h);1142update();1143}
1144
1145//------------------------------------
1146template<typename PixelType>1147void ofImage_<PixelType>::rotate90(int nRotations){1148pixels.rotate90(nRotations);1149update();1150}
1151
1152//------------------------------------
1153template<typename PixelType>1154void ofImage_<PixelType>::mirror(bool vertical, bool horizontal){1155pixels.mirror(vertical, horizontal);1156update();1157}
1158
1159
1160
1161
1162
1163
1164//----------------------------------------------------------------------------------------------------
1165//----------------------------------------------------------------------------------------------------
1166//----------------------------------------------------------------------------------------------------
1167// freeImage based code & utilities:
1168
1169
1170//----------------------------------------------------
1171template<typename PixelType>1172void ofImage_<PixelType>::resizePixels(ofPixels_<PixelType> &pix, int newWidth, int newHeight){1173
1174FIBITMAP * bmp = getBmpFromPixels(pix);1175FIBITMAP * convertedBmp = nullptr;1176
1177convertedBmp = FreeImage_Rescale(bmp, newWidth, newHeight, FILTER_BICUBIC);1178putBmpIntoPixels(convertedBmp, pix, false, true);1179
1180if (bmp != nullptr) FreeImage_Unload(bmp);1181if (convertedBmp != nullptr) FreeImage_Unload(convertedBmp);1182}
1183
1184//----------------------------------------------------
1185template<typename PixelType>1186void ofImage_<PixelType>::changeTypeOfPixels(ofPixels_<PixelType> &pix, ofImageType newType){1187int oldType = pix.getImageType();1188
1189if (oldType == newType) {1190return; // no need to reallocate1191}1192
1193FIBITMAP * bmp = getBmpFromPixels(pix);1194FIBITMAP * convertedBmp = nullptr;1195
1196ofPixelFormat oldPixFormat = pix.getPixelFormat();1197
1198switch (newType){1199case OF_IMAGE_GRAYSCALE:1200convertedBmp = FreeImage_ConvertToGreyscale(bmp);1201break;1202case OF_IMAGE_COLOR:1203convertedBmp = FreeImage_ConvertTo24Bits(bmp);1204break;1205case OF_IMAGE_COLOR_ALPHA:1206convertedBmp = FreeImage_ConvertTo32Bits(bmp);1207break;1208default:1209ofLogError("ofImage") << "changeTypeOfPixels(): unknown image type: "1210<< ofToString(newType);1211break;1212}1213
1214putBmpIntoPixels(convertedBmp, pix, false);1215
1216// if we started with BGRA or BGR pixels make sure we end up with similar1217if( pix.getNumChannels() >= 3 && ( oldPixFormat == OF_PIXELS_BGR || oldPixFormat == OF_PIXELS_BGRA ) ){1218ofPixelFormat fixedFormat = pix.getPixelFormat();1219if( fixedFormat == OF_PIXELS_RGBA ){1220fixedFormat = OF_PIXELS_BGRA;1221}else if( fixedFormat == OF_PIXELS_RGB ){1222fixedFormat = OF_PIXELS_BGR;1223}1224pix.setFromPixels(pix.getData(),pix.getWidth(),pix.getHeight(), fixedFormat);1225}1226
1227if (bmp != nullptr) {1228FreeImage_Unload(bmp);1229}1230if (convertedBmp != nullptr) {1231FreeImage_Unload(convertedBmp);1232}1233}
1234
1235
1236//----------------------------------------------------------
1237template<typename PixelType>1238void ofImage_<PixelType>::unloadTexture(){1239tex.clear();1240}
1241
1242//----------------------------------------------------------
1243template<typename PixelType>1244float ofImage_<PixelType>::getHeight() const{1245return height;1246}
1247
1248//----------------------------------------------------------
1249template<typename PixelType>1250float ofImage_<PixelType>::getWidth() const{1251return width;1252}
1253
1254//----------------------------------------------------------
1255// Sosolimited: texture compression
1256// call this function before you call loadImage()
1257template<typename PixelType>1258void ofImage_<PixelType>::setCompression(ofTexCompression compression)1259{
1260if(bUseTexture){1261tex.setCompression( compression );1262}1263}
1264
1265template class ofImage_<unsigned char>;1266template class ofImage_<float>;1267template class ofImage_<unsigned short>;1268
1269template<>1270std::string ofToString(const ofImageType & imgType){1271switch(imgType) {1272case OF_IMAGE_GRAYSCALE:1273return "OF_IMAGE_GRAYSCALE";1274break;1275case OF_IMAGE_COLOR:1276return "OF_IMAGE_COLOR";1277break;1278case OF_IMAGE_COLOR_ALPHA:1279return "OF_IMAGE_COLOR_ALPHA";1280break;1281case OF_IMAGE_UNDEFINED:1282return "OF_IMAGE_UNDEFINED";1283break;1284}1285return "OF_IMAGE_UNDEFINED";1286}
1287