1
This commit is contained in:
213
common/jpegloader_common.cpp
Normal file
213
common/jpegloader_common.cpp
Normal file
@ -0,0 +1,213 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
#include "jpegloader.h"
|
||||
#include "tier0/dbg.h"
|
||||
#include "tier1/utlvector.h"
|
||||
#include "tier0/vprof.h"
|
||||
#include "jpeglib/jpeglib.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Takes a RGBA image buffer and resizes it using linear interpolation.
|
||||
//
|
||||
// Params: bufRGBA should contain the current image, nWidth and nHeight should describe
|
||||
// the current images dimensions. nNewWidth and nNewHeight should be the new target size,
|
||||
// one, but not both, of these may be -1 which will indicate to preserve aspect ratio
|
||||
// and size that dimension to match the aspect ratio adjustment applied to the other
|
||||
// dimension which must then be specified explicitly. nNewWidth and nNewHeight may
|
||||
// be modified by the function and will specify the final width/height after the
|
||||
// function returns succesfully. If both nNewWidth and nNewHeight are specified
|
||||
// the content will be scaled without changing the aspect ratio and black letterboxing
|
||||
// will be added if appropriate
|
||||
//-----------------------------------------------------------------------------
|
||||
bool BResizeImageInternal( CUtlBuffer &bufImage, int nWidth, int nHeight, int &nNewWidth, int &nNewHeight, bool bIsRGBA = true )
|
||||
{
|
||||
VPROF_BUDGET( "BResizeImageRGBA", VPROF_BUDGETGROUP_OTHER_VGUI );
|
||||
CUtlBuffer bufImageOut;
|
||||
|
||||
if ( nWidth == 0 || nHeight == 0 )
|
||||
return false;
|
||||
|
||||
// Must specify at least one, then we'll compute the other to preserve aspect ratio if it's set to -1
|
||||
if ( nNewWidth == - 1 && nNewHeight == -1 )
|
||||
return false;
|
||||
|
||||
if ( nNewHeight == -1 )
|
||||
{
|
||||
float flAspect = (float)nNewWidth/(float)nWidth;
|
||||
nNewHeight = (int)(flAspect*nHeight);
|
||||
}
|
||||
else if ( nNewWidth == -1 )
|
||||
{
|
||||
float flAspect = (float)nNewHeight/(float)nHeight;
|
||||
nNewWidth = (int)(flAspect*nWidth);
|
||||
}
|
||||
|
||||
if ( nNewWidth == 0 || nNewHeight == 0 )
|
||||
return false;
|
||||
|
||||
int nNewContentHeight = nNewHeight;
|
||||
int nNewContentWidth = nNewWidth;
|
||||
|
||||
// Calculate the width/height of the actual content
|
||||
if ( nWidth/(float)nHeight > nNewContentWidth/(float)nNewContentHeight )
|
||||
nNewContentHeight = ( nNewContentWidth * nHeight )/nWidth;
|
||||
else
|
||||
nNewContentWidth = ( nNewContentHeight * nWidth )/nHeight;
|
||||
|
||||
int bytesPerPixel = bIsRGBA ? 4 : 3;
|
||||
|
||||
bufImageOut.EnsureCapacity( nNewWidth*nNewHeight*bytesPerPixel );
|
||||
bufImageOut.SeekPut( CUtlBuffer::SEEK_HEAD, nNewWidth*nNewHeight*bytesPerPixel );
|
||||
|
||||
|
||||
// Letterboxing
|
||||
int nPaddingTop = (nNewHeight - nNewContentHeight)/2;
|
||||
int nPaddingBottom = nNewHeight - nNewContentHeight - nPaddingTop;
|
||||
int nPaddingLeft = (nNewWidth - nNewContentWidth)/2;
|
||||
int nPaddingRight = nNewWidth - nNewContentWidth - nPaddingLeft;
|
||||
|
||||
Assert( nPaddingTop + nPaddingBottom + nNewContentHeight == nNewHeight );
|
||||
Assert( nPaddingLeft + nPaddingRight + nNewContentWidth == nNewWidth );
|
||||
|
||||
if ( nPaddingLeft > 0 ||
|
||||
nPaddingRight > 0 ||
|
||||
nPaddingTop > 0 ||
|
||||
nPaddingBottom > 0 )
|
||||
{
|
||||
Q_memset( bufImageOut.Base(), 0, nNewWidth*nNewHeight*bytesPerPixel );
|
||||
}
|
||||
|
||||
byte *pBits = (byte*)bufImageOut.Base();
|
||||
|
||||
int nOriginalStride = nWidth;
|
||||
int nTargetStride = nNewWidth;
|
||||
|
||||
float flXRatio = (float)(nWidth-1)/(float)nNewContentWidth;
|
||||
float flYRatio = (float)(nHeight-1)/(float)nNewContentHeight;
|
||||
|
||||
byte *pSrcBits = (byte*)bufImage.Base();
|
||||
for( int yNew=0; yNew<nNewContentHeight; ++yNew )
|
||||
{
|
||||
int y = (int)(flYRatio * yNew);
|
||||
float yDiff = (flYRatio * yNew) - y;
|
||||
|
||||
for ( int xNew=0; xNew<nNewContentWidth; ++xNew )
|
||||
{
|
||||
int x = (int)(flXRatio * xNew);
|
||||
float xDiff = (flXRatio * xNew) - x;
|
||||
|
||||
int aOffset = (x+(y*nOriginalStride))*bytesPerPixel;
|
||||
int bOffset = aOffset+bytesPerPixel;
|
||||
int cOffset = aOffset + (nOriginalStride*bytesPerPixel);
|
||||
int dOffset = cOffset+bytesPerPixel;
|
||||
|
||||
byte red = (byte)(
|
||||
pSrcBits[aOffset]*(1-xDiff)*(1-yDiff)
|
||||
+pSrcBits[bOffset]*(xDiff)*(1-yDiff)
|
||||
+pSrcBits[cOffset]*(yDiff)*(1-xDiff)
|
||||
+pSrcBits[dOffset]*(xDiff)*(yDiff)
|
||||
);
|
||||
|
||||
byte green = (byte)(
|
||||
pSrcBits[aOffset+1]*(1-xDiff)*(1-yDiff)
|
||||
+pSrcBits[bOffset+1]*(xDiff)*(1-yDiff)
|
||||
+pSrcBits[cOffset+1]*(yDiff)*(1-xDiff)
|
||||
+pSrcBits[dOffset+1]*(xDiff)*(yDiff)
|
||||
);
|
||||
|
||||
byte blue = (byte)(
|
||||
pSrcBits[aOffset+2]*(1-xDiff)*(1-yDiff)
|
||||
+pSrcBits[bOffset+2]*(xDiff)*(1-yDiff)
|
||||
+pSrcBits[cOffset+2]*(yDiff)*(1-xDiff)
|
||||
+pSrcBits[dOffset+2]*(xDiff)*(yDiff)
|
||||
);
|
||||
|
||||
byte alpha = 0;
|
||||
if ( bytesPerPixel == 4 )
|
||||
{
|
||||
alpha = (byte)(
|
||||
pSrcBits[aOffset+3]*(1-xDiff)*(1-yDiff)
|
||||
+pSrcBits[bOffset+3]*(xDiff)*(1-yDiff)
|
||||
+pSrcBits[cOffset+3]*(yDiff)*(1-xDiff)
|
||||
+pSrcBits[dOffset+3]*(xDiff)*(yDiff)
|
||||
);
|
||||
}
|
||||
|
||||
int targetOffset = (nPaddingLeft+xNew+((nPaddingTop+yNew)*nTargetStride))*bytesPerPixel;
|
||||
|
||||
pBits[targetOffset] = red;
|
||||
pBits[targetOffset+1] = green;
|
||||
pBits[targetOffset+2] = blue;
|
||||
if ( bytesPerPixel == 4 )
|
||||
pBits[targetOffset+3] = alpha;
|
||||
}
|
||||
}
|
||||
bufImage.Swap( bufImageOut );
|
||||
return true;
|
||||
}
|
||||
|
||||
// Resize an RGB image using linear interpolation
|
||||
bool BResizeImageRGB( CUtlBuffer &bufRGB, int nWidth, int nHeight, int &nNewWidth, int &nNewHeight )
|
||||
{
|
||||
return BResizeImageInternal( bufRGB, nWidth, nHeight, nNewWidth, nNewHeight, false );
|
||||
}
|
||||
|
||||
// Resize an RGBA image using linear interpolation
|
||||
bool BResizeImageRGBA( CUtlBuffer &bufRGB, int nWidth, int nHeight, int &nNewWidth, int &nNewHeight )
|
||||
{
|
||||
return BResizeImageInternal( bufRGB, nWidth, nHeight, nNewWidth, nNewHeight, true );
|
||||
}
|
||||
|
||||
// Convert an RGB image to RGBA with 100% opacity
|
||||
bool BConvertRGBToRGBA( CUtlBuffer &bufRGB, int nWidth, int nHeight )
|
||||
{
|
||||
CUtlBuffer bufRGBA;
|
||||
bufRGBA.EnsureCapacity( nWidth*nHeight*4 );
|
||||
byte *pBits = (byte*)bufRGB.Base();
|
||||
byte *pBitsOut = (byte*)bufRGBA.Base();
|
||||
|
||||
for( int y=0; y<nHeight; ++y )
|
||||
{
|
||||
for( int x=0; x<nWidth; ++x )
|
||||
{
|
||||
*pBitsOut = *pBits;
|
||||
*(pBitsOut+1) = *(pBits+1);
|
||||
*(pBitsOut+2) = *(pBits+2);
|
||||
*(pBitsOut+3) = 255;
|
||||
|
||||
pBitsOut += 4;
|
||||
pBits += 3;
|
||||
}
|
||||
}
|
||||
bufRGB.Swap( bufRGBA );
|
||||
return true;
|
||||
}
|
||||
|
||||
// Convert an RGBA image to RGB using opacity against a given solid background
|
||||
bool BConvertRGBAToRGB( CUtlBuffer &bufRGBA, int nWidth, int nHeight, Color colorBG )
|
||||
{
|
||||
CUtlBuffer bufRGB;
|
||||
bufRGB.EnsureCapacity( nWidth*nHeight*3 );
|
||||
byte *pBits = (byte*)bufRGBA.Base();
|
||||
byte *pBitsOut = (byte*)bufRGB.Base();
|
||||
|
||||
for( int y=0; y<nHeight; ++y )
|
||||
{
|
||||
for( int x=0; x<nWidth; ++x )
|
||||
{
|
||||
float fOpacity = *(pBits+3) / 255.0;
|
||||
*pBitsOut = *pBits * fOpacity + (1.0 - fOpacity) * colorBG.r();
|
||||
*(pBitsOut+1) = *(pBits+1) * fOpacity + (1.0 - fOpacity) * colorBG.g();
|
||||
*(pBitsOut+2) = *(pBits+2) * fOpacity + (1.0 - fOpacity) * colorBG.b();
|
||||
|
||||
pBitsOut += 3;
|
||||
pBits += 4;
|
||||
}
|
||||
}
|
||||
bufRGB.Swap( bufRGBA );
|
||||
return true;
|
||||
}
|
Reference in New Issue
Block a user