open source

This commit is contained in:
lvfulong
2020-11-11 16:17:13 +08:00
parent 4d989f3ecb
commit bc4ca748de
2441 changed files with 623057 additions and 2 deletions
+569
View File
@@ -0,0 +1,569 @@
/**
@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 <cmath>
//------------------------------------------------------------------------------
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<char> p_pBuff, int p_nLenth, imgDecodeCB p_CB){
std::shared_ptr<char> 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<char> 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; i<h; i++){
pngline[i]=(char*)(p_pData+w*4*i);
}
SavePng((char*)p_pszFile, pngline, w, h, 8);
delete [] pngline;
return true;
}
bool saveAsJpeg(const char* p_pData, ImageBaseInfo& p_Info, const char* p_pszFile ){
char* pData = (char*)p_pData;
int width = p_Info.m_nWidth;
int height = p_Info.m_nHeight;
int bpp = p_Info.m_nBpp;
//32转24
if( bpp==32){
pData = new char[width*height*3];
char* pSrc = (char*)p_pData;
char* pDst = pData;
for( int y=0; y<height; y++){
for(int x=0; x<width; x++){
pDst[0]=pSrc[0];pDst[1]=pSrc[1];pDst[2]=pSrc[2];
pSrc+=4;
pDst+=3;
}
}
}
saveJpeg(width, height, 24,(char*)pData, 80, p_pszFile);
if( bpp==32)
delete [] pData;
return false;
}
bool saveAsBmp(const char* p_pData, ImageBaseInfo& p_Info){
return false;
}
//把一个浮点数转换成分数。注意现在是用遍历的方法,速度有限,且只处理到分母为2048
void getFraction(float v,int& a, int& b){
float e=1e-4f;
for(int i=1; i<2048; i++){
float f1 = i*v;
float ff = f1-(int)f1;
if(f1-(int)f1<e){
b=i;
a=(int)(b*v+e);
break;
}
}
}
class RGBAColor
{
public:
RGBAColor(){
fa=fr=fg=fb=0.0f;
}
RGBAColor(int color){
set(color);
}
RGBAColor(const RGBAColor& color){
fa=color.fa;fr=color.fr;fg=color.fg;fb=color.fb;
}
void operator += (const RGBAColor& b){
fa+=b.fa;
fr+=b.fr;
fg+=b.fg;
fb+=b.fb;
}
int toInt32(){
int ret=0;
unsigned char* pRGBA = (unsigned char*)&ret;
unsigned char& a = pRGBA[0];
unsigned char& r = pRGBA[1];
unsigned char& g = pRGBA[2];
unsigned char& b = pRGBA[3];
a=(unsigned char)(fa*255); a=a>255?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; i<colorNum-2; i++) resmid+=RGBAColor(*pData++);
res+=resmid*midk;
res+=RGBAColor(*pData++)*edk;
return res;
}
//fsx,fsy。这种方法只适用于w>1,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( ; y<ey-1; y++){
res += _getLineColor(pCurData,rectw,sxk,1,exk);
pCurData+=bmp.m_nWidth;
}
//最后一行
if(y<ey)
res += _getLineColor(pCurData, rectw, sxk*eyk,eyk,exk*eyk);
return res;
}
bool downsampleBmp( BitmapData& src, BitmapData& dst, int* pFrcation, bool rbBorder ){
int& wa=pFrcation[0];
int& wb=pFrcation[1];
int& ha=pFrcation[2];
int& hb=pFrcation[3];
if(wa==wb&&ha==hb){
//先不处理不变的情况
throw -1;
return false;
}
if( wa>wb || 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; y<dsth; y++){
fsx=0;
for(int x=0; x<dstw; x++){
res = _getBmpRectColor(src,fsx,fsy,fw,fh);
res *= (((float)wa*ha)/(wb*hb));
*pdst++=res.toInt32();
fsx+=fw;
}
fsy+=fh;
}
return true;
/*
int stx = 0;
//行
RGBAColor res,cur;
float dsrc = ((float)wa)/wb;//源每前进一步,对应新的步长
int* pcurSrc=(int*)src.m_pImageData;
for( int y=0; y<dsth; y++){
int num = dstw/srcw;
for(int x=0; x<num; x++,stx+=wb){
float fcurpos=0.0f;
float vk=1.0f;
for( int cx=stx; cx<stx+wb; cx++){
//取一个颜色
cur.set(*pcurSrc++);
//这个颜色可能全给新的像素了,也可能只给了一部分
float d1 = 1.0f-fcurpos;
if(d1>dsrc){//全部
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<dsth-borderAdd; y++ ){
int* pcurdst=pdst;
for( int x=0; x<dstw-borderAdd; x++ ){
unsigned int valr = 0,valg=0,valb=0,vala=0;
unsigned char* pcurc = (unsigned char*)&psrc[x*windw + (y*windh)*srcw];
//下面开始处理一个块
for(int sy=0;sy<windh; sy++){
unsigned char* tmpSrc=pcurc;
for(int sx=0; sx<windw; sx++){
valr+=*tmpSrc++; valg+=*tmpSrc++; valb+=*tmpSrc++; vala+=*tmpSrc++;
}
//下一行的块开头
pcurc += srcw*4;
}
valr/=snum; valg/=snum; valb/=snum; vala/=snum;
unsigned char avgval[]={static_cast<unsigned char>(valr),static_cast<unsigned char>(valg),static_cast<unsigned char>(valb),static_cast<unsigned char>(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;y<h;y++){
for(int x=0; x<w; x++){
int v = (((x/gridw)%2)^((y/gridw)%2))?(0xffffffff):(0x77777777);
*pData++=v;
}
}
}
void copy8BitBmp( BitmapData& dst, int nSx, int nSy, unsigned char* pSrc, int nSrcW, int nSrcH, int nSrcColor ){
int srcsx=0,srcsy=0;
int dstsx=nSx,dstsy=nSy;
int dtw=nSrcW,dth=nSrcH;
if(dstsx<0){
srcsx = -dstsx;
dtw+=dstsx;
dstsx=0;
}
if( dstsy<0){
srcsy = -dstsy;
dth+=dstsy;
dstsy=0;
}
int ex = dstsx+dtw;
int ey = dstsy+dth;
if(ex>dst.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<dth; y++){
unsigned int* pdstl=pdst;
unsigned char* psrcl=psrc;
for( int x=0; x<dtw; x++){
unsigned char alpha = *pSrc++;
int col = nSrcColor&0x00ffffff;
col|=(alpha<<24);
*pdstl++=col;
}
pdst+=dst.m_nWidth;
psrc+=nSrcW;
}
}
void copy32BitBmp(BitmapData& dst, int nSx, int nSy,int nDstW, unsigned char* pSrc, int nSrcW, int nSrcH, int srcPitch )
{
int srcsx = 0, srcsy = 0;
int dstsx = nSx, dstsy = nSy;
int dtw = nSrcW, dth = nSrcH;
if (dstsx < 0) {
srcsx = -dstsx;
dtw += dstsx;
dstsx = 0;
}
if (dstsy < 0) {
srcsy = -dstsy;
dth += dstsy;
dstsy = 0;
}
int ex = dstsx + dtw;
int ey = dstsy + dth;
if (ex > 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--------------------------------