void ofPixels_<PixelType>::cropTo(ofPixels_<PixelType> &toPix, int x, int y, int _width, int _height) const{ if (bAllocated){ if(&toPix == this){ toPix.crop(x,y,_width,_height); return; } _width = ofClamp(_width,1,getWidth()); _height = ofClamp(_height,1,getHeight()); if ((toPix.width != _width) || (toPix.height != _height) || (toPix.pixelFormat != pixelFormat)){ toPix.allocate(_width, _height, pixelFormat); } // this prevents having to do a check for bounds in the for loop; int minX = MAX(x, 0) * getNumChannels(); int maxX = MIN(x+_width, width) * getNumChannels(); int minY = MAX(y, 0); int maxY = MIN(y+_height, height); iterator newPixel = toPix.begin(); for(ConstLine line = getConstLines().begin()+minY; line!=getConstLines().begin()+maxY; ++line ){ for(const_iterator pixel = line.begin()+minX; pixel<line.begin()+maxX; ++pixel){ *newPixel++ = *pixel; } } } }
void ofPixels_<PixelType>::cropTo(ofPixels_<PixelType> &toPix, int x, int y, int _width, int _height) const{ if (bAllocated){ if(&toPix == this){ toPix.crop(x,y,_width,_height); return; } _width = ofClamp(_width,1,getWidth()); _height = ofClamp(_height,1,getHeight()); if ((toPix.width != _width) || (toPix.height != _height) || (toPix.pixelFormat != pixelFormat)){ toPix.allocate(_width, _height, pixelFormat); } // this prevents having to do a check for bounds in the for loop; int minX = MAX(x, 0); int maxX = MIN(x+_width, width); int minY = MAX(y, 0); int maxY = MIN(y+_height, height); auto newPixel = toPix.getPixelsIter().begin(); for(auto line: getConstLines(minY, maxY - minY)){ for(auto pixel: line.getPixels(minX, maxX - minX)){ newPixel++ = pixel; } } } }
void putBmpIntoPixels(FIBITMAP * bmp, ofPixels_<PixelType> &pix, bool swapForLittleEndian = true) { // convert to correct type depending on type of input bmp and PixelType FIBITMAP* bmpConverted = NULL; FREE_IMAGE_TYPE imgType = FreeImage_GetImageType(bmp); if(sizeof(PixelType)==1 && (FreeImage_GetColorType(bmp) == FIC_PALETTE || FreeImage_GetBPP(bmp) < 8 || imgType!=FIT_BITMAP)) { if(FreeImage_IsTransparent(bmp)) { bmpConverted = FreeImage_ConvertTo32Bits(bmp); } else { bmpConverted = FreeImage_ConvertTo24Bits(bmp); } bmp = bmpConverted; }else if(sizeof(PixelType)==2 && imgType!=FIT_UINT16 && imgType!=FIT_RGB16 && imgType!=FIT_RGBA16){ if(FreeImage_IsTransparent(bmp)) { bmpConverted = FreeImage_ConvertToType(bmp,FIT_RGBA16); } else { bmpConverted = FreeImage_ConvertToType(bmp,FIT_RGB16); } bmp = bmpConverted; }else if(sizeof(PixelType)==4 && imgType!=FIT_FLOAT && imgType!=FIT_RGBF && imgType!=FIT_RGBAF){ if(FreeImage_IsTransparent(bmp)) { bmpConverted = FreeImage_ConvertToType(bmp,FIT_RGBAF); } else { bmpConverted = FreeImage_ConvertToType(bmp,FIT_RGBF); } bmp = bmpConverted; } unsigned int width = FreeImage_GetWidth(bmp); unsigned int height = FreeImage_GetHeight(bmp); unsigned int bpp = FreeImage_GetBPP(bmp); unsigned int channels = (bpp / sizeof(PixelType)) / 8; unsigned int pitch = FreeImage_GetPitch(bmp); // ofPixels are top left, FIBITMAP is bottom left FreeImage_FlipVertical(bmp); unsigned char* bmpBits = FreeImage_GetBits(bmp); if(bmpBits != NULL) { pix.setFromAlignedPixels((PixelType*) bmpBits, width, height, channels, pitch); } else { ofLogError("ofImage") << "putBmpIntoPixels(): unable to set ofPixels from FIBITMAP"; } if(bmpConverted != NULL) { FreeImage_Unload(bmpConverted); } #ifdef TARGET_LITTLE_ENDIAN if(swapForLittleEndian && sizeof(PixelType) == 1) { pix.swapRgb(); } #endif }
void removeIslands(ofPixels_<T>& img) { int w = img.getWidth(), h = img.getHeight(); int ia1=-w-1,ia2=-w-0,ia3=-w+1,ib1=-0-1,ib3=-0+1,ic1=+w-1,ic2=+w-0,ic3=+w+1; T* p = img.getPixels(); for(int y = 1; y + 1 < h; y++) { for(int x = 1; x + 1 < w; x++) { int i = y * w + x; if(p[i]) { if(!p[i+ia1]&&!p[i+ia2]&&!p[i+ia3]&&!p[i+ib1]&&!p[i+ib3]&&!p[i+ic1]&&!p[i+ic2]&&!p[i+ic3]) { p[i] = 0; } } } } }
void ofImage_<PixelType>::changeTypeOfPixels(ofPixels_<PixelType> &pix, ofImageType newType){ int oldType = pix.getImageType(); if (oldType == newType) { return; // no need to reallocate } FIBITMAP * bmp = getBmpFromPixels(pix); FIBITMAP * convertedBmp = nullptr; 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; default: ofLogError("ofImage") << "changeTypeOfPixels(): unknown image type: " << newType; break; } putBmpIntoPixels(convertedBmp, pix, false); if (bmp != nullptr) { FreeImage_Unload(bmp); } if (convertedBmp != nullptr) { FreeImage_Unload(convertedBmp); } }
std::size_t DefaultBitImageCommands::selectBitImageMode(const ofPixels_<unsigned char>& binaryPixels, BaseCodes::PrintResolution printResolution) { // width = nL + (nH * 256) // nH is the HIGH part of the WIDTH VALUE. // nL is the LOW part of the WIDTH VALUE. // nH will always be 0 for values less that 256 (1 byte) uint8_t nH = getHighByte(binaryPixels.getWidth()); uint8_t nL = getLowByte(binaryPixels.getWidth()); std::vector<uint8_t> buffer; buffer.push_back(BaseCodes::ESC); buffer.push_back('*'); buffer.push_back(printResolution); buffer.push_back(nL); buffer.push_back(nH); uint8_t currentByte = 0; int bitIndex = 0; for(int x = 0; x < binaryPixels.getWidth(); ++x) { currentByte = 0; bitIndex = 0; for(int y = 0; y < binaryPixels.getHeight(); ++y) { bool binaryValue = binaryPixels[binaryPixels.getPixelIndex(x,y)] < ofColor_<unsigned char>::limit() / 2; currentByte |= binaryValue << (7 - bitIndex); bitIndex++; if(8 == bitIndex) { buffer.push_back(currentByte); currentByte = 0; bitIndex = 0; } } } return writeBytes(buffer); }
void ofPixels_<PixelType>::mirrorTo(ofPixels_<PixelType> & dst, bool vertically, bool horizontal) const{ if(&dst == this){ dst.mirror(vertically,horizontal); return; } if (!vertically && !horizontal){ dst = *this; return; } int bytesPerPixel = getNumChannels(); dst.allocate(width, height, getPixelFormat()); if(vertically && !horizontal){ auto dstLines = dst.getLines(); auto lineSrc = getConstLines().begin(); auto line = --dstLines.end(); auto stride = line.getStride(); for(; line>=dstLines.begin(); --line, ++lineSrc){ memcpy(line.begin(), lineSrc.begin(), stride); } }else if (!vertically && horizontal){ int wToDo = width/2; int hToDo = height; for (int i = 0; i < wToDo; i++){ for (int j = 0; j < hToDo; j++){ int pixelb = i; int pixela = j*width + i; for (int k = 0; k < bytesPerPixel; k++){ dst[pixela*bytesPerPixel + k] = pixels[pixelb*bytesPerPixel + k]; dst[pixelb*bytesPerPixel + k] = pixels[pixela*bytesPerPixel + k]; } } } } else { // I couldn't think of a good way to do this in place. I'm sure there is. mirrorTo(dst,true, false); dst.mirror(false, true); } }
bool ofPixels_<PixelType>::blendInto(ofPixels_<PixelType> &dst, int xTo, int yTo) const{ if (!(isAllocated()) || !(dst.isAllocated()) || getBytesPerPixel() != dst.getBytesPerPixel() || xTo + getWidth()>dst.getWidth() || yTo + getHeight()>dst.getHeight() || getNumChannels()==0) return false; std::function<void(const ConstPixel&,Pixel&)> blendFunc; switch(getNumChannels()){ case 1: blendFunc = [](const ConstPixel&src, Pixel&dst){ dst[0] = clampedAdd(src[0], dst[0]); }; break; case 2: blendFunc = [](const ConstPixel&src, Pixel&dst){ dst[0] = clampedAdd(src[0], dst[0] / ofColor_<PixelType>::limit() * (ofColor_<PixelType>::limit() - src[1])); dst[1] = clampedAdd(src[1], dst[1] / ofColor_<PixelType>::limit() * (ofColor_<PixelType>::limit() - src[1])); }; break; case 3: blendFunc = [](const ConstPixel&src, Pixel&dst){ dst[0] = clampedAdd(src[0], dst[0]); dst[1] = clampedAdd(src[1], dst[1]); dst[2] = clampedAdd(src[2], dst[2]); }; break; case 4: blendFunc = [](const ConstPixel&src, Pixel&dst){ dst[0] = clampedAdd(src[0], dst[0] / ofColor_<PixelType>::limit() * (ofColor_<PixelType>::limit() - src[3])); dst[1] = clampedAdd(src[1], dst[1] / ofColor_<PixelType>::limit() * (ofColor_<PixelType>::limit() - src[3])); dst[2] = clampedAdd(src[2], dst[2] / ofColor_<PixelType>::limit() * (ofColor_<PixelType>::limit() - src[3])); dst[3] = clampedAdd(src[3], dst[3] / ofColor_<PixelType>::limit() * (ofColor_<PixelType>::limit() - src[3])); }; break; } auto dstLine = dst.getLine(yTo); for(auto line: getConstLines()){ auto dstPixel = dstLine.getPixels().begin() + xTo; for(auto p: line.getPixels()){ blendFunc(p,dstPixel); dstPixel++; } dstLine++; } return true; }
void ofPixels_<PixelType>::setChannel(int channel, const ofPixels_<PixelType> channelPixels){ int channels = channelsFromPixelFormat(pixelFormat); if(channels==0) return; channel = ofClamp(channel,0,channels-1); const_iterator channelPixel = channelPixels.begin(); for(auto p: getPixelsIter()){ p[channel] = *channelPixel++; } }
void ofPixels_<PixelType>::setChannel(int channel, const ofPixels_<PixelType> channelPixels){ int channels = channelsFromPixelFormat(pixelFormat); if(channels==0) return; channel = ofClamp(channel,0,channels-1); const_iterator channelPixel = channelPixels.begin(); iterator _end = end(); for(iterator i=begin()+channel;i<_end;i+=channels,++channelPixel){ *i = *channelPixel; } }
void putBmpIntoPixels(FIBITMAP * bmp, ofPixels_<PixelType> &pix, bool swapForLittleEndian = true) { // some images use a palette, or <8 bpp, so convert them to raster 8-bit channels FIBITMAP* bmpConverted = NULL; if(FreeImage_GetColorType(bmp) == FIC_PALETTE || FreeImage_GetBPP(bmp) < 8) { if(FreeImage_IsTransparent(bmp)) { bmpConverted = FreeImage_ConvertTo32Bits(bmp); } else { bmpConverted = FreeImage_ConvertTo24Bits(bmp); } bmp = bmpConverted; } unsigned int width = FreeImage_GetWidth(bmp); unsigned int height = FreeImage_GetHeight(bmp); unsigned int bpp = FreeImage_GetBPP(bmp); unsigned int channels = (bpp / sizeof(PixelType)) / 8; unsigned int pitch = FreeImage_GetPitch(bmp); // ofPixels are top left, FIBITMAP is bottom left FreeImage_FlipVertical(bmp); unsigned char* bmpBits = FreeImage_GetBits(bmp); if(bmpBits != NULL) { pix.setFromAlignedPixels((PixelType*) bmpBits, width, height, channels, pitch); } else { ofLogError() << "ofImage::putBmpIntoPixels() unable to set ofPixels from FIBITMAP"; } if(bmpConverted != NULL) { FreeImage_Unload(bmpConverted); } #ifdef TARGET_LITTLE_ENDIAN if(swapForLittleEndian && sizeof(PixelType) == 1) { pix.swapRgb(); } #endif }
void ofPixels_<PixelType>::mirrorTo(ofPixels_<PixelType> & dst, bool vertically, bool horizontal) const{ if(&dst == this){ dst.mirror(vertically,horizontal); return; } if (!vertically && !horizontal){ dst = *this; return; } int bytesPerPixel = getNumChannels(); if (! (vertically && horizontal)){ int wToDo = horizontal ? width/2 : width; int hToDo = vertically ? height/2 : height; for (int i = 0; i < wToDo; i++){ for (int j = 0; j < hToDo; j++){ int pixelb = (vertically ? (height - j - 1) : j) * width + (horizontal ? (width - i - 1) : i); int pixela = j*width + i; for (int k = 0; k < bytesPerPixel; k++){ dst[pixela*bytesPerPixel + k] = pixels[pixelb*bytesPerPixel + k]; dst[pixelb*bytesPerPixel + k] = pixels[pixela*bytesPerPixel + k]; } } } } else { // I couldn't think of a good way to do this in place. I'm sure there is. mirrorTo(dst,true, false); dst.mirror(false, true); } }
ofPixels_<unsigned char> ImageUtils::scaleAndCropTo(const ofPixels_<unsigned char>& pixels, int width, int height, ofScaleMode scaleMode) { ofRectangle inRect(0,0,pixels.getWidth(),pixels.getHeight()); ofRectangle outRect(0,0,width,height); inRect.scaleTo(outRect,scaleMode); ofPixels_<unsigned char> inPixels = pixels; inPixels.resize(inRect.getWidth(),inRect.getHeight()); ofPixels_<unsigned char> outPixels; inPixels.cropTo(outPixels, outRect.x - inRect.x, 0, outRect.width, outRect.height); return outPixels; }
void ofImage_<PixelType>::changeTypeOfPixels(ofPixels_<PixelType> &pix, ofImageType newType){ int oldType = pix.getImageType(); if (oldType == newType) { return; // no need to reallocate } FIBITMAP * bmp = getBmpFromPixels(pix); FIBITMAP * convertedBmp = NULL; 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; default: ofLogError("ofImage") << "changeTypeOfPixels(): unknown image type: " << newType; break; } putBmpIntoPixels(convertedBmp, pix, false); if (bmp != NULL) { FreeImage_Unload(bmp); } if (convertedBmp != NULL) { FreeImage_Unload(convertedBmp); } if(bUseTexture){ // always reallocate the texture. if ofTexture doesn't need reallocation, // it doesn't have to. but it needs to change the internal format. tex.allocate(pixels.getWidth(), pixels.getHeight(), ofGetGlInternalFormat(pixels)); if(ofGetGLProgrammableRenderer() && (pixels.getNumChannels()==1 || pixels.getNumChannels()==2)){ tex.setRGToRGBASwizzles(true); } } }
void ofImage_<PixelType>::changeTypeOfPixels(ofPixels_<PixelType> &pix, ofImageType newType){ int oldType = pix.getImageType(); if (oldType == newType) { return; // no need to reallocate } FIBITMAP * bmp = getBmpFromPixels(pix); FIBITMAP * convertedBmp = NULL; 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; default: ofLog(OF_LOG_ERROR, "changeTypeOfPixels: format not supported"); break; } putBmpIntoPixels(convertedBmp, pix, false); if (bmp != NULL) { FreeImage_Unload(bmp); } if (convertedBmp != NULL) { FreeImage_Unload(convertedBmp); } if(bUseTexture){ // always reallocate the texture. if ofTexture doesn't need reallocation, // it doesn't have to. but it needs to change the internal format. tex.allocate(pixels.getWidth(), pixels.getHeight(), ofGetGlInternalFormat(pixels)); } }
void ofPixels_<PixelType>::cropTo(ofPixels_<PixelType> &toPix, int x, int y, int _width, int _height){ if (bAllocated == true){ _width = ofClamp(_width,1,getWidth()); _height = ofClamp(_height,1,getHeight()); int bytesPerPixel = channels; if ((toPix.width != _width) || (toPix.height != _height) || (toPix.channels != channels)){ toPix.allocate(_width, _height, channels); } int newWidth = _width; PixelType * newPixels = toPix.pixels; // this prevents having to do a check for bounds in the for loop; int minX = MAX(x, 0); int maxX = MIN(x+_width, width); int minY = MAX(y, 0); int maxY = MIN(y+_height, height); // TODO: point math can help speed this up: for (int i = minX; i < maxX; i++){ for (int j = minY; j < maxY; j++){ int newPixel = (j-y) * newWidth + (i-x); int oldPixel = (j) * width + (i); for (int k = 0; k < bytesPerPixel; k++){ newPixels[newPixel*bytesPerPixel + k] = pixels[oldPixel*bytesPerPixel + k]; } } } } }
ofPixels_<unsigned char> ImageUtils::toGrayscale(const ofPixels_<unsigned char>& pixels) { if (OF_IMAGE_GRAYSCALE == pixels.getImageType()) { return pixels; } ofPixels pix; pix.allocate(pixels.getWidth(), pixels.getHeight(), OF_IMAGE_GRAYSCALE); for (std::size_t x = 0; x < pixels.getWidth(); ++x) { for (std::size_t y = 0; y < pixels.getHeight(); ++y) { ofColor_<unsigned char> c = pixels.getColor(x, y); pix.setColor(x, y, 0.21 * c.r + 0.71 * c.g + 0.07 * c.b); } } return pix; }
void ofImage_<PixelType>::setFromPixels(const ofPixels_<PixelType> & pixels){ setFromPixels(pixels.getPixels(),pixels.getWidth(),pixels.getHeight(),pixels.getImageType()); }
static void saveImage(ofPixels_<PixelType> & pix, ofBuffer & buffer, ofImageFormat format, ofImageQualityType qualityLevel) { //thanks to alvaro casinelli for the implementation ofInitFreeImage(); if (pix.isAllocated() == false){ ofLog(OF_LOG_ERROR,"error saving image - pixels aren't allocated"); return; } #ifdef TARGET_LITTLE_ENDIAN if(sizeof(PixelType) == 1) { pix.swapRgb(); } #endif FIBITMAP * bmp = getBmpFromPixels(pix); #ifdef TARGET_LITTLE_ENDIAN if(sizeof(PixelType) == 1) { pix.swapRgb(); } #endif if (bmp) // bitmap successfully created { // (b) open a memory stream to compress the image onto mem_buffer: // FIMEMORY *hmem = FreeImage_OpenMemory(); // (c) encode and save the image to the memory (on dib FIBITMAP image): // if(FREE_IMAGE_FORMAT(format) == FIF_JPEG) { int quality = JPEG_QUALITYSUPERB; switch(qualityLevel) { case OF_IMAGE_QUALITY_WORST: quality = JPEG_QUALITYBAD; break; case OF_IMAGE_QUALITY_LOW: quality = JPEG_QUALITYAVERAGE; break; case OF_IMAGE_QUALITY_MEDIUM: quality = JPEG_QUALITYNORMAL; break; case OF_IMAGE_QUALITY_HIGH: quality = JPEG_QUALITYGOOD; break; case OF_IMAGE_QUALITY_BEST: quality = JPEG_QUALITYSUPERB; break; } FreeImage_SaveToMemory(FIF_JPEG, bmp, hmem, quality); }else{ FreeImage_SaveToMemory((FREE_IMAGE_FORMAT)format, bmp, hmem); } /* NOTE: at this point, hmem contains the entire data in memory stored in fif format. the amount of space used by the memory is equal to file_size: long file_size = FreeImage_TellMemory(hmem); but can also be retrieved by FreeImage_AcquireMemory that retrieves both the length of the buffer, and the buffer memory address. */ #ifdef TARGET_WIN32 DWORD size_in_bytes = 0; #else uint32_t size_in_bytes = 0; #endif // Save compressed data on mem_buffer // note: FreeImage_AquireMemory allocates space for aux_mem_buffer): // unsigned char *mem_buffer = NULL; if (!FreeImage_AcquireMemory(hmem, &mem_buffer, &size_in_bytes)) cout << "Error aquiring compressed image from memory" << endl; /* Now, before closing the memory stream, copy the content of mem_buffer to an auxiliary buffer */ buffer.set((char*)mem_buffer,size_in_bytes); // Finally, close the FIBITMAP object, or we will get a memory leak: FreeImage_Unload(bmp); // Close the memory stream (otherwise we may get a memory leak). FreeImage_CloseMemory(hmem); } }
static void saveImage(ofPixels_<PixelType> & pix, string fileName, ofImageQualityType qualityLevel) { ofInitFreeImage(); if (pix.isAllocated() == false){ ofLog(OF_LOG_ERROR,"error saving image - pixels aren't allocated"); return; } #ifdef TARGET_LITTLE_ENDIAN if(sizeof(PixelType) == 1) { pix.swapRgb(); } #endif FIBITMAP * bmp = getBmpFromPixels(pix); #ifdef TARGET_LITTLE_ENDIAN if(sizeof(PixelType) == 1) { pix.swapRgb(); } #endif fileName = ofToDataPath(fileName); 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)) { if(fif == FIF_JPEG) { int quality = JPEG_QUALITYSUPERB; switch(qualityLevel) { case OF_IMAGE_QUALITY_WORST: quality = JPEG_QUALITYBAD; break; case OF_IMAGE_QUALITY_LOW: quality = JPEG_QUALITYAVERAGE; break; case OF_IMAGE_QUALITY_MEDIUM: quality = JPEG_QUALITYNORMAL; break; case OF_IMAGE_QUALITY_HIGH: quality = JPEG_QUALITYGOOD; break; case OF_IMAGE_QUALITY_BEST: quality = JPEG_QUALITYSUPERB; break; } FreeImage_Save(fif, bmp, fileName.c_str(), quality); } else { if(qualityLevel != OF_IMAGE_QUALITY_BEST) { ofLogWarning() << "ofImageCompressionType only applies to JPEG images, ignoring value"; } if (fif == FIF_GIF) { FIBITMAP* convertedBmp; if(pix.getImageType() == OF_IMAGE_COLOR_ALPHA) { // this just converts the image to grayscale so it can save something convertedBmp = FreeImage_ConvertTo8Bits(bmp); } else { // this will create a 256-color palette from the image convertedBmp = FreeImage_ColorQuantize(bmp, FIQ_NNQUANT); } FreeImage_Save(fif, convertedBmp, fileName.c_str()); if (convertedBmp != NULL){ FreeImage_Unload(convertedBmp); } } else { FreeImage_Save(fif, bmp, fileName.c_str()); } } } if (bmp != NULL){ FreeImage_Unload(bmp); } }
void ofPixels_<PixelType>::copyFrom(const ofPixels_<PixelType> & mom){ if(mom.isAllocated()) { allocate(mom.getWidth(), mom.getHeight(), mom.getNumChannels()); memcpy(pixels, mom.getPixels(), mom.getWidth() * mom.getHeight() * mom.getBytesPerPixel()); } }
static bool saveImage(const ofPixels_<PixelType> & _pix, ofBuffer & buffer, ofImageFormat format, ofImageQualityType qualityLevel) { // thanks to alvaro casinelli for the implementation ofInitFreeImage(); if (_pix.isAllocated() == false){ ofLogError("ofImage","saveImage(): couldn't save to ofBuffer, pixels are not allocated"); return false; } if(format==OF_IMAGE_FORMAT_JPEG && (_pix.getNumChannels()==4 || _pix.getBitsPerChannel() > 8)){ ofPixels pix3 = _pix; pix3.setNumChannels(3); return saveImage(pix3,buffer,format,qualityLevel); } FIBITMAP * bmp = nullptr; #ifdef TARGET_LITTLE_ENDIAN if(sizeof(PixelType) == 1 && (_pix.getPixelFormat()==OF_PIXELS_RGB || _pix.getPixelFormat()==OF_PIXELS_RGBA)) { // Make a local copy. ofPixels_<PixelType> pix = _pix; pix.swapRgb(); bmp = getBmpFromPixels(pix); }else{ #endif bmp = getBmpFromPixels(_pix); #ifdef TARGET_LITTLE_ENDIAN } #endif if (bmp) // bitmap successfully created { bool returnValue; // (b) open a memory stream to compress the image onto mem_buffer: // FIMEMORY *hmem = FreeImage_OpenMemory(); // (c) encode and save the image to the memory (on dib FIBITMAP image): // if(FREE_IMAGE_FORMAT(format) == FIF_JPEG) { int quality = JPEG_QUALITYSUPERB; switch(qualityLevel) { case OF_IMAGE_QUALITY_WORST: quality = JPEG_QUALITYBAD; break; case OF_IMAGE_QUALITY_LOW: quality = JPEG_QUALITYAVERAGE; break; case OF_IMAGE_QUALITY_MEDIUM: quality = JPEG_QUALITYNORMAL; break; case OF_IMAGE_QUALITY_HIGH: quality = JPEG_QUALITYGOOD; break; case OF_IMAGE_QUALITY_BEST: quality = JPEG_QUALITYSUPERB; break; } returnValue = FreeImage_SaveToMemory(FIF_JPEG, bmp, hmem, quality); }else{ returnValue = FreeImage_SaveToMemory((FREE_IMAGE_FORMAT)format, bmp, hmem); } /* NOTE: at this point, hmem contains the entire data in memory stored in fif format. the amount of space used by the memory is equal to file_size: long file_size = FreeImage_TellMemory(hmem); but can also be retrieved by FreeImage_AcquireMemory that retrieves both the length of the buffer, and the buffer memory address. */ #ifdef TARGET_WIN32 DWORD size_in_bytes = 0; #else std::uint32_t size_in_bytes = 0; #endif // Save compressed data on mem_buffer // note: FreeImage_AquireMemory allocates space for aux_mem_buffer): // unsigned char *mem_buffer = nullptr; if (!FreeImage_AcquireMemory(hmem, &mem_buffer, &size_in_bytes)){ ofLogError("ofImage") << "saveImage(): couldn't save to ofBuffer, aquiring compressed image from memory failed"; return false; } /* Now, before closing the memory stream, copy the content of mem_buffer to an auxiliary buffer */ buffer.set((char*)mem_buffer,size_in_bytes); // Finally, close the FIBITMAP object, or we will get a memory leak: FreeImage_Unload(bmp); // Close the memory stream (otherwise we may get a memory leak). FreeImage_CloseMemory(hmem); return returnValue; }else{ return false; } }
static void saveImage(ofPixels_<PixelType> & pix, string fileName, ofImageQualityType qualityLevel) { ofInitFreeImage(); if (pix.isAllocated() == false){ ofLogError("ofImage") << "saveImage(): couldn't save \"" << fileName << "\", pixels are not allocated"; return; } #ifdef TARGET_LITTLE_ENDIAN if(sizeof(PixelType) == 1 && (pix.getPixelFormat()==OF_PIXELS_RGB || pix.getPixelFormat()==OF_PIXELS_RGBA)) { pix.swapRgb(); } #endif FIBITMAP * bmp = getBmpFromPixels(pix); #ifdef TARGET_LITTLE_ENDIAN if(sizeof(PixelType) == 1 && (pix.getPixelFormat()==OF_PIXELS_BGR || pix.getPixelFormat()==OF_PIXELS_BGRA)) { pix.swapRgb(); } #endif ofFilePath::createEnclosingDirectory(fileName); fileName = ofToDataPath(fileName); 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)) { if(fif == FIF_JPEG) { int quality = JPEG_QUALITYSUPERB; switch(qualityLevel) { case OF_IMAGE_QUALITY_WORST: quality = JPEG_QUALITYBAD; break; case OF_IMAGE_QUALITY_LOW: quality = JPEG_QUALITYAVERAGE; break; case OF_IMAGE_QUALITY_MEDIUM: quality = JPEG_QUALITYNORMAL; break; case OF_IMAGE_QUALITY_HIGH: quality = JPEG_QUALITYGOOD; break; case OF_IMAGE_QUALITY_BEST: quality = JPEG_QUALITYSUPERB; break; } FreeImage_Save(fif, bmp, fileName.c_str(), quality); } else { if(qualityLevel != OF_IMAGE_QUALITY_BEST) { ofLogWarning("ofImage") << "saveImage(): ofImageCompressionType only applies to JPEGs," << " ignoring value for \" "<< fileName << "\""; } if (fif == FIF_GIF) { FIBITMAP* convertedBmp; if(pix.getImageType() == OF_IMAGE_COLOR_ALPHA) { // this just converts the image to grayscale so it can save something convertedBmp = FreeImage_ConvertTo8Bits(bmp); } else { // this will create a 256-color palette from the image convertedBmp = FreeImage_ColorQuantize(bmp, FIQ_NNQUANT); } FreeImage_Save(fif, convertedBmp, fileName.c_str()); if (convertedBmp != nullptr){ FreeImage_Unload(convertedBmp); } } else { FreeImage_Save(fif, bmp, fileName.c_str()); } } } if (bmp != nullptr){ FreeImage_Unload(bmp); } }
bool ofPixels_<PixelType>::resizeTo(ofPixels_<PixelType>& dst, ofInterpolationMethod interpMethod) const{ if(&dst == this){ return true; } if (!(isAllocated()) || !(dst.isAllocated()) || getBytesPerPixel() != dst.getBytesPerPixel()) return false; int srcWidth = getWidth(); int srcHeight = getHeight(); int dstWidth = dst.getWidth(); int dstHeight = dst.getHeight(); int bytesPerPixel = getBytesPerPixel(); PixelType * dstPixels = dst.getData(); switch (interpMethod){ //---------------------------------------- case OF_INTERPOLATE_NEAREST_NEIGHBOR:{ int dstIndex = 0; float srcxFactor = (float)srcWidth/dstWidth; float srcyFactor = (float)srcHeight/dstHeight; float srcy = 0.5; for (int dsty=0; dsty<dstHeight; dsty++){ float srcx = 0.5; int srcIndex = int(srcy)*srcWidth; for (int dstx=0; dstx<dstWidth; dstx++){ int pixelIndex = int(srcIndex + srcx) * bytesPerPixel; for (int k=0; k<bytesPerPixel; k++){ dstPixels[dstIndex] = pixels[pixelIndex]; dstIndex++; pixelIndex++; } srcx+=srcxFactor; } srcy+=srcyFactor; } }break; //---------------------------------------- case OF_INTERPOLATE_BILINEAR: // not implemented yet ofLogError("ofPixels") << "resizeTo(): bilinear resize not implemented, not resizing"; break; //---------------------------------------- case OF_INTERPOLATE_BICUBIC: float px1, py1; float px2, py2; float px3, py3; float srcColor = 0; float interpCol; int patchRow; int patchIndex; float patch[16]; int srcRowBytes = srcWidth*bytesPerPixel; int loIndex = (srcRowBytes)+1; int hiIndex = (srcWidth*srcHeight*bytesPerPixel)-(srcRowBytes)-1; for (int dsty=0; dsty<dstHeight; dsty++){ for (int dstx=0; dstx<dstWidth; dstx++){ int dstIndex0 = (dsty*dstWidth + dstx) * bytesPerPixel; float srcxf = srcWidth * (float)dstx/(float)dstWidth; float srcyf = srcHeight * (float)dsty/(float)dstHeight; int srcx = (int) MIN(srcWidth-1, srcxf); int srcy = (int) MIN(srcHeight-1, srcyf); int srcIndex0 = (srcy*srcWidth + srcx) * bytesPerPixel; px1 = srcxf - srcx; py1 = srcyf - srcy; px2 = px1 * px1; px3 = px2 * px1; py2 = py1 * py1; py3 = py2 * py1; for (int k=0; k<bytesPerPixel; k++){ int dstIndex = dstIndex0+k; int srcIndex = srcIndex0+k; for (int dy=0; dy<4; dy++) { patchRow = srcIndex + ((dy-1)*srcRowBytes); for (int dx=0; dx<4; dx++) { patchIndex = patchRow + (dx-1)*bytesPerPixel; if ((patchIndex >= loIndex) && (patchIndex < hiIndex)) { srcColor = pixels[patchIndex]; } patch[dx*4 + dy] = srcColor; } } interpCol = (PixelType)bicubicInterpolate(patch, px1,py1, px2,py2, px3,py3); dstPixels[dstIndex] = interpCol; } } } break; } return true; }
void ofPixels_<PixelType>::copyFrom(const ofPixels_<PixelType> & mom){ if(mom.isAllocated()) { allocate(mom.getWidth(), mom.getHeight(), mom.getPixelFormat()); memcpy(pixels, mom.getData(), getTotalBytes()); } }
std::size_t DefaultBitImageCommands::printImage(const ofPixels_<unsigned char>& pixels, ofAlignHorz alignHorz, float ditherThreshold, float ditherQuantWeight, BaseCodes::PrintResolution printResolution, int printHeadWidth, int printHeadHeight) { int numVerticalDots = 0; int maxHorizontalDots = 0; int verticalScale = 1; switch(printResolution) { case BaseCodes::RESOLUTION_8_DOTS_SINGLE_DENSITY: maxHorizontalDots = printHeadWidth / 2; numVerticalDots = 8; break; case BaseCodes::RESOLUTION_8_DOTS_DOUBLE_DENSITY: maxHorizontalDots = printHeadWidth; numVerticalDots = 8; break; case BaseCodes::RESOLUTION_24_DOTS_SINGLE_DENSITY: maxHorizontalDots = printHeadWidth / 2; numVerticalDots = 24; break; case BaseCodes::RESOLUTION_24_DOTS_DOUBLE_DENSITY: maxHorizontalDots = printHeadWidth; numVerticalDots = 24; break; } std::size_t totalBytesWritten = 0; ofRectangle imageRect(0,0,pixels.getWidth(),pixels.getHeight()); ofRectangle rectangle(0,0,maxHorizontalDots,pixels.getHeight()); imageRect.scaleTo(rectangle, OF_ASPECT_RATIO_KEEP, alignHorz, OF_ALIGN_VERT_TOP, alignHorz, OF_ALIGN_VERT_TOP); int width = rectangle.getWidth(); int height = imageRect.getHeight(); // ensure vertical res if(height != numVerticalDots) { int remainder = height % numVerticalDots; if (remainder != 0) { height = height + numVerticalDots - remainder; } } ofPixels pix = pixels; // get a copy ofPixels toPrint; toPrint.allocate(width, height, pix.getNumChannels()); toPrint.setColor(ofColor(255)); pix.resize(imageRect.getWidth(), imageRect.getHeight()); pix.pasteInto(toPrint,imageRect.getX(),imageRect.getY()); toPrint = ImageUtils::dither(toPrint,ditherThreshold,ditherQuantWeight); cout << pix.getWidth() << " / " << pix.getHeight() << endl; ofPixels bandBuffer; bandBuffer.allocate(toPrint.getWidth(), numVerticalDots, toPrint.getNumChannels()); // go into page mode totalBytesWritten += writeByte(BaseCodes::ESC); totalBytesWritten += writeByte('L'); // set the print area / origin totalBytesWritten += setPageModePrintArea(0,0,toPrint.getWidth(),toPrint.getHeight() * 2); // TODO 2 * works for double vert density for(int y = 0; y < height; y += numVerticalDots) { // set the vertical displacement const uint8_t command[3] = { BaseCodes::ESC, '3', numVerticalDots * 2 }; // TODO 2 * works for double vert density totalBytesWritten += writeBytes(command, 3); bandBuffer.clear(); toPrint.cropTo(bandBuffer,0,y,width,numVerticalDots); totalBytesWritten += selectBitImageMode(bandBuffer, printResolution); totalBytesWritten += writeByte(BaseCodes::LF); // feed a line // set vertical displacement back to normal const uint8_t command0[2] = { BaseCodes::ESC, '2' }; totalBytesWritten += writeBytes(command0, 2); } // totalBytesWritten += writeByte(BaseCodes::LF); // feed a line totalBytesWritten += writeByte(BaseCodes::FF); return totalBytesWritten; }
bool ofPixels_<PixelType>::pasteInto(ofPixels_<PixelType> &dst, int xTo, int yTo) const{ if (!(isAllocated()) || !(dst.isAllocated()) || getBytesPerPixel() != dst.getBytesPerPixel() || xTo + getWidth()>dst.getWidth() || yTo + getHeight()>dst.getHeight()) return false; int bytesToCopyPerRow = (xTo + getWidth()<=dst.getWidth() ? getWidth() : dst.getWidth()-xTo) * getBytesPerPixel(); int columnsToCopy = yTo + getHeight() <= dst.getHeight() ? getHeight() : dst.getHeight()-yTo; PixelType * dstPix = dst.getData() + ((xTo + yTo*dst.getWidth())*dst.getBytesPerPixel()); const PixelType * srcPix = getData(); int srcStride = getWidth()*getBytesPerPixel(); int dstStride = dst.getWidth()*dst.getBytesPerPixel(); for(int y=0;y<columnsToCopy; y++){ memcpy(dstPix,srcPix,bytesToCopyPerRow); dstPix += dstStride; srcPix += srcStride; } return true; }
void ofPixels_<PixelType>::rotate90To(ofPixels_<PixelType> & dst, int nClockwiseRotations) const{ int channels = channelsFromPixelFormat(pixelFormat); if (bAllocated == false || channels==0){ return; } if(&dst == this){ dst.rotate90(nClockwiseRotations); return; } // first, figure out which type of rotation we have int rotation = nClockwiseRotations; while (rotation < 0){ rotation+=4; } rotation %= 4; // if it's 0, just make a copy. if it's 2, do it by a mirror operation. if (rotation == 0) { dst = *this; return; // do nothing! } else if (rotation == 2) { mirrorTo(dst, true, true); return; } // otherwise, we will need to do some new allocaiton. dst.allocate(height,width,getImageType()); int strideSrc = width * channels; int strideDst = dst.width * channels; if(rotation == 1){ PixelType * srcPixels = pixels; PixelType * startPixels = dst.getData() + strideDst; for (int i = 0; i < height; ++i){ startPixels -= channels; PixelType * dstPixels = startPixels; for (int j = 0; j < width; ++j){ for (int k = 0; k < channels; ++k){ dstPixels[k] = srcPixels[k]; } srcPixels += channels; dstPixels += strideDst; } } } else if(rotation == 3){ PixelType * dstPixels = dst.pixels; PixelType * startPixels = pixels + strideSrc; for (int i = 0; i < dst.height; ++i){ startPixels -= channels; PixelType * srcPixels = startPixels; for (int j = 0; j < dst.width; ++j){ for (int k = 0; k < channels; ++k){ dstPixels[k] = srcPixels[k]; } srcPixels += strideSrc; dstPixels += channels; } } } }
void ofPixels_<PixelType>::copyFrom(const ofPixels_<PixelType> & mom){ if(mom.isAllocated()) { allocate(mom.getWidth(), mom.getHeight(), mom.getPixelFormat()); memcpy(pixels, mom.getPixels(), mom.size() * sizeof(PixelType)); } }