Team Fortress 2 Source Code as on 22/4/2020
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.

212 lines
6.6 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================
  6. #include "jpegloader.h"
  7. #include "tier0/dbg.h"
  8. #include "tier1/utlvector.h"
  9. #include "tier0/vprof.h"
  10. #include "jpeglib/jpeglib.h"
  11. //-----------------------------------------------------------------------------
  12. // Purpose: Takes a RGBA image buffer and resizes it using linear interpolation.
  13. //
  14. // Params: bufRGBA should contain the current image, nWidth and nHeight should describe
  15. // the current images dimensions. nNewWidth and nNewHeight should be the new target size,
  16. // one, but not both, of these may be -1 which will indicate to preserve aspect ratio
  17. // and size that dimension to match the aspect ratio adjustment applied to the other
  18. // dimension which must then be specified explicitly. nNewWidth and nNewHeight may
  19. // be modified by the function and will specify the final width/height after the
  20. // function returns succesfully. If both nNewWidth and nNewHeight are specified
  21. // the content will be scaled without changing the aspect ratio and black letterboxing
  22. // will be added if appropriate
  23. //-----------------------------------------------------------------------------
  24. bool BResizeImageInternal( CUtlBuffer &bufImage, int nWidth, int nHeight, int &nNewWidth, int &nNewHeight, bool bIsRGBA = true )
  25. {
  26. VPROF_BUDGET( "BResizeImageRGBA", VPROF_BUDGETGROUP_OTHER_VGUI );
  27. CUtlBuffer bufImageOut;
  28. if ( nWidth == 0 || nHeight == 0 )
  29. return false;
  30. // Must specify at least one, then we'll compute the other to preserve aspect ratio if it's set to -1
  31. if ( nNewWidth == - 1 && nNewHeight == -1 )
  32. return false;
  33. if ( nNewHeight == -1 )
  34. {
  35. float flAspect = (float)nNewWidth/(float)nWidth;
  36. nNewHeight = (int)(flAspect*nHeight);
  37. }
  38. else if ( nNewWidth == -1 )
  39. {
  40. float flAspect = (float)nNewHeight/(float)nHeight;
  41. nNewWidth = (int)(flAspect*nWidth);
  42. }
  43. if ( nNewWidth == 0 || nNewHeight == 0 )
  44. return false;
  45. int nNewContentHeight = nNewHeight;
  46. int nNewContentWidth = nNewWidth;
  47. // Calculate the width/height of the actual content
  48. if ( nWidth/(float)nHeight > nNewContentWidth/(float)nNewContentHeight )
  49. nNewContentHeight = ( nNewContentWidth * nHeight )/nWidth;
  50. else
  51. nNewContentWidth = ( nNewContentHeight * nWidth )/nHeight;
  52. int bytesPerPixel = bIsRGBA ? 4 : 3;
  53. bufImageOut.EnsureCapacity( nNewWidth*nNewHeight*bytesPerPixel );
  54. bufImageOut.SeekPut( CUtlBuffer::SEEK_HEAD, nNewWidth*nNewHeight*bytesPerPixel );
  55. // Letterboxing
  56. int nPaddingTop = (nNewHeight - nNewContentHeight)/2;
  57. int nPaddingBottom = nNewHeight - nNewContentHeight - nPaddingTop;
  58. int nPaddingLeft = (nNewWidth - nNewContentWidth)/2;
  59. int nPaddingRight = nNewWidth - nNewContentWidth - nPaddingLeft;
  60. Assert( nPaddingTop + nPaddingBottom + nNewContentHeight == nNewHeight );
  61. Assert( nPaddingLeft + nPaddingRight + nNewContentWidth == nNewWidth );
  62. if ( nPaddingLeft > 0 ||
  63. nPaddingRight > 0 ||
  64. nPaddingTop > 0 ||
  65. nPaddingBottom > 0 )
  66. {
  67. Q_memset( bufImageOut.Base(), 0, nNewWidth*nNewHeight*bytesPerPixel );
  68. }
  69. byte *pBits = (byte*)bufImageOut.Base();
  70. int nOriginalStride = nWidth;
  71. int nTargetStride = nNewWidth;
  72. float flXRatio = (float)(nWidth-1)/(float)nNewContentWidth;
  73. float flYRatio = (float)(nHeight-1)/(float)nNewContentHeight;
  74. byte *pSrcBits = (byte*)bufImage.Base();
  75. for( int yNew=0; yNew<nNewContentHeight; ++yNew )
  76. {
  77. int y = (int)(flYRatio * yNew);
  78. float yDiff = (flYRatio * yNew) - y;
  79. for ( int xNew=0; xNew<nNewContentWidth; ++xNew )
  80. {
  81. int x = (int)(flXRatio * xNew);
  82. float xDiff = (flXRatio * xNew) - x;
  83. int aOffset = (x+(y*nOriginalStride))*bytesPerPixel;
  84. int bOffset = aOffset+bytesPerPixel;
  85. int cOffset = aOffset + (nOriginalStride*bytesPerPixel);
  86. int dOffset = cOffset+bytesPerPixel;
  87. byte red = (byte)(
  88. pSrcBits[aOffset]*(1-xDiff)*(1-yDiff)
  89. +pSrcBits[bOffset]*(xDiff)*(1-yDiff)
  90. +pSrcBits[cOffset]*(yDiff)*(1-xDiff)
  91. +pSrcBits[dOffset]*(xDiff)*(yDiff)
  92. );
  93. byte green = (byte)(
  94. pSrcBits[aOffset+1]*(1-xDiff)*(1-yDiff)
  95. +pSrcBits[bOffset+1]*(xDiff)*(1-yDiff)
  96. +pSrcBits[cOffset+1]*(yDiff)*(1-xDiff)
  97. +pSrcBits[dOffset+1]*(xDiff)*(yDiff)
  98. );
  99. byte blue = (byte)(
  100. pSrcBits[aOffset+2]*(1-xDiff)*(1-yDiff)
  101. +pSrcBits[bOffset+2]*(xDiff)*(1-yDiff)
  102. +pSrcBits[cOffset+2]*(yDiff)*(1-xDiff)
  103. +pSrcBits[dOffset+2]*(xDiff)*(yDiff)
  104. );
  105. byte alpha = 0;
  106. if ( bytesPerPixel == 4 )
  107. {
  108. alpha = (byte)(
  109. pSrcBits[aOffset+3]*(1-xDiff)*(1-yDiff)
  110. +pSrcBits[bOffset+3]*(xDiff)*(1-yDiff)
  111. +pSrcBits[cOffset+3]*(yDiff)*(1-xDiff)
  112. +pSrcBits[dOffset+3]*(xDiff)*(yDiff)
  113. );
  114. }
  115. int targetOffset = (nPaddingLeft+xNew+((nPaddingTop+yNew)*nTargetStride))*bytesPerPixel;
  116. pBits[targetOffset] = red;
  117. pBits[targetOffset+1] = green;
  118. pBits[targetOffset+2] = blue;
  119. if ( bytesPerPixel == 4 )
  120. pBits[targetOffset+3] = alpha;
  121. }
  122. }
  123. bufImage.Swap( bufImageOut );
  124. return true;
  125. }
  126. // Resize an RGB image using linear interpolation
  127. bool BResizeImageRGB( CUtlBuffer &bufRGB, int nWidth, int nHeight, int &nNewWidth, int &nNewHeight )
  128. {
  129. return BResizeImageInternal( bufRGB, nWidth, nHeight, nNewWidth, nNewHeight, false );
  130. }
  131. // Resize an RGBA image using linear interpolation
  132. bool BResizeImageRGBA( CUtlBuffer &bufRGB, int nWidth, int nHeight, int &nNewWidth, int &nNewHeight )
  133. {
  134. return BResizeImageInternal( bufRGB, nWidth, nHeight, nNewWidth, nNewHeight, true );
  135. }
  136. // Convert an RGB image to RGBA with 100% opacity
  137. bool BConvertRGBToRGBA( CUtlBuffer &bufRGB, int nWidth, int nHeight )
  138. {
  139. CUtlBuffer bufRGBA;
  140. bufRGBA.EnsureCapacity( nWidth*nHeight*4 );
  141. byte *pBits = (byte*)bufRGB.Base();
  142. byte *pBitsOut = (byte*)bufRGBA.Base();
  143. for( int y=0; y<nHeight; ++y )
  144. {
  145. for( int x=0; x<nWidth; ++x )
  146. {
  147. *pBitsOut = *pBits;
  148. *(pBitsOut+1) = *(pBits+1);
  149. *(pBitsOut+2) = *(pBits+2);
  150. *(pBitsOut+3) = 255;
  151. pBitsOut += 4;
  152. pBits += 3;
  153. }
  154. }
  155. bufRGB.Swap( bufRGBA );
  156. return true;
  157. }
  158. // Convert an RGBA image to RGB using opacity against a given solid background
  159. bool BConvertRGBAToRGB( CUtlBuffer &bufRGBA, int nWidth, int nHeight, Color colorBG )
  160. {
  161. CUtlBuffer bufRGB;
  162. bufRGB.EnsureCapacity( nWidth*nHeight*3 );
  163. byte *pBits = (byte*)bufRGBA.Base();
  164. byte *pBitsOut = (byte*)bufRGB.Base();
  165. for( int y=0; y<nHeight; ++y )
  166. {
  167. for( int x=0; x<nWidth; ++x )
  168. {
  169. float fOpacity = *(pBits+3) / 255.0;
  170. *pBitsOut = *pBits * fOpacity + (1.0 - fOpacity) * colorBG.r();
  171. *(pBitsOut+1) = *(pBits+1) * fOpacity + (1.0 - fOpacity) * colorBG.g();
  172. *(pBitsOut+2) = *(pBits+2) * fOpacity + (1.0 - fOpacity) * colorBG.b();
  173. pBitsOut += 3;
  174. pBits += 4;
  175. }
  176. }
  177. bufRGB.Swap( bufRGBA );
  178. return true;
  179. }