topical media & game development
lib-of-vs-libs-openFrameworks-graphics-ofImage.cpp / cpp
include <ofImage.h>
//----------------------------------------------------------
// static variable for freeImage initialization:
static bool bFreeImageInited = false;
//----------------------------------------------------------
//----------------------------------------------------------
ofImage::ofImage(){
myPixels.width = 0;
myPixels.height = 0;
myPixels.bitsPerPixel = 0;
myPixels.bytesPerPixel = 0;
myPixels.glDataType = GL_LUMINANCE;
myPixels.ofImageType = OF_IMAGE_UNDEFINED;
myPixels.bAllocated = false;
width = 0;
height = 0;
bpp = 0;
type = OF_IMAGE_UNDEFINED;
bUseTexture = true; // the default is, yes, use a texture
//----------------------- init free image if necessary
if (!bFreeImageInited){
FreeImage_Initialise();
bFreeImageInited = true;
}
}
//----------------------------------------------------------
ofImage& ofImage::operator=(const ofImage& mom) {
clone(mom);
update();
return *this;
}
//----------------------------------------------------------
ofImage::ofImage(const ofImage& mom) {
myPixels.bAllocated = false;
if (!bFreeImageInited){
FreeImage_Initialise();
bFreeImageInited = true;
}
clear();
clone(mom);
update();
};
//----------------------------------------------------------
ofImage::~ofImage(){
clear();
}
//----------------------------------------------------------
bool ofImage::loadImage(string fileName){
bool bLoadedOk = false;
bLoadedOk = loadImageIntoPixels(fileName, myPixels);
if (bLoadedOk == true){
if (myPixels.bAllocated == true && bUseTexture == true){
tex.allocate(myPixels.width, myPixels.height, myPixels.glDataType);
}
update();
}
return bLoadedOk;
}
//----------------------------------------------------------
void ofImage::saveImage(string fileName){
saveImageFromPixels(fileName, myPixels);
}
//we could cap these values - but it might be more useful
//to be able to set anchor points outside the image
//----------------------------------------------------------
void ofImage::setAnchorPercent(float xPct, float yPct){
if (bUseTexture)tex.setAnchorPercent(xPct, yPct);
}
//----------------------------------------------------------
void ofImage::setAnchorPoint(int x, int y){
if (bUseTexture)tex.setAnchorPoint(x, y);
}
//----------------------------------------------------------
void ofImage::resetAnchor(){
if (bUseTexture)tex.resetAnchor();
}
//------------------------------------
void ofImage::draw(float _x, float _y, float _w, float _h){
if (bUseTexture){
tex.draw(_x, _y, _w, _h);
}
}
//------------------------------------
void ofImage::draw(float x, float y){
draw(x,y,myPixels.width,myPixels.height);
}
//------------------------------------
void ofImage::allocate(int w, int h, int type){
int newBpp = 0;
switch (type){
case OF_IMAGE_GRAYSCALE:
newBpp = 8;
break;
case OF_IMAGE_COLOR:
newBpp = 24;
break;
case OF_IMAGE_COLOR_ALPHA:
newBpp = 32;
break;
default:
ofLog(OF_LOG_ERROR,"error = bad imageType in ofImage::allocate");
return;
}
allocatePixels(myPixels, w, h, newBpp);
// take care of texture allocation --
if (myPixels.bAllocated == true && bUseTexture == true){
tex.allocate(myPixels.width, myPixels.height, myPixels.glDataType);
}
update();
}
//------------------------------------
void ofImage::clear(){
if (myPixels.bAllocated == true){
delete[] myPixels.pixels;
}
tex.clear();
myPixels.width = 0;
myPixels.height = 0;
myPixels.bitsPerPixel = 0;
myPixels.bytesPerPixel = 0;
myPixels.glDataType = GL_LUMINANCE;
myPixels.ofImageType = OF_IMAGE_UNDEFINED;
myPixels.bAllocated = false;
width = 0;
height = 0;
bpp = 0;
type = OF_IMAGE_UNDEFINED;
bUseTexture = true; // the default is, yes, use a texture
}
//------------------------------------
unsigned char * ofImage::getPixels(){
return myPixels.pixels;
}
//------------------------------------
//for getting a reference to the texture
ofTexture & ofImage::getTextureReference(){
if(!tex.bAllocated() ){
ofLog(OF_LOG_WARNING, "ofImage - getTextureReference - texture is not allocated");
}
return tex;
}
//------------------------------------
void ofImage::setFromPixels(unsigned char * newPixels, int w, int h, int newType, bool bOrderIsRGB){
if (!myPixels.bAllocated){
allocate(w, h, newType);
}
if (!((width == w) && (height == h) && (type == newType))){
clear();
allocate(w,h, newType);
}
int newBpp = 0;
switch (type){
case OF_IMAGE_GRAYSCALE:
newBpp = 8;
break;
case OF_IMAGE_COLOR:
newBpp = 24;
break;
case OF_IMAGE_COLOR_ALPHA:
newBpp = 32;
break;
default:
ofLog(OF_LOG_ERROR,"error = bad imageType in ofImage::setFromPixels");
return;
}
allocatePixels(myPixels, w, h, newBpp);
int bytesPerPixel = myPixels.bitsPerPixel / 8;
memcpy(myPixels.pixels, newPixels, w*h*bytesPerPixel);
if (myPixels.bytesPerPixel > 1){
if (!bOrderIsRGB){
swapRgb(myPixels);
}
}
update();
}
//------------------------------------
void ofImage::update(){
if (myPixels.bAllocated == true && bUseTexture == true){
tex.loadData(myPixels.pixels, myPixels.width, myPixels.height, myPixels.glDataType);
}
width = myPixels.width;
height = myPixels.height;
bpp = myPixels.bitsPerPixel;
type = myPixels.ofImageType;
}
//------------------------------------
void ofImage::setUseTexture(bool bUse){
bUseTexture = bUse;
}
//------------------------------------
void ofImage::grabScreen(int _x, int _y, int _w, int _h){
if (!myPixels.bAllocated){
allocate(_w, _h, OF_IMAGE_COLOR);
}
int screenHeight = ofGetHeight();
_y = screenHeight - _y;
_y -= _h; // top, bottom issues
if (!((width == _w) && (height == _h))){
resize(_w, _h);
}
#ifndef TARGET_OF_IPHONE
glPushClientAttrib( GL_CLIENT_PIXEL_STORE_BIT ); // be nice to anyone else who might use pixelStore
#endif
glPixelStorei(GL_PACK_ALIGNMENT, 1); // set read non block aligned...
glReadPixels(_x, _y, _w, _h, myPixels.glDataType,GL_UNSIGNED_BYTE, myPixels.pixels); // read the memory....
#ifndef TARGET_OF_IPHONE
glPopClientAttrib();
#endif
int sizeOfOneLineOfPixels = myPixels.width * myPixels.bytesPerPixel;
unsigned char * tempLineOfPix = new unsigned char[sizeOfOneLineOfPixels];
unsigned char * linea;
unsigned char * lineb;
for (int i = 0; i < myPixels.height/2; i++){
linea = myPixels.pixels + i * sizeOfOneLineOfPixels;
lineb = myPixels.pixels + (myPixels.height-i-1) * sizeOfOneLineOfPixels;
memcpy(tempLineOfPix, linea, sizeOfOneLineOfPixels);
memcpy(linea, lineb, sizeOfOneLineOfPixels);
memcpy(lineb, tempLineOfPix, sizeOfOneLineOfPixels);
}
delete [] tempLineOfPix;
update();
}
//------------------------------------
void ofImage::clone(const ofImage &mom){
allocatePixels(myPixels, mom.width, mom.height, mom.bpp);
memcpy(myPixels.pixels, mom.myPixels.pixels, myPixels.width*myPixels.height*myPixels.bytesPerPixel);
tex.clear();
bUseTexture = mom.bUseTexture;
if (bUseTexture == true){
tex.allocate(myPixels.width, myPixels.height, myPixels.glDataType);
}
update();
}
//------------------------------------
void ofImage::setImageType(int newType){
changeTypeOfPixels(myPixels, newType);
update();
}
//------------------------------------
void ofImage::resize(int newWidth, int newHeight){
resizePixels(myPixels, newWidth, newHeight);
tex.clear();
if (bUseTexture == true){
tex.allocate(myPixels.width, myPixels.height, myPixels.glDataType);
}
update();
}
//----------------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------------
// freeImage based code & utilities:
//----------------------------------------------------
inline void ofImage::swapRgb(ofPixels &pix){
if (pix.bitsPerPixel != 8){
int sizePixels = pix.width*pix.height;
int cnt = 0;
unsigned char temp;
int byteCount = pix.bitsPerPixel/8;
while (cnt < sizePixels){
temp = pix.pixels[cnt*byteCount];
pix.pixels[cnt*byteCount] = pix.pixels[cnt*byteCount+2];
pix.pixels[cnt*byteCount+2] = temp;
cnt++;
}
}
}
//----------------------------------------------------
inline void ofImage::allocatePixels(ofPixels &pix, int width, int height, int bpp){
bool bNeedToAllocate = false;
if (pix.bAllocated == true){
if ( (pix.width == width) && (pix.height == height) && (pix.bitsPerPixel == bpp)){
//ofLog(OF_LOG_NOTICE,"we are good, no reallocation needed");
bNeedToAllocate = false;
} else {
delete pix.pixels;
bNeedToAllocate = true;
}
} else {
bNeedToAllocate = true;
}
int byteCount = bpp / 8;
if (bNeedToAllocate == true){
pix.width = width;
pix.height = height;
pix.bitsPerPixel = bpp;
pix.bytesPerPixel = bpp / 8;
switch (pix.bitsPerPixel){
case 8:
pix.glDataType = GL_LUMINANCE;
pix.ofImageType = OF_IMAGE_GRAYSCALE;
break;
case 24:
pix.glDataType = GL_RGB;
pix.ofImageType = OF_IMAGE_COLOR;
break;
case 32:
pix.glDataType = GL_RGBA;
pix.ofImageType = OF_IMAGE_COLOR_ALPHA;
break;
}
pix.pixels = new unsigned char[pix.width*pix.height*byteCount];
pix.bAllocated = true;
}
}
//----------------------------------------------------
FIBITMAP * ofImage::getBmpFromPixels(ofPixels &pix){
FIBITMAP * bmp = NULL;
int w = pix.width;
int h = pix.height;
unsigned char * pixels = pix.pixels;
int bpp = pix.bitsPerPixel;
int bytesPerPixel = pix.bitsPerPixel / 8;
bmp = FreeImage_ConvertFromRawBits(pixels, w,h, w*bytesPerPixel, bpp, 0,0,0, false);
//this is for grayscale images they need to be paletted from: http://sourceforge.net/forum/message.php?msg_id=2856879
if( pix.ofImageType == OF_IMAGE_GRAYSCALE ){
RGBQUAD *pal = FreeImage_GetPalette(bmp);
for(int i = 0; i < 256; i++) {
pal[i].rgbRed = i;
pal[i].rgbGreen = i;
pal[i].rgbBlue = i;
}
}
return bmp;
}
//----------------------------------------------------
void ofImage::putBmpIntoPixels(FIBITMAP * bmp, ofPixels &pix){
int width = FreeImage_GetWidth(bmp);
int height = FreeImage_GetHeight(bmp);
int bpp = FreeImage_GetBPP(bmp);
int bytesPerPixel = bpp / 8;
//------------------------------------------
// call the allocation routine (which checks if really need to allocate) here:
allocatePixels(pix, width, height, bpp);
FreeImage_ConvertToRawBits(pix.pixels, bmp, width*bytesPerPixel, bpp, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK, false); // get bits
}
//----------------------------------------------------
void ofImage::resizePixels(ofPixels &pix, int newWidth, int newHeight){
FIBITMAP * bmp = getBmpFromPixels(pix);
FIBITMAP * convertedBmp = NULL;
convertedBmp = FreeImage_Rescale(bmp, newWidth, newHeight, FILTER_BICUBIC);
putBmpIntoPixels(convertedBmp, pix);
#ifdef TARGET_LITTLE_ENDIAN
if (pix.bytesPerPixel != 1) swapRgb(pix);
#endif
if (bmp != NULL) FreeImage_Unload(bmp);
if (convertedBmp != NULL) FreeImage_Unload(convertedBmp);
}
//----------------------------------------------------
void ofImage::changeTypeOfPixels(ofPixels &pix, int newType){
if (pix.ofImageType == newType) return;
FIBITMAP * bmp = getBmpFromPixels(pix);
FIBITMAP * convertedBmp = NULL;
// new type !
switch (newType){
//------------------------------------
case OF_IMAGE_GRAYSCALE:
convertedBmp = FreeImage_ConvertToGreyscale(bmp);
break;
//------------------------------------
case OF_IMAGE_COLOR:
convertedBmp = FreeImage_ConvertTo24Bits(bmp);
break;
//------------------------------------
case OF_IMAGE_COLOR_ALPHA:
convertedBmp = FreeImage_ConvertTo32Bits(bmp);
break;
}
putBmpIntoPixels(convertedBmp, pix);
if (bmp != NULL) FreeImage_Unload(bmp);
if (convertedBmp != NULL) FreeImage_Unload(convertedBmp);
}
//----------------------------------------------------
// freeImage based stuff:
void ofCloseFreeImage(){
if (bFreeImageInited){
FreeImage_DeInitialise();
bFreeImageInited = false;
}
}
//----------------------------------------------------
bool ofImage::loadImageIntoPixels(string fileName, ofPixels &pix){
int width, height, bpp;
fileName = ofToDataPath(fileName);
bool bLoaded = false;
FIBITMAP * bmp = NULL;
FREE_IMAGE_FORMAT fif = FIF_UNKNOWN;
fif = FreeImage_GetFileType(fileName.c_str(), 0);
if(fif == FIF_UNKNOWN) {
// or guess via filename
fif = FreeImage_GetFIFFromFilename(fileName.c_str());
}
if((fif != FIF_UNKNOWN) && FreeImage_FIFSupportsReading(fif)) {
bmp = FreeImage_Load(fif, fileName.c_str(), 0);
bLoaded = true;
if (bmp == NULL){
bLoaded = false;
}
}
//-----------------------------
if (bLoaded ){
width = FreeImage_GetWidth(bmp);
height = FreeImage_GetHeight(bmp);
bpp = FreeImage_GetBPP(bmp);
bool bPallette = (FreeImage_GetColorType(bmp) == FIC_PALETTE);
switch (bpp){
case 8:
if (bPallette) {
FIBITMAP * bmpTemp = FreeImage_ConvertTo24Bits(bmp);
if (bmp != NULL) FreeImage_Unload(bmp);
bmp = bmpTemp;
bpp = FreeImage_GetBPP(bmp);
} else {
// do nothing we are grayscale
}
break;
case 24:
// do nothing we are color
break;
case 32:
// do nothing we are colorAlpha
break;
default:
FIBITMAP * bmpTemp = FreeImage_ConvertTo24Bits(bmp);
if (bmp != NULL) FreeImage_Unload(bmp);
bmp = bmpTemp;
bpp = FreeImage_GetBPP(bmp);
}
int byteCount = bpp / 8;
//------------------------------------------
// call the allocation routine (which checks if really need to allocate) here:
allocatePixels(pix, width, height, bpp);
FreeImage_ConvertToRawBits(pix.pixels, bmp, width*byteCount, bpp, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK, false); // get bits
//------------------------------------------
// RGB or RGBA swap
// this can be done with some ill pointer math.
// anyone game?
//
#ifdef TARGET_LITTLE_ENDIAN
if (byteCount != 1) swapRgb(pix);
#endif
//------------------------------------------
} else {
width = height = bpp = 0;
}
if (bmp != NULL){
FreeImage_Unload(bmp);
}
return bLoaded;
}
//----------------------------------------------------------------
void ofImage::saveImageFromPixels(string fileName, ofPixels &pix){
if (pix.bAllocated == false){
ofLog(OF_LOG_ERROR,"error saving image - pixels aren't allocated");
return;
}
#ifdef TARGET_LITTLE_ENDIAN
if (pix.bytesPerPixel != 1) swapRgb(pix);
#endif
FIBITMAP * bmp = getBmpFromPixels(pix);
#ifdef TARGET_LITTLE_ENDIAN
if (pix.bytesPerPixel != 1) swapRgb(pix);
#endif
fileName = ofToDataPath(fileName);
if (pix.bAllocated == true){
FREE_IMAGE_FORMAT fif = FIF_UNKNOWN;
fif = FreeImage_GetFileType(fileName.c_str(), 0);
if(fif == FIF_UNKNOWN) {
// or guess via filename
fif = FreeImage_GetFIFFromFilename(fileName.c_str());
}
if((fif != FIF_UNKNOWN) && FreeImage_FIFSupportsReading(fif)) {
FreeImage_Save(fif, bmp, fileName.c_str(), 0);
}
}
if (bmp != NULL){
FreeImage_Unload(bmp);
}
}
//----------------------------------------------------------
float ofImage::getHeight(){
return height;
}
//----------------------------------------------------------
float ofImage::getWidth(){
return width;
}
//----------------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------------
(C) Æliens
04/09/2009
You may not copy or print any of this material without explicit permission of the author or the publisher.
In case of other copyright issues, contact the author.