void mexFunction( int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[] ) { int *ns, ms[3], nDims, d, m, r, s; float *A, *B, p; mxClassID id; char type[1024]; // error checking on arguments if(nrhs!=4) mexErrMsgTxt("Four inputs required."); if(nlhs > 1) mexErrMsgTxt("One output expected."); nDims = mxGetNumberOfDimensions(prhs[1]); id = mxGetClassID(prhs[1]); ns = (int*) mxGetDimensions(prhs[1]); d = (nDims == 3) ? ns[2] : 1; m = (ns[0] < ns[1]) ? ns[0] : ns[1]; if( (nDims!=2 && nDims!=3) || id!=mxSINGLE_CLASS || m<4 ) mexErrMsgTxt("A must be a 4x4 or bigger 2D or 3D float array."); // extract inputs if(mxGetString(prhs[0],type,1024)) mexErrMsgTxt("Failed to get type."); A = (float*) mxGetData(prhs[1]); p = (float) mxGetScalar(prhs[2]); r = (int) mxGetScalar(prhs[2]); s = (int) mxGetScalar(prhs[3]); if( s<1 ) mexErrMsgTxt("Invalid sampling value s"); if( r<0 ) mexErrMsgTxt("Invalid radius r"); // create output array (w/o initializing to 0) ms[0]=ns[0]/s; ms[1]=ns[1]/s; ms[2]=d; B = (float*) mxMalloc(ms[0]*ms[1]*d*sizeof(float)); plhs[0] = mxCreateNumericMatrix(0, 0, mxSINGLE_CLASS, mxREAL); mxSetData(plhs[0], B); mxSetDimensions(plhs[0],(mwSize*)ms,nDims); // perform appropriate type of convolution if(!strcmp(type,"convBox")) { if(r>=m/2) mexErrMsgTxt("mask larger than image (r too large)"); convBox( A, B, ns[0], ns[1], d, r, s ); } else if(!strcmp(type,"convTri")) { if(r>=m/2) mexErrMsgTxt("mask larger than image (r too large)"); convTri( A, B, ns[0], ns[1], d, r, s ); } else if(!strcmp(type,"conv11")) { if( s>2 ) mexErrMsgTxt("conv11 can sample by at most s=2"); conv11( A, B, ns[0], ns[1], d, r, s ); } else if(!strcmp(type,"convTri1")) { if( s>2 ) mexErrMsgTxt("convTri1 can sample by at most s=2"); convTri1( A, B, ns[0], ns[1], d, p, s ); } else if(!strcmp(type,"convMax")) { if( s>1 ) mexErrMsgTxt("convMax cannot sample"); convMax( A, B, ns[0], ns[1], d, r ); } else { mexErrMsgTxt("Invalid type."); } }
//--------------------------------------------------------------------- FIBITMAP* FreeImageCodec::encode(MemoryDataStreamPtr& input, CodecDataPtr& pData) const { // Set error handler FreeImage_SetOutputMessage(FreeImageSaveErrorHandler); FIBITMAP* ret = 0; ImageData* pImgData = static_cast< ImageData * >( pData.getPointer() ); PixelBox src(pImgData->width, pImgData->height, pImgData->depth, pImgData->format, input->getPtr()); // The required format, which will adjust to the format // actually supported by FreeImage. PixelFormat requiredFormat = pImgData->format; // determine the settings FREE_IMAGE_TYPE imageType; PixelFormat determiningFormat = pImgData->format; switch(determiningFormat) { case PF_R5G6B5: case PF_B5G6R5: case PF_R8G8B8: case PF_B8G8R8: case PF_A8R8G8B8: case PF_X8R8G8B8: case PF_A8B8G8R8: case PF_X8B8G8R8: case PF_B8G8R8A8: case PF_R8G8B8A8: case PF_A4L4: case PF_BYTE_LA: case PF_R3G3B2: case PF_A4R4G4B4: case PF_A1R5G5B5: case PF_A2R10G10B10: case PF_A2B10G10R10: // I'd like to be able to use r/g/b masks to get FreeImage to load the data // in it's existing format, but that doesn't work, FreeImage needs to have // data in RGB[A] (big endian) and BGR[A] (little endian), always. if (PixelUtil::hasAlpha(determiningFormat)) { #if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_RGB requiredFormat = PF_BYTE_RGBA; #else requiredFormat = PF_BYTE_BGRA; #endif } else { #if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_RGB requiredFormat = PF_BYTE_RGB; #else requiredFormat = PF_BYTE_BGR; #endif } // fall through case PF_L8: case PF_A8: imageType = FIT_BITMAP; break; case PF_L16: imageType = FIT_UINT16; break; case PF_SHORT_GR: requiredFormat = PF_SHORT_RGB; // fall through case PF_SHORT_RGB: imageType = FIT_RGB16; break; case PF_SHORT_RGBA: imageType = FIT_RGBA16; break; case PF_FLOAT16_R: requiredFormat = PF_FLOAT32_R; // fall through case PF_FLOAT32_R: imageType = FIT_FLOAT; break; case PF_FLOAT16_GR: case PF_FLOAT16_RGB: case PF_FLOAT32_GR: requiredFormat = PF_FLOAT32_RGB; // fall through case PF_FLOAT32_RGB: imageType = FIT_RGBF; break; case PF_FLOAT16_RGBA: requiredFormat = PF_FLOAT32_RGBA; // fall through case PF_FLOAT32_RGBA: imageType = FIT_RGBAF; break; default: OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, "Invalid image format", "FreeImageCodec::encode"); }; // Check support for this image type & bit depth if (!FreeImage_FIFSupportsExportType((FREE_IMAGE_FORMAT)mFreeImageType, imageType) || !FreeImage_FIFSupportsExportBPP((FREE_IMAGE_FORMAT)mFreeImageType, (int)PixelUtil::getNumElemBits(requiredFormat))) { // Ok, need to allocate a fallback // Only deal with RGBA -> RGB for now switch (requiredFormat) { case PF_BYTE_RGBA: requiredFormat = PF_BYTE_RGB; break; case PF_BYTE_BGRA: requiredFormat = PF_BYTE_BGR; break; default: break; }; } bool conversionRequired = false; unsigned char* srcData = input->getPtr(); // Check BPP unsigned bpp = static_cast<unsigned>(PixelUtil::getNumElemBits(requiredFormat)); if (!FreeImage_FIFSupportsExportBPP((FREE_IMAGE_FORMAT)mFreeImageType, (int)bpp)) { if (bpp == 32 && PixelUtil::hasAlpha(pImgData->format) && FreeImage_FIFSupportsExportBPP((FREE_IMAGE_FORMAT)mFreeImageType, 24)) { // drop to 24 bit (lose alpha) #if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_RGB requiredFormat = PF_BYTE_RGB; #else requiredFormat = PF_BYTE_BGR; #endif bpp = 24; } else if (bpp == 128 && PixelUtil::hasAlpha(pImgData->format) && FreeImage_FIFSupportsExportBPP((FREE_IMAGE_FORMAT)mFreeImageType, 96)) { // drop to 96-bit floating point requiredFormat = PF_FLOAT32_RGB; } } PixelBox convBox(pImgData->width, pImgData->height, 1, requiredFormat); if (requiredFormat != pImgData->format) { conversionRequired = true; // Allocate memory convBox.data = OGRE_ALLOC_T(uchar, convBox.getConsecutiveSize(), MEMCATEGORY_GENERAL); // perform conversion and reassign source PixelBox src(pImgData->width, pImgData->height, 1, pImgData->format, input->getPtr()); PixelUtil::bulkPixelConversion(src, convBox); srcData = static_cast<unsigned char*>(convBox.data); } ret = FreeImage_AllocateT( imageType, static_cast<int>(pImgData->width), static_cast<int>(pImgData->height), bpp); if (!ret) { if (conversionRequired) OGRE_FREE(convBox.data, MEMCATEGORY_GENERAL); OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "FreeImage_AllocateT failed - possibly out of memory. ", __FUNCTION__); } if (requiredFormat == PF_L8 || requiredFormat == PF_A8) { // Must explicitly tell FreeImage that this is greyscale by setting // a "grey" palette (otherwise it will save as a normal RGB // palettized image). FIBITMAP *tmp = FreeImage_ConvertToGreyscale(ret); FreeImage_Unload(ret); ret = tmp; } size_t dstPitch = FreeImage_GetPitch(ret); size_t srcPitch = pImgData->width * PixelUtil::getNumElemBytes(requiredFormat); // Copy data, invert scanlines and respect FreeImage pitch uchar* pSrc; uchar* pDst = FreeImage_GetBits(ret); for (size_t y = 0; y < pImgData->height; ++y) { pSrc = srcData + (pImgData->height - y - 1) * srcPitch; memcpy(pDst, pSrc, srcPitch); pDst += dstPitch; } if (conversionRequired) { // delete temporary conversion area OGRE_FREE(convBox.data, MEMCATEGORY_GENERAL); } return ret; }