EVOLUTION-MANAGER
Edit File: pictureLoader.cpp
// // C++ Implementation: pictureLoader // // Description: // // // Author: Yorn <yorn@gmx.net>, (C) 2009 // // Copyright: See COPYING file that comes with this distribution // // #include "pictureLoader.h" #include <gd.h> #include <iostream> #include <cstring> #define SCALEBITS 8 #define ONE_HALF (1 << (SCALEBITS - 1)) #define FIX(x) ((int) ((x) * (1L<<SCALEBITS) + 0.5)) #define INIT_CLIP int32 tmp #define CLIP(x,n) tmp = (int32)(x+0.5); \ if (tmp > 255) n=255; \ else if (tmp < 0) n=0; \ else n = (uint8)(tmp); PictureLoader::PictureLoader() { } PictureLoader::~PictureLoader() { } bool PictureLoader::load(RGBPlane& retPlane, const std::string& filename, uint32 _width, uint32 _height, bool useBiggest) { std::string::size_type suffixStart(filename.find_last_of('.')); if (suffixStart == std::string::npos) { std::cerr << "RGBPlane::load: Can not identify suffix of <"<<filename<<">\n"; return(false); } std::string suffix(filename.substr(suffixStart+1)); gdImagePtr im(0); FILE* in(0); in = fopen(filename.c_str(), "rb"); if (in == 0) { std::cerr << "RGBPlane::load: Can not open file <"<<filename<<">\n"; return(false); } if ((suffix == "jpg") || (suffix == "JPG") || (suffix == "jpeg") || (suffix == "JPEG")) { im = gdImageCreateFromJpeg(in); } if ((suffix == "png") || (suffix == "PNG")) { im = gdImageCreateFromPng(in); } if ((suffix == "gif") || (suffix == "GIF")) { im = gdImageCreateFromGif(in); } if (im != 0) { if ((_width != 0) && (_height != 0)) { uint32 origWidth(gdImageSX(im)); uint32 origHeight(gdImageSY(im)); /* calculate the new size -> picture must fit into the given rectangle */ float factorX = (_width*1.0)/(origWidth*1.0); float factorY = (_height*1.0)/(origHeight*1.0); float factor(1.0); #ifdef DEBUG std::cout << "wanted: "<<_width<<"x"<<_height<<" orig: " <<origWidth<<"x"<<origHeight<<std::endl; #endif if (useBiggest) { if (factorX < factorY) factor = factorY; else factor = factorX; } else { if (factorX < factorY) factor = factorX; else factor = factorY; } #ifdef DEBUG std::cerr << "recalculating ("<<factor<<") image to " <<(uint32) (origWidth*factor+0.5)<< "x" << (uint32) (origHeight*factor+0.5)<<std::endl; #endif gdImagePtr resampled = gdImageCreateTrueColor((uint32) (origWidth *factor+0.5), (uint32) (origHeight*factor+0.5)); gdImageCopyResampled(resampled, im, 0, 0, 0, 0, resampled->sx, resampled->sy, origWidth, origHeight); retPlane = convertToRgbPlane(resampled); gdImageDestroy(resampled); } else { retPlane = convertToRgbPlane(im); } gdImageDestroy(im); fclose(in); return (true); } fclose(in); std::cerr << "RGBPlane::load: Can not read file of type <"<<suffix<<">\n"; return(false); } RGBPlane PictureLoader::convertToRgbPlane(gdImagePtr im) { uint32 width = gdImageSX(im); uint32 height = gdImageSY(im); RGBPlane pic(width, height); int c(0); uint32 x(0); for (uint32 i(0); i<height; ++i) for (uint32 j(0); j<width; ++j) { c = gdImageGetPixel(im, j, i); pic->plane[x++] = gdImageRed(im, c); pic->plane[x++] = gdImageGreen(im, c); pic->plane[x++] = gdImageBlue(im,c); pic->plane[x++] = gdImageAlpha(im,c); } return(pic); } PictureLoader::SuffixType PictureLoader::identifySuffix(const std::string& filename) { std::string::size_type suffixStart(filename.find_last_of('.')); if (suffixStart == std::string::npos) { std::cerr << "RGBPlane::load: Can not identify suffix of <"<<filename <<">\n"; return (suffix_unknown); } std::string suffix(filename.substr(suffixStart+1)); if ((suffix == "jpg") || (suffix == "JPG") || (suffix == "jpeg") || (suffix == "JPEG")) { return (suffix_jpg); } if ((suffix == "png") || (suffix == "PNG")) { return (suffix_png); } if ((suffix == "gif") || (suffix == "GIF")) { return (suffix_gif); } return (suffix_unknown); } bool PictureLoader::save(RGBPlane& pic, const std::string& filename, uint32 newWidth, uint32 newHeight) { int actColor; int planeCount(0); SuffixType type = identifySuffix(filename); gdImagePtr im = gdImageCreateTrueColor(pic->width, pic->height); for (uint32 i(0); i < pic->height; ++i) for (uint32 j(0); j < pic->width; ++j) { int red = pic->plane[planeCount++]; int green = pic->plane[planeCount++]; int blue = pic->plane[planeCount++]; actColor = gdImageColorAllocate(im, red, green, blue); planeCount++; // alpha channel not in use gdImageSetPixel(im, j, i, actColor); } FILE* out = fopen(filename.c_str(), "wb"); if ((newWidth != 0) || (newHeight != 0)) { if (newWidth == 0) newWidth = pic->width*newHeight/pic->height; if (newHeight == 0) newHeight = pic->height*newWidth/pic->width; gdImagePtr resampled; resampled = gdImageCreateTrueColor(newWidth, newHeight); gdImageCopyResampled(resampled, im, 0, 0, 0, 0, resampled->sx, resampled->sy, pic->width, pic->height); switch (type) { case suffix_jpg: gdImageJpeg(resampled, out, -1); break; case suffix_png: gdImagePng(resampled, out); break; // case suffix_gif: default: std::cerr << "can not identify suffix\n"; } /* Write JPEG using default quality */ gdImageDestroy(resampled); } else { switch (type) { case suffix_jpg: gdImageJpeg(im, out, -1); break; case suffix_png: gdImagePng(im, out); break; // case suffix_gif: default: std::cerr << "can not identify suffix\n"; } } /* Close file */ fclose(out); /* Destroy it */ gdImageDestroy(im); return (true); } #ifdef HAVE_LIBTHEORAENC void PictureLoader::exportYCrCb_theora(RGBPlane& picture, th_ycbcr_buffer& buffer) { uint32 frameWidth; uint32 frameHeight; uint32 XOffset; uint32 YOffset; /* recalculate the buffer (must be multiple of 16) */ frameWidth = (picture->width+15)&~0xF; frameHeight = (picture->height+15)&~0xF; // We force the offset to be even. // This ensures that the chroma samples align properly with the luma // samples. XOffset = ((frameWidth - picture->width)/4); //&~1; YOffset = ((frameHeight - picture->height)/4); //&~1; // std::cerr << width <<" x "<<height<<" "<<frameWidth<<" x "<<frameHeight <<" "<<XOffset<<" "<<YOffset<<std::endl; uint32 stride = frameWidth; if ((frameWidth != (uint32)buffer[0].width) || (frameHeight != (uint32)buffer[0].height)) { /* delete old planes */ delete buffer[0].data; delete buffer[1].data; delete buffer[2].data; /* create a new YCbCrPlane */ buffer[0].width = frameWidth; buffer[0].height = frameHeight; buffer[0].stride = stride; buffer[0].data = new uint8[frameWidth*frameHeight]; // memset(buffer[0].data, 0x00, frameWidth*frameHeight); buffer[1].width = frameWidth/2; buffer[1].height = frameHeight/2; buffer[1].stride = stride/2; buffer[1].data = new uint8[frameWidth*frameHeight/4]; // memset(buffer[1].data, 0x00, frameWidth*frameHeight/4); buffer[2].width = frameWidth/2; buffer[2].height = frameHeight/2; buffer[2].stride = stride/2; buffer[2].data = new uint8[frameWidth*frameHeight/4]; // memset(buffer[2].data, 0x00, frameWidth*frameHeight/4); } int wrap, wrap3; wrap = stride; wrap3 = picture->width * 4; uint32 HeightPrecalculation0x; uint32 HeightPrecalculation1x; uint32 CromaPrecalculation; uint32 position00; uint32 position01; uint32 position10; uint32 position11; uint32 inPos00; uint32 inPos01; uint32 inPos10; uint32 inPos11; uint32 red_sample; uint32 green_sample; uint32 blue_sample; uint32 cromaPos; for (uint32 i(0); i<(uint32)picture->height/2; ++i) { HeightPrecalculation0x = (2*(i+YOffset))*buffer[0].stride; HeightPrecalculation1x = (2*(i+YOffset)+1)*buffer[0].stride; CromaPrecalculation = (i+YOffset)*buffer[1].stride; for (uint32 j(0); j<(uint32)picture->width/2; ++j) { position00 = HeightPrecalculation0x+(2*(j+XOffset)); position01 = HeightPrecalculation0x+(2*(j+XOffset)+1); position10 = HeightPrecalculation1x+(2*(j+XOffset)); position11 = HeightPrecalculation1x+(2*(j+XOffset)+1); inPos00 = 4*((2*i)*picture->width+(2*j)); inPos01 = 4*((2*i)*picture->width+(2*j+1)); inPos10 = 4*((2*i+1)*picture->width+(2*j)); inPos11 = 4*((2*i+1)*picture->width+(2*j+1)); cromaPos = CromaPrecalculation+(j+XOffset); buffer[0].data[position00] = (FIX(0.29900) * picture->plane[inPos00] + FIX(0.58700) * picture->plane[inPos00+1] + FIX(0.11400) * picture->plane[inPos00+2] + ONE_HALF) >> SCALEBITS; buffer[0].data[position01] = (FIX(0.29900) * picture->plane[inPos01] + FIX(0.58700) * picture->plane[inPos01+1] + FIX(0.11400) * picture->plane[inPos01+2] + ONE_HALF) >> SCALEBITS; buffer[0].data[position10] = (FIX(0.29900) * picture->plane[inPos10] + FIX(0.58700) * picture->plane[inPos10+1] + FIX(0.11400) * picture->plane[inPos10+2] + ONE_HALF) >> SCALEBITS; buffer[0].data[position11] = (FIX(0.29900) * picture->plane[inPos11] + FIX(0.58700) * picture->plane[inPos11+1] + FIX(0.11400) * picture->plane[inPos11+2] + ONE_HALF) >> SCALEBITS; red_sample = picture->plane[inPos00] + picture->plane[inPos01] + picture->plane[inPos10] + picture->plane[inPos11]; green_sample = picture->plane[inPos00+1] + picture->plane[inPos01+1] + picture->plane[inPos10+1] + picture->plane[inPos11+1]; blue_sample = picture->plane[inPos00+2] + picture->plane[inPos01+2] + picture->plane[inPos10+2] + picture->plane[inPos11+2]; buffer[1].data[cromaPos] = ((-FIX(0.16874) * red_sample - FIX(0.33126) * green_sample +FIX(0.50000) * blue_sample + 4 * ONE_HALF- 1) >> (SCALEBITS + 2)) + 128; buffer[2].data[cromaPos] = ((FIX(0.50000) * red_sample - FIX(0.41869) * green_sample -FIX(0.08131) * blue_sample + 4 * ONE_HALF - 1) >> (SCALEBITS + 2)) + 128; } } } void PictureLoader::exportYCrCb_444_theora(RGBPlane& picture, th_ycbcr_buffer& buffer) { uint32 frameWidth; uint32 frameHeight; uint32 XOffset; uint32 YOffset; /* recalculate the buffer (must be multiple of 16) */ frameWidth = (picture->width+15)&~0xF; frameHeight = (picture->height+15)&~0xF; // We force the offset to be even. // This ensures that the chroma samples align properly with the luma // samples. XOffset = ((frameWidth - picture->width)/4); //&~1; YOffset = ((frameHeight - picture->height)/4); //&~1; // std::cerr << width <<" x "<<height<<" "<<frameWidth<<" x "<<frameHeight <<" "<<XOffset<<" "<<YOffset<<std::endl; uint32 stride = frameWidth; if ((frameWidth != (uint32)buffer[0].width) || (frameHeight != (uint32)buffer[0].height)) { /* delete old planes */ delete buffer[0].data; delete buffer[1].data; delete buffer[2].data; /* create a new YCbCrPlane */ buffer[0].width = frameWidth; buffer[0].height = frameHeight; buffer[0].stride = stride; buffer[0].data = new uint8[frameWidth*frameHeight]; // memset(buffer[0].data, 0x00, frameWidth*frameHeight); buffer[1].width = frameWidth; buffer[1].height = frameHeight; buffer[1].stride = stride; buffer[1].data = new uint8[frameWidth*frameHeight]; // memset(buffer[1].data, 0x00, frameWidth*frameHeight/4); buffer[2].width = frameWidth; buffer[2].height = frameHeight; buffer[2].stride = stride; buffer[2].data = new uint8[frameWidth*frameHeight]; // memset(buffer[2].data, 0x00, frameWidth*frameHeight/4); } int wrap, wrap3; wrap = stride; wrap3 = picture->width * 4; uint32 HeightPrecalculation; uint32 HeightPrecalculation1x; uint32 CromaPrecalculation; uint32 position00; uint32 position01; uint32 position10; uint32 position11; uint32 ycrcbPosition; uint32 rgbPosition; uint32 inPos10; uint32 inPos11; uint32 red_sample; uint32 green_sample; uint32 blue_sample; uint32 cromaPos; for (uint32 i(0); i<(uint32)picture->height; ++i) { HeightPrecalculation = (i+YOffset)*buffer[0].stride; for (uint32 j(0); j<(uint32)picture->width; ++j) { ycrcbPosition = HeightPrecalculation+(j+XOffset); rgbPosition = 4*(i*picture->width+j); red_sample = picture->plane[rgbPosition]; green_sample = picture->plane[rgbPosition+1]; blue_sample = picture->plane[rgbPosition+2]; buffer[0].data[ycrcbPosition] = (FIX(0.29900) * red_sample + FIX(0.58700) * green_sample + FIX(0.11400) * blue_sample + ONE_HALF) >> SCALEBITS; buffer[1].data[ycrcbPosition] = ((-FIX(0.67496) * red_sample - FIX(1.32504) * green_sample +FIX(2.0) * blue_sample + 4 * ONE_HALF- 1) >> (SCALEBITS + 2)) + 128; buffer[2].data[ycrcbPosition] = ((FIX(2.0) * red_sample - FIX(1.67476) * green_sample -FIX(0.32524) * blue_sample + 4 * ONE_HALF - 1) >> (SCALEBITS + 2)) + 128; } } } RGBPlane PictureLoader::importYCrCb_theora(const th_ycbcr_buffer& buffer, uint32 _width, uint32 _height, int32 XOffset, int32 YOffset) { uint32 width; uint32 height; // what size to use? if ((_width == 0) || (_height == 0)) { width = buffer[0].width; height = buffer[0].height; XOffset = 0; YOffset = 0; } else { width = _width; height = _height; } RGBPlane retPlane(width, height); // uint32 size; // Offset calculated for the croma planes (which is the reference) if (XOffset == -1) { XOffset = ((buffer[0].width - width)/4); // guessing } else { XOffset /= 2; // why 1/2 ? - do not remember } // Y-Offset is calculated from the bottom, but we start from upper corner if (YOffset == -1) { YOffset = ((buffer[0].height - height)/4); // guessing } else { // YOffset is from botton, but we need the start YOffset = YOffset/2; } uint8* YPlane = buffer[0].data; uint8* CrPlane = buffer[2].data; uint8* CbPlane = buffer[1].data; INIT_CLIP; uint32 HeightPrecalculation0x; uint32 HeightPrecalculation1x; uint32 CromaPrecalculation; // using cr plain as reference for (uint32 i(0); i<(uint32)height/2; ++i) { HeightPrecalculation0x = (2*(i+YOffset))*buffer[0].stride; HeightPrecalculation1x = (2*(i+YOffset)+1)*buffer[0].stride; CromaPrecalculation = (i+YOffset)*buffer[1].stride; for (uint32 j(0); j<(uint32)width/2; ++j) { // if ( (i<YOffset) || (j<XOffset) || (i>(height-YOffset)) || (j>(width-XOffset))) // continue; uint32 position00 = HeightPrecalculation0x+(2*(j+XOffset)); uint32 position01 = HeightPrecalculation0x+(2*(j+XOffset)+1); uint32 position10 = HeightPrecalculation1x+(2*(j+XOffset)); uint32 position11 = HeightPrecalculation1x+(2*(j+XOffset)+1); uint32 outPos00 = 4*((2*i)*width+(2*j)); uint32 outPos01 = 4*((2*i)*width+(2*j+1)); uint32 outPos10 = 4*((2*i+1)*width+(2*j)); uint32 outPos11 = 4*((2*i+1)*width+(2*j+1)); uint32 cromaPos = CromaPrecalculation+(j+XOffset); /* red */ int32 value; value = (uint32)(YPlane[position00] + (1.402 * (CrPlane[cromaPos] - 128))); CLIP(value, retPlane->plane[outPos00]); value = (uint32)(YPlane[position01] + (1.402 * (CrPlane[cromaPos] - 128))); CLIP(value, retPlane->plane[outPos01]); value = (uint32)(YPlane[position10] + (1.402 * (CrPlane[cromaPos] - 128))); CLIP(value, retPlane->plane[outPos10]); value = (uint32)(YPlane[position11] + (1.402 * (CrPlane[cromaPos] - 128))); CLIP(value, retPlane->plane[outPos11]); /* green */ value = (uint32)(YPlane[position00] - (0.34414 * (CbPlane[cromaPos] - 128)) - (0.71414 * (CrPlane[cromaPos] - 128))); CLIP(value, retPlane->plane[outPos00+1]); value = (uint32)(YPlane[position01] - (0.34414 * (CbPlane[cromaPos] - 128)) - (0.71414 * (CrPlane[cromaPos] - 128))); CLIP(value, retPlane->plane[outPos01+1]); value = (uint32)(YPlane[position10] - (0.34414 * (CbPlane[cromaPos] - 128)) - (0.71414 * (CrPlane[cromaPos] - 128))); CLIP(value, retPlane->plane[outPos10+1]); value = (uint32)(YPlane[position11] - (0.34414 * (CbPlane[cromaPos] - 128)) - (0.71414 * (CrPlane[cromaPos] - 128))); CLIP(value, retPlane->plane[outPos11+1]); /* blue */ value = (uint32)(YPlane[position00] + (1.772 * (CbPlane[cromaPos] - 128))); CLIP(value, retPlane->plane[outPos00+2]); value = (uint32)(YPlane[position00] + (1.772 * (CbPlane[cromaPos] - 128))); CLIP(value, retPlane->plane[outPos01+2]); value = (uint32)(YPlane[position00] + (1.772 * (CbPlane[cromaPos] - 128))); CLIP(value, retPlane->plane[outPos10+2]); value = (uint32)(YPlane[position00] + (1.772 * (CbPlane[cromaPos] - 128))); CLIP(value, retPlane->plane[outPos11+2]); retPlane->plane[outPos00+3] = 255; retPlane->plane[outPos01+3] = 255; retPlane->plane[outPos10+3] = 255; retPlane->plane[outPos11+3] = 255; } } return(retPlane); } #endif