/** @file JCImageRW.cpp @brief @author hugao @version 1.0 @date 2016_5_11 */ #include "JCImageRW.h" #include "../misc/JCWorkerThread.h" #include "../buffer/JCBuffer.h" #include "../fileSystem/JCFileSystem.h" #include //------------------------------------------------------------------------------ namespace laya { BitmapData::BitmapData() { m_nImageID = 0; m_nWidth = 0; m_nHeight = 0; m_nBpp = 32; m_pImageData = 0; m_nImageType = ImgType_unknow; } BitmapData::BitmapData(char* p_pData, int p_nWidth, int p_nHeight) { m_nWidth = p_nWidth; m_nHeight = p_nHeight; m_nBpp = 32; m_pImageData = p_pData; m_nImageType = ImgType_unknow; } BitmapData::BitmapData(int p_nWidth, int p_nHeight, bool p_bTranslate, int p_nFillColor) { m_nWidth = p_nWidth; m_nHeight = p_nHeight; m_nBpp = 32; m_pImageData = (char*) new int[p_nWidth*p_nHeight]; if (p_nFillColor == 0) memset(m_pImageData, 0, p_nWidth*p_nHeight*sizeof(int)); else for (int i = 0; i < m_nWidth*m_nHeight; i++) ((int*)m_pImageData)[i] = p_nFillColor; m_nImageType = ImgType_unknow; } void BitmapData::reconfigure(int width, int height, int bpp, ImageType imageType) { bool isChanged = false; if (m_nWidth != width) { isChanged = true; m_nWidth = width; } if (m_nHeight != height) { isChanged = true; m_nHeight = height; } if (m_nBpp != bpp) { isChanged = true; m_nBpp = bpp; } if(m_pImageData == nullptr) { isChanged = true; } m_nImageType = imageType; if (isChanged) { releaseData(); int bufferLength = this->m_nWidth * this->m_nHeight * (this->m_nBpp / 8); m_pImageData = new char[bufferLength]; } } void BitmapData::copyData(char* dataPtr) { int bufferLength = this->m_nWidth * this->m_nHeight * (this->m_nBpp / 8); memcpy(m_pImageData, dataPtr, bufferLength); } #ifndef WEBASM unsigned char* ReadPNGFromMem(unsigned char* data, int dataSize, PNG_UINT32* w, PNG_UINT32* h); int LoadJpegFromMem (BitmapData* pBitmapData,unsigned char * memData, int size ); int LoadGif(BitmapData* pBitmapData, unsigned char * memData, int size); bool saveJpeg(int width ,int height,int bpp, char *buffer, int quality, const char*filename); JCWorkerThread* g_DecThread=NULL; //全局的解码线程 bool loadImageMemSync( const char* p_pMem, int p_nLenth, BitmapData& p_bmp ){ ImageType imgType = getImgType(p_pMem, p_nLenth); p_bmp.m_nImageType = imgType; p_bmp.m_nBpp = 32; switch( imgType ){ case ImgType_jpeg: return LoadJpegFromMem(&p_bmp,(unsigned char*)p_pMem,p_nLenth)!=0; break; case ImgType_png: p_bmp.m_pImageData = (char*)ReadPNGFromMem((unsigned char*)p_pMem, p_nLenth, (PNG_UINT32*)&p_bmp.m_nWidth, (PNG_UINT32*)&p_bmp.m_nHeight); return p_bmp.m_pImageData!=0; break; case ImgType_gif: return LoadGif(&p_bmp, (unsigned char*)p_pMem, p_nLenth) != 0; break; case ImgType_unknow: default: break; } return false; } BitmapData loadLocalImageSync( const char* p_pszFile ){ BitmapData bmp; JCBuffer buf; readFileSync(p_pszFile,buf); bool b = loadImageMemSync(buf.m_pPtr, buf.m_nLen, bmp); if(!b){ bmp.m_pImageData=NULL; } return bmp; } void _AsyncLoadImage(std::shared_ptr p_pBuff, int p_nLenth, imgDecodeCB p_CB){ std::shared_ptr pMem = p_pBuff; BitmapData bmp; bool b = loadImageMemSync(pMem.get(), p_nLenth, bmp ); if( b ){ p_CB(bmp); }else{ if(bmp.m_pImageData ) delete [] bmp.m_pImageData ; bmp.m_pImageData = 0; p_CB(bmp); } } void loadImageMemASync(std::shared_ptr p_pBuff, int p_nLenth, imgDecodeCB p_CB){ g_DecThread->post( std::bind(_AsyncLoadImage, p_pBuff, p_nLenth,p_CB ) ); } ImageType getImgType( const char* p_pMem, int p_nLength ){ static int jpegID = 0x00ffd8ff; //最高位00那个位置不一定是什么 static int gifID = 0x38464947; static int pngID = 0x474e5089; int idval = *(int*)p_pMem; if( idval == pngID )return ImgType_png; else if( idval==gifID ) return ImgType_gif; else if( (idval &0xffffff) == jpegID ) return ImgType_jpeg; return ImgType_unknow; } bool getImageBaseInfo( const char* p_pMem, int p_nLength, ImageBaseInfo& p_Info ){ return true; } extern int SavePng(char* png_file_name, char **data, int width, int height, int bit_depth); bool saveAsPng(const char* p_pData, int w, int h, const char* p_pszFile ){ char** pngline = new char*[h]; for( int i=0; i255?255:a; r=(unsigned char)(fr*255); r=r>255?255:r; g=(unsigned char)(fg*255); g=g>255?255:g; b=(unsigned char)(fb*255); b=b>255?255:b; return ret; } void set(int color){ unsigned char* pRGBA = (unsigned char*)&color; fa = pRGBA[0]/255.0f; fr = pRGBA[1]/255.0f; fg = pRGBA[2]/255.0f; fb = pRGBA[3]/255.0f; } void clear(){ fa=fr=fg=fb=0.0f; } RGBAColor operator *(float f){ RGBAColor ret; ret.fa=fa*f; ret.fr=fr*f; ret.fg=fg*f; ret.fb=fb*f; return ret; } void operator *=(float f){ fa*=f;fr*=f;fg*=f;fb*=f; } private: float fa,fr,fg,fb; }; //求一条线的颜色的和 RGBAColor _getLineColor(int* pData, int colorNum, float stk, float midk, float edk){ RGBAColor res; res+=RGBAColor(*pData++)*stk; RGBAColor resmid; for(int i=0; i1,h>1的情况,即缩小图片。而且也不是很精确,没有考虑插值。 RGBAColor _getBmpRectColor(BitmapData& bmp,float fsx, float fsy, float w, float h ){ if(w<1.0f||h<1.0f){ throw -1; } RGBAColor res; float dstposx=0.0f; float dstposy=0.0f; int sx=(int)fsx; int sy=(int)fsy; int ex=(int)ceil(fsx+w); ex=ex>bmp.m_nWidth?bmp.m_nWidth:ex; int ey=(int)ceil(fsy+h); ey=ey>bmp.m_nHeight?bmp.m_nHeight:ey; //TODO 对于整幅图像的缩小,下面几个值每个目标像素都要重算一遍,效率低 float fracfsx = fsx-sx; float fracfsy = fsy-sy; float sxk = fracfsx==0.0f?1:(1.0f-fracfsx); float syk = fracfsy==0.0f?1:(1.0f-fracfsy); float exk = (fsx+w)-(ex-1); if(exk<0)exk=1.0f; float eyk = (fsy+h)-(ey-1); if(eyk<0)eyk=1.0f; int rectw = ex-sx; int recth = ey-sy; if(recth<=0) return res; int y=sy; int* pCurData = ((int*)bmp.m_pImageData)+sy*bmp.m_nWidth+sx; //第一行 res += _getLineColor(pCurData,rectw,sxk*syk,syk,exk*syk); y++; pCurData+=bmp.m_nWidth; //中间行 for( ; ywb || ha>hb ){ //不支持放大 throw -1; return false; } int& srcw = src.m_nWidth; int& srch = src.m_nHeight; int& dstw = dst.m_nWidth; int& dsth = dst.m_nHeight; dstw = (int)ceil((float)srcw*wa/wb); dsth = (int)ceil((float)srch*ha/hb); int borderAdd=0; if(rbBorder){ dstw++; dsth++; borderAdd=1; } //实际图片 dst.m_pImageData = new char[dstw*dsth*4]; #ifdef _DEBUG memset(dst.m_pImageData,0x86,dstw*dsth*4); #endif dst.m_nBpp = 32; int* pdst = (int*)dst.m_pImageData; float fsx=0.0f,fsy=0.0f,fw=(float)wb/wa,fh=(float)hb/ha; RGBAColor res; for(int y=0; ydsrc){//全部 res+=cur; }else{//部分 vk = d1/dsrc;//一定<1 res+=(cur*vk); } fcurpos+=dsrc; } } //剩下的 int left = dstw%srcw; } //列 */ } bool downsampleBmp( BitmapData& src, BitmapData& dst, int windw, int windh, bool rbBorder ){ if( src.m_pImageData==NULL) return false; if(windw<1 || windh<1)return false; if(windw==1 && windh==1){ //这个怎么处理.这么用是浪费的 throw -1; } int& srcw = src.m_nWidth; int& srch = src.m_nHeight; int& dstw = dst.m_nWidth; int& dsth = dst.m_nHeight; //取整。可能会丢掉一部分 dstw = srcw/windw; dsth = srch/windh; //TODO //采用先水平扫描的方法,这样可能会快一些 int borderAdd=0; if(rbBorder){ dstw++; dsth++; borderAdd=1; } //实际图片 dst.m_pImageData = new char[dstw*dsth*4]; dst.m_nBpp = 32; int snum=windw*windh; int* psrc = (int*)src.m_pImageData; int* pdst = (int*)dst.m_pImageData; for( int y=0; y(valr),static_cast(valg),static_cast(valb),static_cast(vala)}; *pcurdst++=*(int*)avgval; } //水平复制最后一个 if(borderAdd){ int lastv = *(pcurdst-1); *pcurdst++ = lastv; } pdst+=dstw; //这个要实际到下一行,考虑包边 } //复制最后一行 if(borderAdd){ int* pcurimg = (int*)dst.m_pImageData; memcpy(pcurimg+dstw*(dsth-1),pcurimg+dstw*(dsth-2), dstw*sizeof(int)); } return true; } void createGridBmp( BitmapData& out, int w, int h, int gridw){ out.m_nBpp=32; out.m_nWidth=w; out.m_nHeight=h; out.m_pImageData=(char*)new int[w*h]; int* pData = (int*)out.m_pImageData; for(int y=0;ydst.m_nWidth){ dtw -= (ex - dst.m_nWidth); } if(ey>dst.m_nHeight){ dth -= (ey - dst.m_nHeight); } unsigned int* pdst = (unsigned int*)(dst.m_pImageData+(dstsy*dst.m_nWidth+dstsx)*4); unsigned char* psrc = pSrc+srcsy*nSrcW+srcsx; for( int y=0; y nDstW) { dtw -= (ex - nDstW); } if (ey > dst.m_nHeight) { dth -= (ey - dst.m_nHeight); } if (dtw < 0) dtw = 0; char* pdst = dst.m_pImageData + (dstsy*nDstW + dstsx) * 4; unsigned char* psrc = pSrc + srcsy*srcPitch + srcsx*4; for (int y = 0; y < dth; y++) { memcpy(pdst, psrc, dtw * 4); pdst += nDstW *4; psrc += srcPitch; } } #endif void convertRGBA8888ToRGB888(const unsigned char* data, size_t dataLen, unsigned char* outData) { for (size_t i = 0, l = dataLen - 3; i < l; i += 4) { *outData++ = data[i]; *outData++ = data[i + 1]; *outData++ = data[i + 2]; } } void convertRGBA8888ToA8(const unsigned char* data, size_t dataLen, unsigned char* outData) { for (size_t i = 0, l = dataLen - 3; i < l; i += 4) { *outData++ = data[i + 3]; } } void convertRGBA8888ToFormat(const unsigned char* data, size_t dataLen, GLenum format, unsigned char** outData, size_t* outDataLen) { switch (format) { case GL_RGB: *outDataLen = dataLen / 4 * 3; *outData = new unsigned char[sizeof(unsigned char) * (*outDataLen)]; convertRGBA8888ToRGB888(data, dataLen, *outData); break; case GL_ALPHA: *outDataLen = dataLen / 4; *outData = new unsigned char[sizeof(unsigned char) * (*outDataLen)]; convertRGBA8888ToA8(data, dataLen, *outData); break; default: *outData = (unsigned char*)data; *outDataLen = dataLen; } } } //------------------------------------------------------------------------------ //-----------------------------END FILE--------------------------------