DocumentServer/ActiveX/Common/ImageStudioUtils.h
nikolay ivanov a8be6b9e72 init repo
2014-07-05 18:22:49 +00:00

670 lines
16 KiB
C++

/*
* (c) Copyright Ascensio System SIA 2010-2014
*
* This program is a free software product. You can redistribute it and/or
* modify it under the terms of the GNU Affero General Public License (AGPL)
* version 3 as published by the Free Software Foundation. In accordance with
* Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
* that Ascensio System SIA expressly excludes the warranty of non-infringement
* of any third-party rights.
*
* This program is distributed WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For
* details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
*
* You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
* EU, LV-1021.
*
* The interactive user interfaces in modified source and object code versions
* of the Program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU AGPL version 3.
*
* Pursuant to Section 7(b) of the License you must retain the original Product
* logo when distributing the program. Pursuant to Section 7(e) we decline to
* grant you any rights under trademark law for use of our trademarks.
*
* All the Product's GUI elements, including illustrations and icon sets, as
* well as technical writing content are licensed under the terms of the
* Creative Commons Attribution-ShareAlike 4.0 International. See the License
* terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
*
*/
#pragma once
#include <mediaformatdefine.h>
#include <memoryutils.h>
#include <atldefine.h>
#include <gdiplusex.h>
#include "MediaDataDefine.h"
namespace ImageStudioUtils
{
static int CompareStrings(const WCHAR* str1, const WCHAR* str2)
{
CString cstr1; cstr1 = str1;
CString cstr2; cstr2 = str2;
if (cstr1 == cstr2)
return 0;
return 1;
}
static DWORD WidthBytes(DWORD bits)
{
return (bits + 31) / 32 * 4;
}
static int GetBit(BYTE value, int pos, BOOL swap = FALSE)
{
if (swap)
pos = 7 - pos;
int mask = (1 << pos);
if (value & mask)
return 1;
return 0;
}
static int GetBitShort(short value, int pos, BOOL swap = FALSE)
{
if (swap)
pos = 15 - pos;
int mask = (1 << pos);
if (value & mask)
return 1;
return 0;
}
static void SetBit(int* value, int pos, BOOL newVal)
{
int mask = (1 << pos);
int val = *value;
if (newVal)
val |= mask;
else
val &= ~mask;
*value = val;
}
static void SetBit(BYTE* value, int pos, BOOL newVal)
{
int mask = (1 << pos);
BYTE val = *value;
if (newVal)
val |= mask;
else
val &= ~mask;
*value = val;
}
static void SetBit(short* value, int pos, BOOL newVal)
{
int mask = (1 << pos);
short val = *value;
if (newVal)
val |= mask;
else
val &= ~mask;
*value = val;
}
static void SwapBits565(BYTE* pData)
{
unsigned short* pShorts = (unsigned short*)pData;
unsigned short nShortSrc = *pShorts;
unsigned short nShortDst = 0;
nShortDst |= (nShortSrc & (1 << 0)) ? (1 << 4) : 0;
nShortDst |= (nShortSrc & (1 << 1)) ? (1 << 3) : 0;
nShortDst |= (nShortSrc & (1 << 2)) ? (1 << 2) : 0;
nShortDst |= (nShortSrc & (1 << 3)) ? (1 << 1) : 0;
nShortDst |= (nShortSrc & (1 << 4)) ? (1 << 0) : 0;
nShortDst |= (nShortSrc & (1 << 5)) ? (1 << 10) : 0;
nShortDst |= (nShortSrc & (1 << 6)) ? (1 << 9) : 0;
nShortDst |= (nShortSrc & (1 << 7)) ? (1 << 8) : 0;
nShortDst |= (nShortSrc & (1 << 8)) ? (1 << 7) : 0;
nShortDst |= (nShortSrc & (1 << 9)) ? (1 << 6) : 0;
nShortDst |= (nShortSrc & (1 << 10)) ? (1 << 5) : 0;
nShortDst |= (nShortSrc & (1 << 11)) ? (1 << 15) : 0;
nShortDst |= (nShortSrc & (1 << 12)) ? (1 << 14) : 0;
nShortDst |= (nShortSrc & (1 << 13)) ? (1 << 13) : 0;
nShortDst |= (nShortSrc & (1 << 14)) ? (1 << 12) : 0;
nShortDst |= (nShortSrc & (1 << 15)) ? (1 << 11) : 0;
*pShorts = nShortDst;
}
static void SwapBits8(BYTE* pData)
{
unsigned char* pChars = (unsigned char*)pData;
unsigned char nCharSrc = *pChars;
unsigned char nCharDst = 0;
nCharDst |= (nCharSrc & (1 << 0)) ? (1 << 7) : 0;
nCharDst |= (nCharSrc & (1 << 1)) ? (1 << 6) : 0;
nCharDst |= (nCharSrc & (1 << 2)) ? (1 << 5) : 0;
nCharDst |= (nCharSrc & (1 << 3)) ? (1 << 4) : 0;
nCharDst |= (nCharSrc & (1 << 4)) ? (1 << 3) : 0;
nCharDst |= (nCharSrc & (1 << 5)) ? (1 << 2) : 0;
nCharDst |= (nCharSrc & (1 << 6)) ? (1 << 1) : 0;
nCharDst |= (nCharSrc & (1 << 7)) ? (1 << 0) : 0;
*pChars = nCharDst;
}
static BYTE GetBrightness(BYTE Red, BYTE Green, BYTE Blue)
{
if (Red > Green)
{
if (Red > Blue)
return Red;
return Blue;
}
if (Green > Blue)
return Green;
return Blue;
}
static BYTE GetLightness(BYTE Red, BYTE Green, BYTE Blue)
{
BYTE MinValue, MaxValue;
if (Red > Green)
{
MaxValue = Blue;
if (Red > Blue)
MaxValue = Red;
MinValue = Blue;
if (Green < Blue)
MinValue = Green;
}
else
{
MaxValue = Blue;
if (Green > Blue)
MaxValue = Green;
MinValue = Blue;
if (Red < Blue)
MinValue = Red;
}
return (MaxValue + MinValue)/2;
}
static BYTE GetIntensity(BYTE Red, BYTE Green, BYTE Blue)
{
return (BYTE)(0.3 * Red + 0.59 * Green + 0.11 * Blue);
}
static BOOL ByteArrayToMediaData(BYTE* pArray, int nWidth, int nHeight, IUnknown** pInterface, BOOL bFlipVertical = TRUE)
{
if (!pInterface || nWidth < 1 || nHeight < 1)
return FALSE;
*pInterface = NULL;
MediaCore::IAVSUncompressedVideoFrame* pMediaData = NULL;
CoCreateInstance(MediaCore::CLSID_CAVSUncompressedVideoFrame, NULL, CLSCTX_ALL, MediaCore::IID_IAVSUncompressedVideoFrame, (void**)(&pMediaData));
if (NULL == pMediaData)
return FALSE;
if (bFlipVertical)
pMediaData->put_ColorSpace(CSP_BGRA | CSP_VFLIP);
else
pMediaData->put_ColorSpace(CSP_BGRA);
pMediaData->put_Width(nWidth);
pMediaData->put_Height(nHeight);
pMediaData->put_AspectRatioX(nWidth);
pMediaData->put_AspectRatioY(nHeight);
pMediaData->put_Interlaced(VARIANT_FALSE);
pMediaData->put_Stride(0, 4*nWidth);
pMediaData->AllocateBuffer(4*nWidth*nHeight);
BYTE* pBufferPtr = 0;
long nCreatedBufferSize = 0;
pMediaData->get_Buffer(&pBufferPtr);
pMediaData->get_BufferSize(&nCreatedBufferSize);
pMediaData->put_Plane(0, pBufferPtr);
if (!pBufferPtr || nCreatedBufferSize != 4*nWidth*nHeight)
{
RELEASEINTERFACE(pMediaData);
return FALSE;
}
if (pArray != NULL)
memcpy(pBufferPtr, pArray, nCreatedBufferSize);
*pInterface = pMediaData;
return TRUE;
}
static BOOL SafeArrayToMediaData(SAFEARRAY*& pArray, IUnknown** pInterface, BOOL bDeleteArray = TRUE)
{
if (!pArray || pArray->cDims != 3)
return FALSE;
int nWidth = pArray->rgsabound[1].cElements;
int nHeight = pArray->rgsabound[0].cElements;
BOOL bSuccess = ByteArrayToMediaData((BYTE*)pArray->pvData, nWidth, nHeight, pInterface);
if (!bSuccess)
return FALSE;
if (bDeleteArray)
{
SafeArrayDestroy(pArray);
pArray = 0;
}
return TRUE;
}
static BOOL GdiPlusBitmapToMediaData(Gdiplus::Bitmap* pBitmap, IUnknown** pInterface, BOOL bFlipVertical = TRUE)
{
if (!pBitmap)
return FALSE;
int nWidth = pBitmap->GetWidth();
int nHeight = pBitmap->GetHeight();
Gdiplus::Rect oRect(0, 0, nWidth, nHeight);
Gdiplus::BitmapData oBitmapData;
if (pBitmap->LockBits(&oRect, ImageLockModeRead, PixelFormat32bppARGB, &oBitmapData) != Ok)
return FALSE;
BOOL bSuccess = ByteArrayToMediaData((BYTE*)oBitmapData.Scan0, nWidth, nHeight, pInterface, bFlipVertical);
pBitmap->UnlockBits(&oBitmapData);
return bSuccess;
}
static BOOL GdiPlusImageToMediaData(GdiPlusEx::CGdiPlusImage* pImage, IUnknown** pInterface, BOOL bFlipVertical = TRUE)
{
if (!pImage || !pImage->IsValid())
return FALSE;
Gdiplus::Bitmap* pBitmap = (Bitmap*)(*pImage);
return GdiPlusBitmapToMediaData(pBitmap, pInterface, bFlipVertical);
}
static BOOL GdiPlusImageToSafeArray(GdiPlusEx::CGdiPlusImage* pImage, SAFEARRAY** pArray)
{
if (!pImage || !pImage->IsValid())
return FALSE;
return pImage->SaveToSafeArray(*pArray);
}
static BOOL MediaDataToBGRAMediaData(IUnknown** pInterface, MediaCore::IAVSUncompressedVideoFrame*& pMediaData, BOOL bCreateDublicate = FALSE)
{
pMediaData = NULL;
if (NULL == pInterface || NULL == (*pInterface))
return FALSE;
MediaCore::IAVSUncompressedVideoFrame* pMediaDataIn = NULL;
(*pInterface)->QueryInterface(MediaCore::IID_IAVSUncompressedVideoFrame, (void**)(&pMediaDataIn));
if (NULL == pMediaDataIn)
return FALSE;
LONG lWidth = 0; pMediaDataIn->get_Width(&lWidth);
LONG lHeight = 0; pMediaDataIn->get_Height(&lHeight);
LONG lAspectX = 0; pMediaDataIn->get_AspectRatioX(&lAspectX);
LONG lAspectY = 0; pMediaDataIn->get_AspectRatioY(&lAspectY);
if (TRUE)
{
MediaFormat::IAVSVideoFormat* pMediaFormat = NULL;
CoCreateInstance(MediaFormat::CLSID_CAVSVideoFormat, NULL, CLSCTX_ALL, MediaFormat::IID_IAVSVideoFormat, (void**)(&pMediaFormat));
if (NULL == pMediaFormat)
{
pMediaDataIn->Release();
return FALSE;
}
MediaCore::IAVSVideoFrameTransform* pMediaTransform = NULL;
CoCreateInstance(MediaCore::CLSID_CAVSVideoFrameTransform, NULL, CLSCTX_ALL, MediaCore::IID_IAVSVideoFrameTransform, (void**)(&pMediaTransform));
if (NULL == pMediaTransform)
{
pMediaDataIn->Release();
pMediaFormat->Release();
return FALSE;
}
pMediaFormat->SetDefaultProperties();
pMediaFormat->put_Width(lWidth);
pMediaFormat->put_Height(lHeight);
pMediaFormat->put_AspectRatioX(lAspectX);
pMediaFormat->put_AspectRatioY(lAspectY);
pMediaFormat->put_ColorSpace(CSP_BGRA | CSP_VFLIP);
pMediaTransform->SetVideoFormat(pMediaFormat);
IUnknown *pTransformResult = NULL;
pMediaTransform->TransformFrame(pMediaDataIn, &pTransformResult);
if (NULL != pTransformResult)
{
if (((*pInterface)==pTransformResult)&&(bCreateDublicate))
{
MediaCore::IAVSMediaData *pData = NULL;
pTransformResult->QueryInterface(MediaCore::IID_IAVSMediaData, (void**)(&pData));
if (NULL!=pData)
{
MediaCore::IAVSMediaData *pmdOutFrame = NULL;
pData->CreateDuplicate(DUBLICATE_TYPE_COPY, &pmdOutFrame);
pData->Release();
if (NULL!=pmdOutFrame)
{
pmdOutFrame->QueryInterface(MediaCore::IID_IAVSUncompressedVideoFrame, (void**)(&pMediaData));
pmdOutFrame->Release();
}
}
}
else
{
pTransformResult->QueryInterface(MediaCore::IID_IAVSUncompressedVideoFrame, (void**)(&pMediaData));
}
pTransformResult->Release();
}
pMediaFormat->Release();
pMediaTransform->Release();
}
pMediaDataIn->Release();
return (NULL != pMediaData);
}
static BOOL MediaDataToByteArray(IUnknown** pInterface, MediaCore::IAVSUncompressedVideoFrame*& pMediaData, BYTE*& pArray, int& nWidth, int& nHeight)
{
if (!pInterface || !*pInterface)
return FALSE;
pMediaData = NULL;
if (!MediaDataToBGRAMediaData(pInterface, pMediaData))
return FALSE;
LONG lWidth = 0; pMediaData->get_Width(&lWidth);
LONG lHeight = 0; pMediaData->get_Height(&lHeight);
LONG lColorSpace = 0; pMediaData->get_ColorSpace(&lColorSpace);
LONG lStride = 0; pMediaData->get_Stride(0, &lStride);
LONG lBufferSize = 0; pMediaData->get_BufferSize(&lBufferSize);
BYTE* pSourceBuffer = 0; pMediaData->get_Buffer(&pSourceBuffer);
if (CSP_BGRA != (CSP_COLOR_MASK & lColorSpace) || 4*lWidth != lStride || lWidth < 1 || lHeight < 1 || lBufferSize != 4*lWidth*lHeight || !pSourceBuffer)
{
pMediaData->Release();
pMediaData = NULL;
return FALSE;
}
pArray = pSourceBuffer;
nWidth = lWidth;
nHeight = lHeight;
return TRUE;
}
static BOOL MediaDataToSafeArray(IUnknown** pInterface, SAFEARRAY*& pArray)
{
int nWidth = 0;
int nHeight = 0;
BYTE* pPixels = 0;
MediaCore::IAVSUncompressedVideoFrame* pMediaData = NULL;
if (!MediaDataToByteArray(pInterface, pMediaData, pPixels, nWidth, nHeight))
return FALSE;
SAFEARRAYBOUND saBounds[3];
saBounds[0].lLbound = saBounds[1].lLbound = saBounds[2].lLbound = 0;
saBounds[0].cElements = 4;
saBounds[1].cElements = nWidth;
saBounds[2].cElements = nHeight;
pArray = SafeArrayCreate(VT_UI1, 3, saBounds);
if (!pArray)
{
pMediaData->Release();
return FALSE;
}
memcpy(pArray->pvData, pPixels, 4*nWidth*nHeight);
pMediaData->Release();
return TRUE;
}
static BOOL MediaDataToGdiPlusImage(IUnknown** pInterface, GdiPlusEx::CGdiPlusImage* pImage)
{
if (!pImage)
return FALSE;
int nWidth = 0;
int nHeight = 0;
BYTE* pPixels = 0;
MediaCore::IAVSUncompressedVideoFrame* pMediaData = NULL;
if (!MediaDataToByteArray(pInterface, pMediaData, pPixels, nWidth, nHeight))
return FALSE;
pImage->Destroy();
if (!pImage->CreateFromByteArray(pPixels, nWidth, nHeight, TRUE))
return FALSE;
pMediaData->Release();
return TRUE;
}
static BYTE* ExtractImage(SAFEARRAY** pArray, int& nWidth, int& nHeight, int& nChannels)
{
if (!pArray || !(*pArray))
return 0;
nWidth = nHeight = 0;
VARTYPE type;
long lBoundC, uBoundC;
long lBoundW, uBoundW;
long lBoundH, uBoundH;
if (SafeArrayGetDim(*pArray) != 3)
return 0;
if (FAILED(SafeArrayGetVartype(*pArray, &type)) || type != VT_UI1 || SafeArrayGetElemsize(*pArray) != 1)
return 0;
if (FAILED(SafeArrayGetLBound(*pArray, 1, &lBoundC)) || FAILED(SafeArrayGetUBound(*pArray, 1, &uBoundC)) ||
FAILED(SafeArrayGetLBound(*pArray, 2, &lBoundW)) || FAILED(SafeArrayGetUBound(*pArray, 2, &uBoundW)) ||
FAILED(SafeArrayGetLBound(*pArray, 3, &lBoundH)) || FAILED(SafeArrayGetUBound(*pArray, 3, &uBoundH)))
return 0;
nChannels = 1 + uBoundC - lBoundC;
nWidth = 1 + uBoundW - lBoundW;
nHeight = 1 + uBoundH - lBoundH;
return (BYTE*)((*pArray)->pvData);
}
static BOOL ExtractFromArray(void** Image, int& width, int& height, BYTE*& pixels)
{
SAFEARRAY** Array = ((SAFEARRAY**)Image);
int channels = 0;
pixels = ImageStudioUtils::ExtractImage(Array, width, height, channels);
if (!pixels || channels != 4)
return FALSE;
return TRUE;
}
static void FillAlphaChannel(SAFEARRAY** pArray, int Value)
{
if (!pArray)
return;
if (!*pArray)
return;
int nWidth, nHeight, nChannels;
BYTE* pData = ExtractImage(pArray, nWidth, nHeight, nChannels);
if (!pData)
return;
int nSize = nChannels*nWidth*nHeight;
for (int nIndex = 0; nIndex < nSize; nIndex += nChannels)
pData[nIndex + nChannels - 1] = Value;
}
static COLORREF GetColorLight(COLORREF color, int levels = 16)
{
int nR = min(255, max(0, levels + GetRValue(color)));
int nG = min(255, max(0, levels + GetGValue(color)));
int nB = min(255, max(0, levels + GetBValue(color)));
return RGB(nR, nG, nB);
}
static COLORREF GetColorDark(COLORREF color, int levels = 16)
{
return GetColorLight(color, -levels);
}
static DWORD Align32(DWORD n)
{
return (((n * (DWORD)8) + 31) & ~31) >> 3;
}
static void DestroySafeArray(SAFEARRAY** pArray)
{
if (!pArray || !*pArray)
return;
try
{
long uBound = 0;
if (SUCCEEDED(SafeArrayGetUBound(*pArray, 0, &uBound)) && uBound > 0)
SafeArrayDestroy(*pArray);
if (SafeArrayGetElemsize(*pArray) > 0)
SafeArrayDestroy(*pArray);
}
catch(...)
{
}
}
static void GetEncoderClsid(const WCHAR* pFormat, CLSID* pClsid)
{
UINT nEncoders = 0;
UINT nSize = 0;
Gdiplus::ImageCodecInfo* pImageCodecInfo = 0;
Gdiplus::GetImageEncodersSize(&nEncoders, &nSize);
if (!nSize)
throw 0;
pImageCodecInfo = (Gdiplus::ImageCodecInfo*)(malloc(nSize));
if (!pImageCodecInfo)
throw 0;
Gdiplus::GetImageEncoders(nEncoders, nSize, pImageCodecInfo);
for (UINT nEncoder = 0; nEncoder < nEncoders; ++nEncoder)
{
if (CompareStrings(pImageCodecInfo[nEncoder].MimeType, pFormat) == 0)
{
*pClsid = pImageCodecInfo[nEncoder].Clsid;
free(pImageCodecInfo);
return;
}
}
free(pImageCodecInfo);
throw 0;
}
}