Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

571 lines
16 KiB

  1. //===== Copyright � 1996-2005, Valve Corporation, All rights reserved. ======//
  2. //
  3. // Purpose:
  4. //
  5. //===========================================================================//
  6. #include "bitmap/psd.h"
  7. #include "tier0/dbg.h"
  8. #include "tier1/utlbuffer.h"
  9. #include "filesystem.h"
  10. #include "tier2/tier2.h"
  11. #include "tier2/utlstreambuffer.h"
  12. #include "bitmap/imageformat.h"
  13. #include "bitmap/bitmap.h"
  14. // memdbgon must be the last include file in a .cpp file!!!
  15. #include "tier0/memdbgon.h"
  16. //-----------------------------------------------------------------------------
  17. // The PSD signature bytes
  18. //-----------------------------------------------------------------------------
  19. #define PSD_SIGNATURE 0x38425053
  20. #define PSD_IMGRES_SIGNATURE 0x3842494D
  21. //-----------------------------------------------------------------------------
  22. // Format of the PSD header on disk
  23. // NOTE: PSD file header, everything is bigendian
  24. //-----------------------------------------------------------------------------
  25. #pragma pack (1)
  26. enum PSDMode_t
  27. {
  28. MODE_GREYSCALE = 1,
  29. MODE_PALETTIZED = 2,
  30. MODE_RGBA = 3,
  31. MODE_CMYK = 4,
  32. MODE_MULTICHANNEL = 7,
  33. MODE_LAB = 9,
  34. MODE_COUNT = 10,
  35. };
  36. //////////////////////////////////////////////////////////////////////////
  37. //
  38. // BEGIN PSD FILE:
  39. //
  40. // PSDHeader_t
  41. // unsigned int numBytesPalette;
  42. // byte palette[ numBytesPalette ]; = { (all red palette entries), (all green palette entries), (all blue palette entries) }, where numEntries = numBytesPalette/3;
  43. // unsigned int numBytesImgResources;
  44. // byte imgresources[ numBytesImgResources ]; = { sequence of PSDImgResEntry_t }
  45. // unsigned int numBytesLayers;
  46. // byte layers[ numBytesLayers ];
  47. // unsigned short uCompressionInfo;
  48. // < ~ image data ~ >
  49. //
  50. // END PSD FILE
  51. //
  52. //////////////////////////////////////////////////////////////////////////
  53. struct PSDHeader_t
  54. {
  55. unsigned int m_nSignature;
  56. unsigned short m_nVersion;
  57. unsigned char m_pReserved[6];
  58. unsigned short m_nChannels;
  59. unsigned int m_nRows;
  60. unsigned int m_nColumns;
  61. unsigned short m_nDepth;
  62. unsigned short m_nMode;
  63. };
  64. struct PSDPalette_t
  65. {
  66. unsigned char *m_pRed;
  67. unsigned char *m_pGreen;
  68. unsigned char *m_pBlue;
  69. };
  70. //-----------------------------------------------------------------------------
  71. // NOTE: This is how we could load files using file mapping
  72. //-----------------------------------------------------------------------------
  73. //HANDLE File = CreateFile(FileName,GENERIC_READ,0,0,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);
  74. //Assert(File != INVALID_HANDLE_VALUE);
  75. //HANDLE FileMap = CreateFileMapping(File,0,PAGE_READONLY,0,0,0);
  76. //Assert(FileMap != INVALID_HANDLE_VALUE);
  77. //void *FileData = MapViewOfFile(FileMap,FILE_MAP_READ,0,0,0);
  78. //-----------------------------------------------------------------------------
  79. // Is it a PSD file?
  80. //-----------------------------------------------------------------------------
  81. bool IsPSDFile( CUtlBuffer &buf )
  82. {
  83. int nGet = buf.TellGet();
  84. PSDHeader_t header;
  85. buf.Get( &header, sizeof(header) );
  86. buf.SeekGet( CUtlBuffer::SEEK_HEAD, nGet );
  87. if ( BigLong( header.m_nSignature ) != PSD_SIGNATURE )
  88. return false;
  89. if ( BigShort( header.m_nVersion ) != 1 )
  90. return false;
  91. return ( BigShort( header.m_nDepth ) == 8 );
  92. }
  93. bool IsPSDFile( const char *pFileName, const char *pPathID )
  94. {
  95. CUtlBuffer buf;
  96. if ( !g_pFullFileSystem->ReadFile( pFileName, pPathID, buf, sizeof(PSDHeader_t) ) )
  97. {
  98. Warning( "Unable to read file %s\n", pFileName );
  99. return false;
  100. }
  101. return IsPSDFile( buf );
  102. }
  103. //-----------------------------------------------------------------------------
  104. // Returns information about the PSD file
  105. //-----------------------------------------------------------------------------
  106. bool PSDGetInfo( CUtlBuffer &buf, int *pWidth, int *pHeight, ImageFormat *pImageFormat, float *pSourceGamma )
  107. {
  108. int nGet = buf.TellGet();
  109. PSDHeader_t header;
  110. buf.Get( &header, sizeof(header) );
  111. buf.SeekGet( CUtlBuffer::SEEK_HEAD, nGet );
  112. if ( BigLong( header.m_nSignature ) != PSD_SIGNATURE )
  113. return false;
  114. if ( BigShort( header.m_nVersion ) != 1 )
  115. return false;
  116. if ( BigShort( header.m_nDepth ) != 8 )
  117. return false;
  118. *pWidth = BigLong( header.m_nColumns );
  119. *pHeight = BigLong( header.m_nRows );
  120. *pImageFormat = BigShort( header.m_nChannels ) == 3 ? IMAGE_FORMAT_RGB888 : IMAGE_FORMAT_RGBA8888;
  121. *pSourceGamma = ARTWORK_GAMMA;
  122. return true;
  123. }
  124. bool PSDGetInfo( const char *pFileName, const char *pPathID, int *pWidth, int *pHeight, ImageFormat *pImageFormat, float *pSourceGamma )
  125. {
  126. CUtlBuffer buf;
  127. if ( !g_pFullFileSystem->ReadFile( pFileName, pPathID, buf, sizeof(PSDHeader_t) ) )
  128. {
  129. Warning( "Unable to read file %s\n", pFileName );
  130. return false;
  131. }
  132. return PSDGetInfo( buf, pWidth, pHeight, pImageFormat, pSourceGamma );
  133. }
  134. //-----------------------------------------------------------------------------
  135. // Get PSD file image resources
  136. //-----------------------------------------------------------------------------
  137. PSDImageResources PSDGetImageResources( CUtlBuffer &buf )
  138. {
  139. int nGet = buf.TellGet();
  140. // Header
  141. PSDHeader_t header;
  142. buf.Get( &header, sizeof( header ) );
  143. // Then palette
  144. unsigned int numBytesPalette = BigLong( buf.GetUnsignedInt() );
  145. buf.SeekGet( CUtlBuffer::SEEK_CURRENT, numBytesPalette );
  146. // Then image resources
  147. unsigned int numBytesImgResources = BigLong( buf.GetUnsignedInt() );
  148. PSDImageResources imgres( numBytesImgResources, ( unsigned char * ) buf.PeekGet() );
  149. // Restore the seek
  150. buf.SeekGet( CUtlBuffer::SEEK_HEAD, nGet );
  151. return imgres;
  152. }
  153. //-----------------------------------------------------------------------------
  154. // Converts from CMYK to RGB
  155. //-----------------------------------------------------------------------------
  156. static inline void CMYKToRGB( RGBA8888_t &color )
  157. {
  158. unsigned char nCyan = 255 - color.r;
  159. unsigned char nMagenta = 255 - color.g;
  160. unsigned char nYellow = 255 - color.b;
  161. unsigned char nBlack = 255 - color.a;
  162. int nCyanBlack = (int)nCyan + (int)nBlack;
  163. int nMagentaBlack = (int)nMagenta + (int)nBlack;
  164. int nYellowBlack = (int)nYellow + (int)nBlack;
  165. color.r = ( nCyanBlack < 255 ) ? 255 - nCyanBlack : 0;
  166. color.g = ( nMagentaBlack < 255 ) ? 255 - nMagentaBlack : 0;
  167. color.b = ( nYellowBlack < 255 ) ? 255 - nYellowBlack : 0;
  168. color.a = 255;
  169. }
  170. //-----------------------------------------------------------------------------
  171. // Deals with uncompressed channels
  172. //-----------------------------------------------------------------------------
  173. static void PSDConvertToRGBA8888( int nChannelsCount, PSDMode_t mode, PSDPalette_t &palette, Bitmap_t &bitmap )
  174. {
  175. bool bShouldFillInAlpha = false;
  176. unsigned char *pDest = bitmap.GetBits();
  177. switch( mode )
  178. {
  179. case MODE_RGBA:
  180. bShouldFillInAlpha = ( nChannelsCount == 3 );
  181. break;
  182. case MODE_PALETTIZED:
  183. {
  184. // Convert from palette
  185. bShouldFillInAlpha = ( nChannelsCount == 1 );
  186. for( int j=0; j < bitmap.Height(); ++j )
  187. {
  188. for ( int k = 0; k < bitmap.Width(); ++k, pDest += 4 )
  189. {
  190. unsigned char nPaletteIndex = pDest[0];
  191. pDest[0] = palette.m_pRed[nPaletteIndex];
  192. pDest[1] = palette.m_pGreen[nPaletteIndex];
  193. pDest[2] = palette.m_pBlue[nPaletteIndex];
  194. }
  195. }
  196. }
  197. break;
  198. case MODE_GREYSCALE:
  199. {
  200. // Monochrome
  201. bShouldFillInAlpha = ( nChannelsCount == 1 );
  202. for( int j=0; j < bitmap.Height(); ++j )
  203. {
  204. for ( int k = 0; k < bitmap.Width(); ++k, pDest += 4 )
  205. {
  206. pDest[1] = pDest[0];
  207. pDest[2] = pDest[0];
  208. }
  209. }
  210. }
  211. break;
  212. case MODE_CMYK:
  213. {
  214. // NOTE: The conversion will fill in alpha by default
  215. bShouldFillInAlpha = false;
  216. for( int j=0; j < bitmap.Height(); ++j )
  217. {
  218. for ( int k = 0; k < bitmap.Width(); ++k, pDest += 4 )
  219. {
  220. CMYKToRGB( *((RGBA8888_t*)pDest) );
  221. }
  222. }
  223. }
  224. break;
  225. }
  226. if ( bShouldFillInAlpha )
  227. {
  228. // No alpha channel, fill in white
  229. unsigned char *pDest = bitmap.GetBits();
  230. for( int j=0; j < bitmap.Height(); ++j )
  231. {
  232. for ( int k = 0; k < bitmap.Width(); ++k, pDest += 4 )
  233. {
  234. pDest[3] = 0xFF;
  235. }
  236. }
  237. }
  238. }
  239. //-----------------------------------------------------------------------------
  240. // Deals with uncompressed channels
  241. //-----------------------------------------------------------------------------
  242. static int s_pChannelIndex[MODE_COUNT+1][4] =
  243. {
  244. { -1, -1, -1, -1 },
  245. { 0, 3, -1, -1 }, // MODE_GREYSCALE
  246. { 0, 3, -1, -1 }, // MODE_PALETTIZED
  247. { 0, 1, 2, 3 }, // MODE_RGBA
  248. { 0, 1, 2, 3 }, // MODE_CMYK
  249. { -1, -1, -1, -1 },
  250. { -1, -1, -1, -1 },
  251. { -1, -1, -1, -1 }, // MODE_MULTICHANNEL
  252. { -1, -1, -1, -1 },
  253. { -1, -1, -1, -1 }, // MODE_LAB
  254. { 3, -1, -1, -1 }, // Secret second pass mode for CMYK
  255. };
  256. static void PSDReadUncompressedChannels( CUtlBuffer &buf, int nChannelsCount, PSDMode_t mode, PSDPalette_t &palette, Bitmap_t &bitmap )
  257. {
  258. unsigned char *pChannelRow = (unsigned char*)stackalloc( bitmap.Width() );
  259. for ( int i=0; i<nChannelsCount; ++i )
  260. {
  261. int nIndex = s_pChannelIndex[mode][i];
  262. Assert( nIndex != -1 );
  263. unsigned char *pDest = bitmap.GetBits();
  264. for( int j=0; j < bitmap.Height(); ++j )
  265. {
  266. buf.Get( pChannelRow, bitmap.Width() );
  267. // Collate the channels together
  268. for ( int k = 0; k < bitmap.Width(); ++k, pDest += 4 )
  269. {
  270. pDest[nIndex] = pChannelRow[k];
  271. }
  272. }
  273. }
  274. PSDConvertToRGBA8888( nChannelsCount, mode, palette, bitmap );
  275. }
  276. //-----------------------------------------------------------------------------
  277. // Deals with compressed channels
  278. //-----------------------------------------------------------------------------
  279. static void PSDReadCompressedChannels( CUtlBuffer &buf, int nChannelsCount, PSDMode_t mode, PSDPalette_t &palette, Bitmap_t &bitmap )
  280. {
  281. unsigned char *pChannelRow = (unsigned char*)stackalloc( bitmap.Width() );
  282. for ( int i=0; i<nChannelsCount; ++i )
  283. {
  284. int nIndex = s_pChannelIndex[mode][i];
  285. Assert( nIndex != -1 );
  286. unsigned char *pDest = bitmap.GetBits();
  287. for( int j=0; j < bitmap.Height(); ++j )
  288. {
  289. unsigned char *pSrc = pChannelRow;
  290. unsigned int nPixelsRemaining = bitmap.Width();
  291. while ( nPixelsRemaining > 0 )
  292. {
  293. int nCount = buf.GetChar();
  294. if ( nCount >= 0 )
  295. {
  296. // If nCount is between 0 + 7F, it means copy the next nCount+1 bytes directly
  297. ++nCount;
  298. Assert( (unsigned int)nCount <= nPixelsRemaining );
  299. buf.Get( pSrc, nCount );
  300. }
  301. else
  302. {
  303. // If nCount is between 80 and FF, it means replicate the next byte -Count+1 times
  304. nCount = -nCount + 1;
  305. Assert( (unsigned int)nCount <= nPixelsRemaining );
  306. unsigned char nPattern = buf.GetUnsignedChar();
  307. memset( pSrc, nPattern, nCount );
  308. }
  309. pSrc += nCount;
  310. nPixelsRemaining -= nCount;
  311. }
  312. Assert( nPixelsRemaining == 0 );
  313. // Collate the channels together
  314. for ( int k = 0; k < bitmap.Width(); ++k, pDest += 4 )
  315. {
  316. pDest[nIndex] = pChannelRow[k];
  317. }
  318. }
  319. }
  320. PSDConvertToRGBA8888( nChannelsCount, mode, palette, bitmap );
  321. }
  322. //-----------------------------------------------------------------------------
  323. // Reads the PSD file into the specified buffer
  324. //-----------------------------------------------------------------------------
  325. bool PSDReadFileRGBA8888( CUtlBuffer &buf, Bitmap_t &bitmap )
  326. {
  327. PSDHeader_t header;
  328. buf.Get( &header, sizeof(header) );
  329. if ( BigLong( header.m_nSignature ) != PSD_SIGNATURE )
  330. return false;
  331. if ( BigShort( header.m_nVersion ) != 1 )
  332. return false;
  333. if ( BigShort( header.m_nDepth ) != 8 )
  334. return false;
  335. PSDMode_t mode = (PSDMode_t)BigShort( header.m_nMode );
  336. int nChannelsCount = BigShort( header.m_nChannels );
  337. if ( mode == MODE_MULTICHANNEL || mode == MODE_LAB )
  338. return false;
  339. switch ( mode )
  340. {
  341. case MODE_RGBA:
  342. if ( nChannelsCount < 3 )
  343. return false;
  344. break;
  345. case MODE_GREYSCALE:
  346. case MODE_PALETTIZED:
  347. if ( nChannelsCount != 1 && nChannelsCount != 2 )
  348. return false;
  349. break;
  350. case MODE_CMYK:
  351. if ( nChannelsCount < 4 )
  352. return false;
  353. break;
  354. default:
  355. Warning( "Unsupported PSD color mode!\n" );
  356. return false;
  357. }
  358. int nWidth = BigLong( header.m_nColumns );
  359. int nHeight = BigLong( header.m_nRows );
  360. // Skip parts of memory we don't care about
  361. int nColorModeSize = BigLong( buf.GetUnsignedInt() );
  362. Assert( nColorModeSize % 3 == 0 );
  363. unsigned char *pPaletteBits = (unsigned char*)stackalloc( nColorModeSize );
  364. PSDPalette_t palette;
  365. palette.m_pRed = palette.m_pGreen = palette.m_pBlue = 0;
  366. if ( nColorModeSize )
  367. {
  368. int nPaletteSize = nColorModeSize / 3;
  369. buf.Get( pPaletteBits, nColorModeSize );
  370. palette.m_pRed = pPaletteBits;
  371. palette.m_pGreen = palette.m_pRed + nPaletteSize;
  372. palette.m_pBlue = palette.m_pGreen + nPaletteSize;
  373. }
  374. int nImageResourcesSize = BigLong( buf.GetUnsignedInt() );
  375. buf.SeekGet( CUtlBuffer::SEEK_CURRENT, nImageResourcesSize );
  376. int nLayersSize = BigLong( buf.GetUnsignedInt() );
  377. buf.SeekGet( CUtlBuffer::SEEK_CURRENT, nLayersSize );
  378. unsigned short nCompressionType = BigShort( buf.GetShort() );
  379. bitmap.Init( nWidth, nHeight, IMAGE_FORMAT_RGBA8888 );
  380. bool bSecondPassCMYKA = ( nChannelsCount > 4 && mode == MODE_CMYK );
  381. if ( nCompressionType == 0 )
  382. {
  383. PSDReadUncompressedChannels( buf, ( nChannelsCount > 4 ) ? 4 : nChannelsCount, mode, palette, bitmap );
  384. }
  385. else
  386. {
  387. // Skip the data that indicates the length of each compressed row in bytes
  388. // NOTE: There are two bytes per row per channel
  389. unsigned int nLineLengthData = sizeof(unsigned short) * bitmap.Height() * nChannelsCount;
  390. buf.SeekGet( CUtlBuffer::SEEK_CURRENT, nLineLengthData );
  391. PSDReadCompressedChannels( buf, ( nChannelsCount > 4 ) ? 4 : nChannelsCount, mode, palette, bitmap );
  392. }
  393. // Read the alpha in a second pass for CMYKA
  394. if ( bSecondPassCMYKA )
  395. {
  396. if ( nCompressionType == 0 )
  397. {
  398. PSDReadUncompressedChannels( buf, 1, MODE_COUNT, palette, bitmap );
  399. }
  400. else
  401. {
  402. PSDReadCompressedChannels( buf, 1, MODE_COUNT, palette, bitmap );
  403. }
  404. }
  405. return true;
  406. }
  407. //-----------------------------------------------------------------------------
  408. // Loads the heightfield from a file
  409. //-----------------------------------------------------------------------------
  410. bool PSDReadFileRGBA8888( const char *pFileName, const char *pPathID, Bitmap_t &bitmap )
  411. {
  412. CUtlStreamBuffer buf( pFileName, pPathID, CUtlBuffer::READ_ONLY );
  413. if ( !g_pFullFileSystem->ReadFile( pFileName, pPathID, buf, sizeof(PSDHeader_t) ) )
  414. {
  415. Warning( "Unable to read file %s\n", pFileName );
  416. return false;
  417. }
  418. return PSDReadFileRGBA8888( buf, bitmap );
  419. }
  420. //////////////////////////////////////////////////////////////////////////
  421. //
  422. // PSD Helper structs implementation
  423. //
  424. //////////////////////////////////////////////////////////////////////////
  425. PSDImageResources::ResElement PSDImageResources::FindElement( Resource eType ) const
  426. {
  427. ResElement res;
  428. memset( &res, 0, sizeof( res ) );
  429. unsigned char const *pvBuffer = m_pvBuffer, * const pvBufferEnd = m_pvBuffer + m_numBytes;
  430. while ( pvBuffer < pvBufferEnd )
  431. {
  432. // 4 : signature
  433. // 2 : type
  434. // 4 : reserved
  435. // 2 : length
  436. // bytes[ length ]
  437. uint32 uSignature = BigLong( *( uint32* )( pvBuffer ) );
  438. pvBuffer += 4;
  439. if ( uSignature != PSD_IMGRES_SIGNATURE )
  440. break;
  441. unsigned short uType = BigShort( *( unsigned short * )( pvBuffer ) );
  442. pvBuffer += 6;
  443. unsigned short uLength = BigShort( *( unsigned short * )( pvBuffer ) );
  444. pvBuffer += 2;
  445. if ( uType == eType )
  446. {
  447. res.m_eType = eType;
  448. res.m_numBytes = uLength;
  449. res.m_pvData = pvBuffer;
  450. break;
  451. }
  452. else
  453. {
  454. pvBuffer += ( ( uLength + 1 ) &~1 );
  455. }
  456. }
  457. return res;
  458. }
  459. PSDResFileInfo::ResFileInfoElement PSDResFileInfo::FindElement( ResFileInfo eType ) const
  460. {
  461. ResFileInfoElement res;
  462. memset( &res, 0, sizeof( res ) );
  463. unsigned char const *pvBuffer = m_res.m_pvData, * const pvBufferEnd = pvBuffer + m_res.m_numBytes;
  464. while ( pvBuffer < pvBufferEnd )
  465. {
  466. // 2 : = 0x1C02
  467. // 1 : type
  468. // 2 : length
  469. // bytes[ length ]
  470. unsigned short uResLabel = BigShort( *( unsigned short * )( pvBuffer ) );
  471. pvBuffer += 2;
  472. unsigned char uType = *pvBuffer;
  473. pvBuffer += 1;
  474. unsigned short uLength = BigShort( *( unsigned short * )( pvBuffer ) );
  475. pvBuffer += 2;
  476. if ( uType == eType && uResLabel == 0x1C02 )
  477. {
  478. res.m_eType = eType;
  479. res.m_numBytes = uLength;
  480. res.m_pvData = pvBuffer;
  481. break;
  482. }
  483. else
  484. {
  485. pvBuffer += uLength;
  486. }
  487. }
  488. return res;
  489. }