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
File diff suppressed because it is too large Load Diff
+312
View File
@@ -0,0 +1,312 @@
/**
@file JCGifImg.h
@brief
@author James
@version 1.0
@date 2016_7_13
*/
#ifndef __JCGifImg_H__
#define __JCGifImg_H__
#include <fstream>
#include <iostream>
using namespace std;
namespace laya
{
/*
* 图像扩展参数
*/
typedef struct
{
bool active; //本结构中的其它参数是否可用
unsigned int disposalMethod; //处理方法(见gif89a.doc,可忽略)
bool userInputFlag; //是否期待用户输入
bool trsFlag; //是否有透明色
unsigned short delayTime; //延时时间(单位1/100秒)
unsigned int trsColorIndex; //透明色调色板索引
}GCTRLEXT;
/*
* 一帧图象的参数
*/
typedef struct
{
unsigned short imageLPos; //图象左边沿到逻辑屏幕的距离(单位像素)
unsigned short imageTPos; //图象上边沿到逻辑屏幕的距离(单位像素)
unsigned short imageWidth; //图象的宽度(单位像素)
unsigned short imageHeight; //图象的高度(单位像素)
bool lFlag; //是否有局部调色板(决定其他调色板参数是否有效)
bool interlaceFlag; //图象数据是否交错
bool sortFlag; //局部调色板数据是否按优先排序
unsigned int lSize; //局部调色板大小(有多少个实际入口)
unsigned char* pColorTable; //指向局部调色板的指针(256个入口,每个入口三字节)
unsigned char* dataBuf; //调色板格式请参看gif89a.doc
GCTRLEXT ctrlExt; //图象数据指针
}FRAME; //图象扩展参数(与透明背景和动画有关)
typedef FRAME *LPFRAME;
typedef const FRAME *LPCFRAME;
/*
* GIF文件的全局参数
*/
typedef struct
{ //GIF文件的全局参数
unsigned int frames; //文件中图象帧数
unsigned short scrWidth, scrHeight; //逻辑屏幕的宽度和高度(单位像素)
bool gFlag; //是否有全局调色板(决定其他调色板参数是否有效)
unsigned int colorRes; //色彩分辨率(不使用)
bool gSort; //全局调色板是否按优先排序
unsigned int gSize; //全局调色板大小(有多少个实际入口)
unsigned int BKColorIdx; //背景色的调色板索引
unsigned int pixelAspectRatio; //像素长宽比例
unsigned char *gColorTable; //指向全局调色板的指针(256个入口,每个入口三字节)
}GLOBAL_INFO; //调色板格式请参看gif89a.doc
typedef GLOBAL_INFO *LPGLOBAL_INFO;
typedef const GLOBAL_INFO *LPCGLOBAL_INFO;
/*
*
*/
typedef struct
{
unsigned int len;
unsigned char* p;
}STRING_TABLE_ENTRY;
class BufferIOStream
{
public:
BufferIOStream(char* p_sBuffer, int p_nBufferSize)
{
m_pBuffer = p_sBuffer;
m_nSize = p_nBufferSize;
m_nCurPos = 0;
}
~BufferIOStream()
{
close();
}
bool read(char* p_pRet, int p_nSize)
{
if ((m_nCurPos + p_nSize) > m_nSize)
{
return false;
}
char* pCur = m_pBuffer + m_nCurPos;
memcpy(p_pRet, pCur, p_nSize);
m_nCurPos += p_nSize;
return true;
}
bool good()
{
return true;
}
int tellg()
{
return m_nCurPos;
}
void close()
{
/*直接拿的指针应该在外面释放
if( m_pBuffer != NULL )
{
delete[] m_pBuffer;
m_pBuffer = NULL;
}
*/
m_nSize = 0;
m_nCurPos = 0;
}
bool eof()
{
return (m_nCurPos >= m_nSize);
}
void seekg(int p_nPos)
{
m_nCurPos = p_nPos;
}
void seekg(int p_nPos, int p_nMark)
{
if (p_nMark == 0)
{
m_nCurPos = 0 + p_nPos;
}
else if (p_nMark == 1)
{
m_nCurPos += p_nPos;
}
else if (p_nMark == 2)
{
m_nCurPos = m_nSize + p_nPos;
}
}
protected:
char* m_pBuffer;
int m_nSize;
int m_nCurPos;
};
/**
* Gif类
*/
class GifLoader
{
public:
/** @brief
* 构造函数
*/
GifLoader(void);
/** @brief 构造函数
* @param[in] 文件名字
* @param[in] 是否一次性读取完成
* @return
*/
GifLoader(const char* p_sFileName, bool p_bInMem);
GifLoader(unsigned char* p_pBuffer, int p_nBufferSize);
/** @brief
* 析构函数
*/
~GifLoader(void);
/** @brief
* 重载错误符号
*/
bool operator!(void);
/** @brief 打开图片
* @param[in] 图片路径
* @param[in] 是否一次性读取完成
* @return
*/
bool open(const char* p_sFileName, bool p_bInMem);
/** @brief 关闭
*
*/
void close(void);
/** @brief 获得版本
*
*/
char* getVersion(void);
/** @brief 获得下一帧
*
*/
LPCFRAME getNextFrame(void);
/** @brief 获得图片的全局信息
*
*/
LPCGLOBAL_INFO getGlobalInfo();
/*
*
*/
public:
//从内存读取的方法 现在代码比较恶心,回头把ifstream 和 bufferIOStream 封装成一个类
bool open(void);
unsigned int checkFrames(BufferIOStream& p_kStrteam);
bool getAllFrames(BufferIOStream& p_kIOStream);
bool extractData(FRAME* p_pFrame, BufferIOStream& p_kStrteam);
private:
/*
功能 :检查文件中图象帧数。
参数 :ifs:对文件流的引用。
返回值:文件中图象帧数。
*/
unsigned int checkFrames(ifstream& p_kStrteam);
/*
功能 :将所有图象帧数据读入内存。
参数 :ifs:对文件流的引用。
返回值:操作是否成功,为真成功,为假失败。
*/
bool getAllFrames(ifstream& p_kStrteam);
/*
功能 :解压缩一帧图象数据。
参数 :f:指向用于保存图象数据的结构。
ifs:对文件流的引用。
返回值:操作是否成功,为真成功,为假失败。
*/
bool extractData(FRAME* p_pFrame, ifstream& p_kStrteam);
/*
功能 :初始化字符串表。
参数 :strTable:指向字符串表的指针。
rootSize:初始化的入口数。
返回值:操作是否成功,为真成功,为假失败。
*/
bool initStrTable(STRING_TABLE_ENTRY* p_pSTable, unsigned int p_nRootSize);
/*
功能 :在字符串表中增加一项。
参数 :strTable:指向字符串表的指针。
addIdx:增加的入口索引。
idx:用于构造要增加的字符串的入口索引。
c:用于构造要增加的字符串的字符。
返回值:操作是否成功,为真成功,为假失败。
*/
bool addStrTable(STRING_TABLE_ENTRY* p_pSTable, unsigned int p_nAddInedx, unsigned int p_nIndex, unsigned char p_cBuf);
public:
FRAME* m_vAllFrames; //指向所有图象帧的指针(inMem为真时用)
private:
GLOBAL_INFO m_kGInfo; //GIF文件的全局参数
FRAME m_kCurFrame; //当前帧的参数(inMem为假时用)
GCTRLEXT m_kCtrlExt; //图象扩展参数(读入数据时临时使用)
private:
BufferIOStream* m_pBufferIOStream; //用于读取内存的
ifstream m_kIOStream; //用于读文件的文件流
char m_sVersion[4]; //版本字符串
bool m_bError; //类实例变量创建时是否出错的标志
bool m_bOpened; //是否处于打开状态
bool m_bInMem; //图象数据是否一次读入内存
unsigned char m_vGColorTable[256 * 3]; //全局调色板
unsigned char m_vLColorTable[256 * 3]; //局部调色板(inMem为假时用)
streampos m_kDataStart; //保存文件流中图象数据开始的地方
unsigned int m_nCurIndex; //当前帧的索引(inMem为真时用)
};
}
//------------------------------------------------------------------------------
#endif //__JCGifImg_H__
//-----------------------------END FILE--------------------------------
+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--------------------------------
+167
View File
@@ -0,0 +1,167 @@
/**
@file JCImageRW.h
@brief
@author hugao
@version 1.0
@date 2016_5_11
*/
#ifndef __JCImageRW_H__
#define __JCImageRW_H__
#include <memory>
#include <functional>
#define PNG_UINT32 unsigned int
#if __APPLE__
#include <OpenGLES/ES3/gl.h>
#else
#include <GLES3/gl3.h>
#endif
namespace laya
{
enum ImageType
{
ImgType_unknow,
ImgType_jpeg,
ImgType_png,
ImgType_gif,
ImgType_ETC1,
ImgType_ETC2,
ImgType_PVR,
};
struct ImageBaseInfo
{
int m_nWidth, m_nHeight, m_nBpp;
};
class BitmapData:public ImageBaseInfo
{
public:
BitmapData();
BitmapData(char* p_pData, int p_nWidth, int p_nHeight );
BitmapData(int p_nWidth, int p_nHeight, bool p_bTranslate, int p_nFillColor );
void releaseData()
{
if(m_pImageData)
{
delete [] m_pImageData;
m_pImageData=0;
}
}
int m_nImageID;
char* m_pImageData;
ImageType m_nImageType;
void reconfigure(int width, int height, int bpp, ImageType imageType);
void copyData(char* dataPtr);
};
#ifndef WEBASM
//参数是对象实例而不是引用。因为实际对象可能是临时对象
typedef std::function<void(BitmapData bmp)> imgDecodeCB;
/** @brief 在函数内部会给 p_pData 分配空间。注意是一维数组,不是二维的 这里只负责解码图片,没有缓存管理等功能。
* 返回的是函数内部分配的指针。需要外部释放
* @param[in] 内存数据
* @param[in] 长度
* @param[in] 获得到的bitmap
* @return 是否解码成功
*/
bool loadImageMemSync( const char* p_pMem, int p_nLenth, BitmapData& p_bmp );
/** @brief
直接加载一个图片文件。
* @param[in] p_pszFile 本地文件的路径,绝对路径。
* @return
返回一个Bitmap对象,注意需要自己手动删除其中的指针。
*/
BitmapData loadLocalImageSync( const char* p_pszFile );
void loadImageMemASync(std::shared_ptr<char> p_pBuff, int p_nLenth, imgDecodeCB p_CB);
ImageType getImgType( const char* p_pMem, int p_nLength );
/** @brief 获得图片的基本信息。要求快速,如果不必解码就不要解码 同步函数
* @param[in] 内存数据
* @param[in] 内存长度
* @param[in] 图片基本信息
* @return 是否解码成功
*/
bool getImageBaseInfo( const char* p_pMem, int p_nLength, ImageBaseInfo& p_Info );
/** @brief 保存png
* @param[in] 图片数据
* @param[in] w
* @param[in] h
* @param[in] 文件名字
* @return 是否保存成功
*/
bool saveAsPng(const char* p_pData, int w, int h, const char* p_pszFile );
/** @brief 保存jpg
* @param[in] 图片数据
* @param[in] 图片信息
* @param[in] 文件名字
* @return 是否保存成功
*/
bool saveAsJpeg(const char* p_pData, ImageBaseInfo& p_Info, const char* p_pszFile );
/** @brief 保存bmp
* @param[in] 图片数据
* @param[in] 图片信息
* @return 是否保存成功
*/
bool saveAsBmp(const char* p_pData, ImageBaseInfo& p_Info);
/** @brief windw是每隔几个采样一个。windh类推。
* @param[in]
* @param[in]
* @param[in]
* @param[out]
* @return 返回的dst是在函数内部分配的
*/
bool downsampleBmp( BitmapData& src, BitmapData& dst, int windw, int windh, bool rbBorder );
/** @brief pFrcation 是4个int表示的宽高缩放。[宽分子,宽分母,高分子,高分母]
* @param[in]
* @param[in]
* @param[in]
* @param[out]
* @return
*/
bool downsampleBmp( BitmapData& src, BitmapData& dst, int* pFrcation, bool rbBorder );
void createGridBmp( BitmapData& out, int w, int h, int gridw);
/** @brief
* 把一个灰度图转换成某种颜色,拷贝到dst中。
* @param[in] dst 目标BitmapData。
* @param[in] nSx 目标bmp的起点x
* @param[in] nSy 目标bmp的起点y
* @param[in] pSrc 源图片。是一个灰度图。灰度值表示颜色的深浅。
* @param[in] nSrcW 源图片的宽
* @param[in] nSrcH 源图片的高
* @param[in] nSrcColor 颜色。
* @return void
*/
void copy8BitBmp( BitmapData& dst, int nSx, int nSy, unsigned char* pSrc, int nSrcW, int nSrcH, int nSrcColor );
void copy32BitBmp(BitmapData& dst, int nSx, int nSy,int nDstW, unsigned char* pSrc, int nSrcW, int nSrcH, int srcPitch);
std::pair<unsigned char*, unsigned long> convertBitmapToJpeg(const char* p_pData, int nWidth, int nHeight, int nBpp);
std::pair<unsigned char*, unsigned long> convertBitmapToPng(const char* p_pData, int nWidth, int nHeight, int nBitDepth);
void convertRGBA8888ToFormat(const unsigned char* data, size_t dataLen, GLenum format, unsigned char** outData, size_t* outDataLen);
#endif
}
//------------------------------------------------------------------------------
#endif //__JCImageRW_H__
//-----------------------------END FILE--------------------------------
+425
View File
@@ -0,0 +1,425 @@
/**
@file JCJpegImg.cpp
@brief
@author hugao
@version 1.0
@date 2016_5_11
*/
#include <stdio.h>
#include <memory.h>
#include <stdlib.h>
#include "JCImageRW.h"
#include "../util/JCCommonMethod.h"
#pragma warning (disable: 4996)
//------------------------------------------------------------------------------
/*
* Include file for users of JPEG library.
* You will need to have included system headers that define at least
* the typedefs FILE and size_t before you can include jpeglib.h.
* (stdio.h is sufficient on ANSI-conforming systems.)
* You may also wish to include "jerror.h".
*/
#include "jpeglib.h"
/*
* <setjmp.h> is used for the optional error recovery mechanism shown in
* the second part of the example.
*/
#include <setjmp.h>
namespace laya
{
/******************** JPEG COMPRESSION SAMPLE INTERFACE *******************/
/* This half of the example shows how to feed data into the JPEG compressor.
* We present a minimal version that does not worry about refinements such
* as error recovery (the JPEG code will just exit() if it gets an error).
*/
/*
* ERROR HANDLING:
*
* The JPEG library's standard error handler (jerror.c) is divided into
* several "methods" which you can override individually. This lets you
* adjust the behavior without duplicating a lot of code, which you might
* have to update with each future release.
*
* Our example here shows how to override the "error_exit" method so that
* control is returned to the library's caller when a fatal error occurs,
* rather than calling exit() as the standard error_exit method does.
*
* We use C's setjmp/longjmp facility to return control. This means that the
* routine which calls the JPEG library must first execute a setjmp() call to
* establish the return point. We want the replacement error_exit to do a
* longjmp(). But we need to make the setjmp buffer accessible to the
* error_exit routine. To do this, we make a private extension of the
* standard JPEG error handler object. (If we were using C++, we'd say we
* were making a subclass of the regular error handler.)
*
* Here's the extended error handler struct:
*/
struct my_error_mgr {
struct jpeg_error_mgr pub; /* "public" fields */
jmp_buf setjmp_buffer; /* for return to caller */
};
typedef struct my_error_mgr * my_error_ptr;
/*
* Here's the routine that will replace the standard error_exit method:
*/
METHODDEF(void)
my_error_exit (j_common_ptr cinfo)
{
/* cinfo->err really points to a my_error_mgr struct, so coerce pointer */
my_error_ptr myerr = (my_error_ptr) cinfo->err;
/* Always display the message. */
/* We could postpone this until after returning, if we chose. */
(*cinfo->err->output_message) (cinfo);
/* Return control to the setjmp point */
longjmp(myerr->setjmp_buffer, 1);
}
/*
* Sample routine for JPEG decompression. We assume that the source file name
* is passed in. We want to return 1 on success, 0 on error.
*/
unsigned char* readFile(const char* filename,int &size)
{
unsigned char *infile;
FILE* fInput;
if ((fInput = fopen(filename, "rb")) == NULL)
{
fprintf(stderr, "can't open %s\n", filename);
return 0;
}
fseek(fInput,0L,SEEK_END);
size=ftell(fInput);
fseek(fInput,0L,SEEK_SET);
infile = (unsigned char*)malloc(size);
if (!infile) {
throw - 3;
}
else {
size = fread(infile, 1, size, fInput);
}
fclose(fInput);
return infile;
}
GLOBAL(int) LoadJpegFromMem (BitmapData * texture,unsigned char * infile,int size )
{
/* This struct contains the JPEG decompression parameters and pointers to
* working space (which is allocated as needed by the JPEG library).
*/
struct jpeg_decompress_struct cinfo;
/* We use our private extension JPEG error handler.
* Note that this struct must live as long as the main JPEG parameter
* struct, to avoid dangling-pointer problems.
*/
struct my_error_mgr jerr;
/* More stuff */
JSAMPARRAY buffer; /* Output row buffer */
int row_stride; /* physical row width in output buffer */
/* In this example we want to open the input file before doing anything else,
* so that the setjmp() error recovery below can assume the file is open.
* VERY IMPORTANT: use "b" option to fopen() if you are on a machine that
* requires it in order to read binary files.
*/
/* Step 1: allocate and initialize JPEG decompression object */
/* We set up the normal JPEG error routines, then override error_exit. */
cinfo.err = jpeg_std_error(&jerr.pub);
jerr.pub.error_exit = my_error_exit;
/* Establish the setjmp return context for my_error_exit to use. */
if (setjmp(jerr.setjmp_buffer)) {
/* If we get here, the JPEG code has signaled an error.
* We need to clean up the JPEG object, close the input file, and return.
*/
jpeg_destroy_decompress(&cinfo);
//fclose(infile);
return 0;
}
/* Now we can initialize the JPEG decompression object. */
jpeg_create_decompress(&cinfo);
/* Step 2: specify data source (eg, a file) */
//jpeg_stdio_src(&cinfo, infile);
jpeg_mem_src(&cinfo, infile,size);
/* Step 3: read file parameters with jpeg_read_header() */
(void) jpeg_read_header(&cinfo, TRUE);
/* We can ignore the return value from jpeg_read_header since
* (a) suspension is not possible with the stdio data source, and
* (b) we passed TRUE to reject a tables-only JPEG file as an error.
* See libjpeg.txt for more info.
*/
/* Step 4: set parameters for decompression */
/* In this example, we don't need to change any of the defaults set by
* jpeg_read_header(), so we do nothing here.
*/
if (cinfo.jpeg_color_space == JCS_GRAYSCALE)
{
}
else
{
cinfo.out_color_space = JCS_RGB;
}
/* Step 5: Start decompressor */
(void) jpeg_start_decompress(&cinfo);
/* We can ignore the return value since suspension is not possible
* with the stdio data source.
*/
texture->m_nWidth = cinfo.image_width;
texture->m_nHeight = cinfo.output_height;
texture->m_nBpp = 32;//cinfo.output_components * 8;
/*if(cinfo.output_components!=3)
{
(void)jpeg_finish_decompress(&cinfo);
jpeg_destroy_decompress(&cinfo);
return false;
}*/
#if 0
if(cinfo.output_components == 3)
{
texture->type = GL_RGB;
}
else // Else if its 32 BPP
{
texture->type = GL_RGBA;
}
texture->imageData = std::shared_ptr<GLubyte> (new GLubyte[texture->width*texture->height*cinfo.output_components], std::default_delete<char[]>());
#endif
//texture->type = GL_RGBA;
texture->m_pImageData = /*std::shared_array<char> */(new char[texture->m_nWidth*texture->m_nHeight*texture->m_nBpp / 8]);
if(texture->m_pImageData == NULL) // If no space was allocated
{
//fclose(infile); // Close the file
(void)jpeg_finish_decompress(&cinfo);
jpeg_destroy_decompress(&cinfo);
return false; // Return failed
}
/* We may need to do some setup of our own at this point before reading
* the data. After jpeg_start_decompress() we have the correct scaled
* output image dimensions available, as well as the output colormap
* if we asked for color quantization.
* In this example, we need to make an output work buffer of the right size.
*/
/* JSAMPLEs per row in output buffer */
row_stride = cinfo.output_width * cinfo.output_components;
/* Make a one-row-high sample array that will go away when done with image */
buffer = (*cinfo.mem->alloc_sarray)
((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1);
/* Step 6: while (scan lines remain to be read) */
/* jpeg_read_scanlines(...); */
/* Here we use the library's state variable cinfo.output_scanline as the
* loop counter, so that we don't have to keep track ourselves.
*/
#if 0
int bufOffset = 0;
int line =1;
while (cinfo.output_scanline < cinfo.output_height) {
/* jpeg_read_scanlines expects an array of pointers to scanlines.
* Here the array is only one element long, but you could ask for
* more than one scanline at a time if that's more convenient.
*/
(void) jpeg_read_scanlines(&cinfo, buffer, 1);
/* Assume put_scanline_someplace wants a pointer and sample count. */
bufOffset = (cinfo.output_height-line)*row_stride;
memcpy(texture->imageData+bufOffset,buffer[0],row_stride); //kuo
line++;
}
#else
int line =0;
int pixels = 0;
if (cinfo.jpeg_color_space == JCS_GRAYSCALE)
{
pixels = row_stride;
}
else
{
pixels = row_stride / 3;
}
while (cinfo.output_scanline < cinfo.output_height)
{
/* jpeg_read_scanlines expects an array of pointers to scanlines.
* Here the array is only one element long, but you could ask for
* more than one scanline at a time if that's more convenient.
*/
(void) jpeg_read_scanlines(&cinfo, buffer, 1);
unsigned char* startBuffer = (unsigned char*)texture->m_pImageData+line*pixels*4;
if (cinfo.jpeg_color_space == JCS_GRAYSCALE)
{
for (int i = 0; i < pixels; ++i)
{
startBuffer[i * 4 + 0] = buffer[0][i];
startBuffer[i * 4 + 1] = buffer[0][i];
startBuffer[i * 4 + 2] = buffer[0][i];
startBuffer[i * 4 + 3] = 255;
}
}
else
{
for (int i = 0; i < pixels; ++i)
{
startBuffer[i * 4 + 0] = buffer[0][i * 3 + 0];
startBuffer[i * 4 + 1] = buffer[0][i * 3 + 1];
startBuffer[i * 4 + 2] = buffer[0][i * 3 + 2];
startBuffer[i * 4 + 3] = 255;
}
}
/* Assume put_scanline_someplace wants a pointer and sample count. */
//memcpy(texture->imageData+line*row_stride,buffer[0],row_stride); //kuo
line++;
}
#endif
/* Step 7: Finish decompression */
(void) jpeg_finish_decompress(&cinfo);
/* We can ignore the return value since suspension is not possible
* with the stdio data source.
*/
/* Step 8: Release JPEG decompression object */
/* This is an important step since it will release a good deal of memory. */
jpeg_destroy_decompress(&cinfo);
/* After finish_decompress, we can close the input file.
* Here we postpone it until after no more JPEG errors are possible,
* so as to simplify the setjmp error logic above. (Actually, I don't
* think that jpeg_destroy can do an error exit, but why assume anything...)
*/
//fclose(infile);
/* At this point you may want to check to see whether any corrupt-data
* warnings occurred (test whether jerr.pub.num_warnings is nonzero).
*/
/* And we're done! */
return 1;
}
//------------------------------------------------------------------------------
bool LoadJpegWH( const char* p_sFileName,int& p_nWidth,int& p_nHeight )
{
return true;
}
//保存jpeg图片,要求格式必须为rgb的
bool saveJpeg(int width ,int height,int bpp, char *buffer, int quality, const char*filename){
int components = bpp/8;
if( components!=1 && components!=3 )
return false;
jpeg_compress_struct jcs;
jpeg_error_mgr jem;
FILE *fp;
JSAMPROW row_pointer[1];//?一行位图?
int row_stride; //?每一行的字节数
jcs.err = jpeg_std_error(&jem);
jpeg_create_compress(&jcs);
fp = fopen(filename,"wb");
if(fp==NULL)
return false;
jpeg_stdio_dest(&jcs,fp);
jcs.image_width = width; //位图的宽和高,单位为像素
jcs.image_height = height;
jcs.input_components =components; //?在此为1,表示灰度图,?如果是彩色位图,则为3?
jcs.in_color_space = components==3?JCS_RGB:JCS_GRAYSCALE;//JCS_GRAYSCALE表示灰度图,JCS_RGB表示彩色图像??
jpeg_set_defaults(&jcs);
jpeg_set_quality(&jcs, quality, (boolean)true);
jpeg_start_compress(&jcs,(boolean)true);
row_stride = jcs.input_components*width; /* JSAMPLEs per row in image_buffer */
while(jcs.next_scanline < jcs.image_height){
row_pointer[0] = (JSAMPROW)&buffer[jcs.next_scanline * row_stride ];
jpeg_write_scanlines(&jcs, row_pointer, 1);
}
jpeg_finish_compress(&jcs);
jpeg_destroy_compress(&jcs);
fclose(fp);
return true;
}
std::pair<unsigned char*, unsigned long> convertBitmapToJpeg(int uWidth, int uHeight, int bpp, unsigned char* pImg, int iQuality)
{
std::pair<unsigned char*, unsigned long> mRes = std::make_pair((unsigned char*)NULL, 0);
int components = bpp / 8;
if (components != 1 && components != 3)
return mRes;
jpeg_compress_struct jcInfo;
jpeg_error_mgr jErr;
jcInfo.err = jpeg_std_error(&jErr);
jpeg_create_compress(&jcInfo);
jpeg_mem_dest(&jcInfo, &mRes.first, &mRes.second);
jcInfo.image_width = uWidth;
jcInfo.image_height = uHeight;
jcInfo.input_components = 3;
jcInfo.in_color_space = JCS_RGB;
jpeg_set_defaults(&jcInfo);
jpeg_set_quality(&jcInfo, iQuality, TRUE);
jpeg_start_compress(&jcInfo, TRUE);
int iRowStride = jcInfo.image_width * jcInfo.input_components;
while (jcInfo.next_scanline < jcInfo.image_height) {
JSAMPROW pData = &(pImg[jcInfo.next_scanline * iRowStride]);
jpeg_write_scanlines(&jcInfo, &pData, 1);
}
jpeg_finish_compress(&jcInfo);
jpeg_destroy_compress(&jcInfo);
return mRes;
}
std::pair<unsigned char*, unsigned long> convertBitmapToJpeg(const char* p_pData, int nWidth, int nHeight, int nBpp)
{
char* pData = (char*)p_pData;
//32转24
if (nBpp == 32) {
pData = new char[nWidth*nHeight * 3];
char* pSrc = (char*)p_pData;
char* pDst = pData;
for (int y = 0; y < nHeight; y++) {
for (int x = 0; x < nWidth; x++) {
pDst[0] = pSrc[0]; pDst[1] = pSrc[1]; pDst[2] = pSrc[2];
pSrc += 4;
pDst += 3;
}
}
}
std::pair<unsigned char*, unsigned long> ret = convertBitmapToJpeg(nWidth, nHeight, 24, (unsigned char*)pData, 80);
if (nBpp == 32)
delete[] pData;
return ret;
}
}
//------------------------------------------------------------------------------
//-----------------------------END FILE--------------------------------
+313
View File
@@ -0,0 +1,313 @@
/**
@file JCPngImg.cpp
@brief
@author hugao
@version 1.0
@date 2016_5_11
*/
#include <string.h>
#include "png.h"
#include "pngconf.h"
#include <stdio.h>
#include <memory.h>
#include <stdlib.h>
#include "../util/JCCommonMethod.h"
#include "JCImageRW.h"
//------------------------------------------------------------------------------
#pragma warning (disable: 4996)
namespace laya
{
typedef struct
{
unsigned char* data;
int size;
int offset;
}ImageSource;
//从内存读取PNG图片的回调函数
static void pngReadCallback(png_structp png_ptr, png_bytep data, png_size_t length)
{
ImageSource* isource = (ImageSource*)png_get_io_ptr(png_ptr);
if( (int)(isource->offset + length) <= isource->size)
{
memcpy(data, isource->data+isource->offset, length);
isource->offset += length;
}
else
png_error(png_ptr, "pngReaderCallback failed");
}
void my_error_fn(png_structp png_ptr, png_const_charp error_msg)
{
}
void my_warning_fn(png_structp png_ptr,png_const_charp warning_msg)
{
}
static unsigned int multiply_alpha(unsigned int alpha, unsigned int color)
{
unsigned int temp = alpha * color + 0x80;
return (temp + (temp >> 8)) >> 8;
}
static void premultiply_data(png_structp png, png_row_infop row_info, png_bytep data)
{
unsigned int i;
for (i = 0; i < row_info->rowbytes; i += 4)
{
unsigned char* base = &data[i];
unsigned int alpha = base[3];
if (alpha == 0)
base[0] = base[1] = base[2] = base[3] = 0;
else
{
unsigned int red = base[0];
unsigned int green = base[1];
unsigned int blue = base[2];
if (alpha != 0xFF)
{
red = multiply_alpha(alpha, red);
green = multiply_alpha(alpha, green);
blue = multiply_alpha(alpha, blue);
}
base[0] = (unsigned char)red;
base[1] = (unsigned char)green;
base[2] = (unsigned char)blue;
base[3] = (unsigned char)alpha;
}
}
}
unsigned char* ReadPNGFromMem(unsigned char* data, int dataSize, PNG_UINT32* w, PNG_UINT32* h)
{
//unsigned char sig[8];
png_structp png_ptr;
png_infop info_ptr;
unsigned char* image_data;
int bit_depth;
int color_type;
unsigned int rowbytes;
png_uint_32 i;
png_bytepp row_pointers;
if ((png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, my_error_fn, my_warning_fn)) == NULL) {
return NULL;
}
if ((info_ptr = png_create_info_struct(png_ptr)) == NULL) {
png_destroy_read_struct(&png_ptr, NULL, NULL);
return NULL;
}
if (setjmp(png_jmpbuf(png_ptr))) {
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
return NULL;
}
ImageSource imgsource;
imgsource.data = data;
imgsource.size = dataSize;
imgsource.offset = 0;
png_set_read_fn(png_ptr, &imgsource,pngReadCallback);
png_read_info(png_ptr, info_ptr);
png_set_sig_bytes(png_ptr, 8);
png_get_IHDR(png_ptr, info_ptr, w, h, &bit_depth, &color_type, NULL, NULL, NULL);
//预乘alpha
//png_set_read_user_transform_fn(png_ptr, premultiply_data);
//if (color_type & PNG_COLOR_MASK_ALPHA)
// png_set_strip_alpha(png_ptr); //去掉alhpa信息了。TODO 以后要加上。
if (bit_depth >8)
png_set_strip_16(png_ptr); //16bit的通道要转换成8bit的
if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
png_set_gray_to_rgb(png_ptr);
if (color_type == PNG_COLOR_TYPE_PALETTE)
png_set_palette_to_rgb(png_ptr);
if(png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
png_set_tRNS_to_alpha(png_ptr);
// if (color_type == PNG_COLOR_TYPE_RGB)
png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER);//PNG_FILLER_BEFORE);
png_read_update_info(png_ptr, info_ptr);
rowbytes = png_get_rowbytes(png_ptr, info_ptr);
if ((image_data =(unsigned char *) malloc(*h * rowbytes)) == NULL) {
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
return NULL;
}
if ((row_pointers =(png_bytepp) malloc(*h * sizeof(png_bytep))) == NULL) {
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
free(image_data);
return NULL;
}
for (i = 0; i < *h; i++)
//row_pointers[*h - 1 - i] = image_data + i*rowbytes;
row_pointers[i] = image_data + i*rowbytes;
png_read_image(png_ptr, row_pointers);
free(row_pointers);
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
return image_data;
}
/*
//获得宽高信息,并不最终解码
bool LoadPngWH( const char* p_sFileName,int& p_nWidth,int& p_nHeight )
{
FILE* f;
unsigned char sig[8];
png_structp png_ptr;
png_infop info_ptr;
//unsigned char* image_data;
int bit_depth;
int color_type;
//unsigned int rowbytes;
//png_uint_32 i;
//png_bytepp row_pointers;
if ((f = fopen(p_sFileName, "rb")) == NULL)
return false;
fread(sig, sizeof(*sig), sizeof(sig), f);
if (!png_check_sig(sig, sizeof(*sig))) {
fclose(f);
return false;
}
if ((png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL)) == NULL) {
fclose(f);
return false;
}
if ((info_ptr = png_create_info_struct(png_ptr)) == NULL) {
png_destroy_read_struct(&png_ptr, NULL, NULL);
fclose(f);
return false;
}
if (setjmp(png_jmpbuf(png_ptr))) {
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
fclose(f);
return false;
}
png_ptr->io_ptr = (png_voidp) f;
png_set_sig_bytes(png_ptr, 8);
png_read_info(png_ptr, info_ptr);
png_uint_32 w,h;
png_get_IHDR(png_ptr, info_ptr, &w, &h, &bit_depth, &color_type, NULL, NULL, NULL);
p_nWidth = w;
p_nHeight = h;
fclose(f);
return true;
}
*/
int SavePng(char* png_file_name, char **data, int width, int height, int bit_depth)
{
png_structp png_ptr;
png_infop info_ptr;
FILE *png_file = fopen(png_file_name, "wb");
//assert(png_file);
png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if(png_ptr == NULL)
{
//cerr<<"ERROR:png_create_write_struct/n";
if (png_file)
fclose(png_file);
return 0;
}
info_ptr = png_create_info_struct(png_ptr);
if(info_ptr == NULL)
{
//cerr<<"ERROR:png_create_info_struct/n";
if (png_file) {
fclose(png_file);
}
png_destroy_write_struct(&png_ptr, NULL);
return 0;
}
png_init_io(png_ptr, png_file);
png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth, PNG_COLOR_TYPE_RGB_ALPHA,
PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
//png_set_PLTE(png_ptr, info_ptr, palette, palette_len);
png_write_info(png_ptr, info_ptr);
png_bytepp row_pointers = new png_bytep[height];
for (int i=0; i<height; ++i)
{
row_pointers[i] = (png_bytep)data[i];
}
png_write_image(png_ptr, row_pointers);
delete[] row_pointers;
png_write_end(png_ptr, info_ptr);
//png_free(png_ptr, palette);
//palette=NULL;
png_destroy_write_struct(&png_ptr, &info_ptr);
fclose(png_file);
return 0;
}
typedef unsigned char ui8;
static void PngWriteToMemoryFunc(png_structp png_ptr, png_bytep data, png_size_t length) {
std::vector<ui8> *p = (std::vector<ui8>*)png_get_io_ptr(png_ptr);
p->insert(p->end(), data, data + length);
}
std::pair<unsigned char*, unsigned long> convertBitmapToPng(const char* p_pData, int nWidth, int nHeight, int nBitDepth)
{
std::vector<unsigned char> buffer;
buffer.reserve(nWidth * nHeight * 4);
std::pair<unsigned char*, unsigned long> res
= std::make_pair((unsigned char*)NULL, 0);
png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL, NULL, NULL);
if (!png_ptr)
return res;
png_infop info_ptr = png_create_info_struct(png_ptr);
if (!info_ptr)
return res;
if (setjmp(png_jmpbuf(png_ptr)))
return res;
png_set_write_fn(png_ptr, &buffer, PngWriteToMemoryFunc, NULL);
png_set_IHDR(png_ptr, info_ptr,
nWidth,
nHeight,
8,
PNG_COLOR_TYPE_RGB_ALPHA,
PNG_INTERLACE_NONE,
PNG_COMPRESSION_TYPE_DEFAULT,
PNG_FILTER_TYPE_DEFAULT);
png_write_info(png_ptr, info_ptr);
for (int i = 0; i < nHeight; i++)
png_write_row(png_ptr, (unsigned char*)p_pData + i * nWidth * 4);
png_write_end(png_ptr, info_ptr);
png_destroy_write_struct(&png_ptr, &info_ptr);
unsigned long nByte = buffer.size();
unsigned char* pBuffer = new unsigned char[nByte];
memcpy(pBuffer, &buffer[0], nByte);
res.first = pBuffer;
res.second = nByte;
return res;
}
}
//------------------------------------------------------------------------------
//-----------------------------END FILE--------------------------------