U
ufo007
Unregistered / Unconfirmed
GUEST, unregistred user!
PhotoShop,我想没有人会不知道吧。如今最新的版本是6.0,其图象文件*.PSD和5.5相比变化并不太大。以下我就介绍
*.PSD文件的读取方法,并提供完整读取函数。
其中:m_Rect为目标区域,m_lpDDS7为目标DirectDraw表面,m_pbAlphaMask为目标Aplha通告指针(有关Alpha的相关文
章请看云风的文章)。Read16函数为从指定文件当前位置读取一个WORD,Read32函数为从指定文件当前位置读取一个DWORD。
MAX_PSD_CHANNELS为24。
HRESULT LoadPSD( LPSTR strFilename ) // 读取PSD文件
{
DWORD dwWidth, dwHeight;
// 宽高
long lSurfWidth = m_Rect.right - m_Rect.left;
long lSurfHeight = m_Rect.bottom - m_Rect.top;
WORD CompressionType;
// 压缩类型
HDC hDC;
FILE *fpPSD;
WORD ChannelCount;
// 通道数
// 打开PSD文件
if ( ( fpPSD = fopen ( strFilename, "rb" ) ) == NULL ) {
return E_FAIL;
}
// 头四个字节为"8BPS"
char signature[5];
signature[0] = fgetc( fpPSD );
signature[1] = fgetc( fpPSD );
signature[2] = fgetc( fpPSD );
signature[3] = fgetc( fpPSD );
signature[4] = '/0';
if ( strcmp( signature,"8BPS" ) != 0 ) {
return E_FAIL;
}
// 版本必须为1
if ( Read16( fpPSD ) != 1 ) {
return E_FAIL;
}
// 跳过一些数据 (总是0)
Read32( fpPSD );
Read16( fpPSD );
// 读取通道数
ChannelCount = Read16( fpPSD );
// 确定至少有一个通道
if ( ( ChannelCount < 0 ) || ( ChannelCount > MAX_PSD_CHANNELS ) ) {
return E_FAIL;
}
// 读入宽和高
dwHeight = Read32( fpPSD );
dwWidth = Read32( fpPSD );
if ( dwWidth != ( DWORD )lSurfWidth ||
dwHeight != ( DWORD )lSurfHeight ) {
return E_FAIL;
}
// 只读入8位通道
if ( Read16( fpPSD ) != 8 ) {
return E_FAIL;
}
// 确定模式为RGB.
// 可能值:
// 0: 位图
// 1: 灰阶
// 2: 索引
// 3: RGB
// 4: CMYK
// 7: Multichannel
// 8: Duotone
// 9: Lab
if ( Read16( fpPSD ) != 3 ) {
return E_FAIL;
}
// 跳过数据(如调色板)
int ModeDataCount = Read32( fpPSD );
if ( ModeDataCount )
fseek( fpPSD, ModeDataCount, SEEK_CUR );
// 跳过数据(如:pen tool paths, etc)
int ResourceDataCount = Read32( fpPSD );
if ( ResourceDataCount )
fseek( fpPSD, ResourceDataCount, SEEK_CUR );
// 条过保留数据
int ReservedDataCount = Read32( fpPSD );
if ( ReservedDataCount )
fseek( fpPSD, ReservedDataCount, SEEK_CUR );
// 0: 非压缩
// 1: RLE压缩
CompressionType = Read16( fpPSD );
if ( CompressionType > 1 ) {
return E_FAIL;
}
BYTE* PSDPixels = new BYTE[ ( lSurfWidth * lSurfHeight ) * 4 ];
// 解包数据
UnPackPSD( fpPSD, lSurfWidth, lSurfHeight, PSDPixels, ChannelCount, CompressionType );
fclose( fpPSD );
// 复制信息
BITMAPINFO BitmapInfo;
ZeroMemory( &BitmapInfo, sizeof( BitmapInfo ) );
BitmapInfo.bmiHeader.biSize = sizeof( BitmapInfo.bmiHeader );
BitmapInfo.bmiHeader.biWidth = lSurfWidth;
BitmapInfo.bmiHeader.biHeight = -lSurfHeight;
BitmapInfo.bmiHeader.biPlanes = 1;
BitmapInfo.bmiHeader.biBitCount = 32;
m_lpDDS7->GetDC( &hDC );
int rc = StretchDIBits( hDC,
0,
0,
lSurfWidth,
lSurfHeight,
0,
0,
lSurfWidth,
lSurfHeight,
PSDPixels,
&BitmapInfo,
DIB_RGB_COLORS,
SRCCOPY );
m_lpDDS7->ReleaseDC( hDC );
if ( rc == GDI_ERROR ) {
H_ARRAY_DELETE( PSDPixels );
#ifdef _DEBUG
g_pHERR->OutDebugMsg( 3, H2DSERR_INVALID_PSD );
#endif
return E_FAIL;
}
// 是否读取Alpha混合通道
if( ChannelCount > 3 ) {
m_pbAlphaMask = new BYTE[ lSurfWidth * lSurfHeight ];
for ( int x = 0;
x < lSurfWidth;
x++ )
for ( int y = 0;
y < lSurfHeight;
y++ ) {
m_pbAlphaMask[ ( y * lSurfWidth ) + x ] = PSDPixels[ ( ( ( y * lSurfHeight ) + x ) * 4 ) + 3 ];
}
} else
{
m_pbAlphaMask = NULL;
}
H_ARRAY_DELETE( PSDPixels );
return DD_OK;
}
void CHades2DSurface::UnPackPSD( FILE *fp, DWORD dwWidth, DWORD dwHeight, BYTE* pixels, WORD ChannelCnt, WORD Compression )
// PSD文件解包
// fp为PSD文件指针,dwWidth、dwHeight为宽高,poxels为解包目标指针,
// ChannelCnt为通道数,Compression位压缩类型。
{
int Default[4] = { 0, 0, 0, 255 };
int chn[4] = { 2, 1, 0, 3};
int PixelCount = dwWidth * dwHeight;
if ( Compression ) {
fseek( fp, dwHeight * ChannelCnt * 2, SEEK_CUR );
for ( int c = 0;
c < 4;
c++ ) {
int pn = 0;
int channel = chn[c];
if ( channel >= ChannelCnt ) {
for ( pn=0;
pn < PixelCount pn++ ) {
pixels[ ( pn * 4 ) + channel ] = Default[ channel ];
}
} else
// 非压缩
{
int count = 0;
while( count < PixelCount ) {
int len = fgetc( fp );
if( len == 128 ) { }
else
if ( len < 128 ) // 非RLE
{
len++;
count += len;
while(len) {
pixels[ ( pn * 4 ) + channel ] = fgetc( fp );
pn++;
len--;
}
} else
if ( len > 128 ) // RLE打包
{
len ^= 0x0FF;
len += 2;
unsigned char val = fgetc( fp );
count += len;
while( len ) {
pixels[ ( pn * 4 ) + channel ] = val;
pn++;
len--;
}
}
}
}
}
} else
{
for ( int c=0;
c < 4;
c++ ) {
int channel = chn[c];
if ( channel > ChannelCnt ) {
for( int pn = 0;
pn < PixelCount;
pn++ ) {
pixels[ ( pn * 4 ) + channel ] = Default[ channel ];
}
} else
{
for( int n = 0;
n < PixelCount;
n++ ) {
pixels[ ( n * 4 ) + channel ] = fgetc( fp );
}
}
}
}
}
以上就是*.PSD文件的读取方法,有兴趣的朋友可以继续深入研究,到时可别忘了发我一份。
*.PSD文件的读取方法,并提供完整读取函数。
其中:m_Rect为目标区域,m_lpDDS7为目标DirectDraw表面,m_pbAlphaMask为目标Aplha通告指针(有关Alpha的相关文
章请看云风的文章)。Read16函数为从指定文件当前位置读取一个WORD,Read32函数为从指定文件当前位置读取一个DWORD。
MAX_PSD_CHANNELS为24。
HRESULT LoadPSD( LPSTR strFilename ) // 读取PSD文件
{
DWORD dwWidth, dwHeight;
// 宽高
long lSurfWidth = m_Rect.right - m_Rect.left;
long lSurfHeight = m_Rect.bottom - m_Rect.top;
WORD CompressionType;
// 压缩类型
HDC hDC;
FILE *fpPSD;
WORD ChannelCount;
// 通道数
// 打开PSD文件
if ( ( fpPSD = fopen ( strFilename, "rb" ) ) == NULL ) {
return E_FAIL;
}
// 头四个字节为"8BPS"
char signature[5];
signature[0] = fgetc( fpPSD );
signature[1] = fgetc( fpPSD );
signature[2] = fgetc( fpPSD );
signature[3] = fgetc( fpPSD );
signature[4] = '/0';
if ( strcmp( signature,"8BPS" ) != 0 ) {
return E_FAIL;
}
// 版本必须为1
if ( Read16( fpPSD ) != 1 ) {
return E_FAIL;
}
// 跳过一些数据 (总是0)
Read32( fpPSD );
Read16( fpPSD );
// 读取通道数
ChannelCount = Read16( fpPSD );
// 确定至少有一个通道
if ( ( ChannelCount < 0 ) || ( ChannelCount > MAX_PSD_CHANNELS ) ) {
return E_FAIL;
}
// 读入宽和高
dwHeight = Read32( fpPSD );
dwWidth = Read32( fpPSD );
if ( dwWidth != ( DWORD )lSurfWidth ||
dwHeight != ( DWORD )lSurfHeight ) {
return E_FAIL;
}
// 只读入8位通道
if ( Read16( fpPSD ) != 8 ) {
return E_FAIL;
}
// 确定模式为RGB.
// 可能值:
// 0: 位图
// 1: 灰阶
// 2: 索引
// 3: RGB
// 4: CMYK
// 7: Multichannel
// 8: Duotone
// 9: Lab
if ( Read16( fpPSD ) != 3 ) {
return E_FAIL;
}
// 跳过数据(如调色板)
int ModeDataCount = Read32( fpPSD );
if ( ModeDataCount )
fseek( fpPSD, ModeDataCount, SEEK_CUR );
// 跳过数据(如:pen tool paths, etc)
int ResourceDataCount = Read32( fpPSD );
if ( ResourceDataCount )
fseek( fpPSD, ResourceDataCount, SEEK_CUR );
// 条过保留数据
int ReservedDataCount = Read32( fpPSD );
if ( ReservedDataCount )
fseek( fpPSD, ReservedDataCount, SEEK_CUR );
// 0: 非压缩
// 1: RLE压缩
CompressionType = Read16( fpPSD );
if ( CompressionType > 1 ) {
return E_FAIL;
}
BYTE* PSDPixels = new BYTE[ ( lSurfWidth * lSurfHeight ) * 4 ];
// 解包数据
UnPackPSD( fpPSD, lSurfWidth, lSurfHeight, PSDPixels, ChannelCount, CompressionType );
fclose( fpPSD );
// 复制信息
BITMAPINFO BitmapInfo;
ZeroMemory( &BitmapInfo, sizeof( BitmapInfo ) );
BitmapInfo.bmiHeader.biSize = sizeof( BitmapInfo.bmiHeader );
BitmapInfo.bmiHeader.biWidth = lSurfWidth;
BitmapInfo.bmiHeader.biHeight = -lSurfHeight;
BitmapInfo.bmiHeader.biPlanes = 1;
BitmapInfo.bmiHeader.biBitCount = 32;
m_lpDDS7->GetDC( &hDC );
int rc = StretchDIBits( hDC,
0,
0,
lSurfWidth,
lSurfHeight,
0,
0,
lSurfWidth,
lSurfHeight,
PSDPixels,
&BitmapInfo,
DIB_RGB_COLORS,
SRCCOPY );
m_lpDDS7->ReleaseDC( hDC );
if ( rc == GDI_ERROR ) {
H_ARRAY_DELETE( PSDPixels );
#ifdef _DEBUG
g_pHERR->OutDebugMsg( 3, H2DSERR_INVALID_PSD );
#endif
return E_FAIL;
}
// 是否读取Alpha混合通道
if( ChannelCount > 3 ) {
m_pbAlphaMask = new BYTE[ lSurfWidth * lSurfHeight ];
for ( int x = 0;
x < lSurfWidth;
x++ )
for ( int y = 0;
y < lSurfHeight;
y++ ) {
m_pbAlphaMask[ ( y * lSurfWidth ) + x ] = PSDPixels[ ( ( ( y * lSurfHeight ) + x ) * 4 ) + 3 ];
}
} else
{
m_pbAlphaMask = NULL;
}
H_ARRAY_DELETE( PSDPixels );
return DD_OK;
}
void CHades2DSurface::UnPackPSD( FILE *fp, DWORD dwWidth, DWORD dwHeight, BYTE* pixels, WORD ChannelCnt, WORD Compression )
// PSD文件解包
// fp为PSD文件指针,dwWidth、dwHeight为宽高,poxels为解包目标指针,
// ChannelCnt为通道数,Compression位压缩类型。
{
int Default[4] = { 0, 0, 0, 255 };
int chn[4] = { 2, 1, 0, 3};
int PixelCount = dwWidth * dwHeight;
if ( Compression ) {
fseek( fp, dwHeight * ChannelCnt * 2, SEEK_CUR );
for ( int c = 0;
c < 4;
c++ ) {
int pn = 0;
int channel = chn[c];
if ( channel >= ChannelCnt ) {
for ( pn=0;
pn < PixelCount pn++ ) {
pixels[ ( pn * 4 ) + channel ] = Default[ channel ];
}
} else
// 非压缩
{
int count = 0;
while( count < PixelCount ) {
int len = fgetc( fp );
if( len == 128 ) { }
else
if ( len < 128 ) // 非RLE
{
len++;
count += len;
while(len) {
pixels[ ( pn * 4 ) + channel ] = fgetc( fp );
pn++;
len--;
}
} else
if ( len > 128 ) // RLE打包
{
len ^= 0x0FF;
len += 2;
unsigned char val = fgetc( fp );
count += len;
while( len ) {
pixels[ ( pn * 4 ) + channel ] = val;
pn++;
len--;
}
}
}
}
}
} else
{
for ( int c=0;
c < 4;
c++ ) {
int channel = chn[c];
if ( channel > ChannelCnt ) {
for( int pn = 0;
pn < PixelCount;
pn++ ) {
pixels[ ( pn * 4 ) + channel ] = Default[ channel ];
}
} else
{
for( int n = 0;
n < PixelCount;
n++ ) {
pixels[ ( n * 4 ) + channel ] = fgetc( fp );
}
}
}
}
}
以上就是*.PSD文件的读取方法,有兴趣的朋友可以继续深入研究,到时可别忘了发我一份。