/* * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or * its licensors. * * For complete copyright and license terms please see the LICENSE at the root of this * distribution (the "License"). All use of this software is governed by the License, * or, if provided, by the license below or the license accompanying this file. Do not * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * */ // Original file Copyright Crytek GMBH or its affiliates, used under license. #include "StdAfx.h" #include "GdiUtil.h" #include "Image.h" #include "StringUtils.h" #include #include #include bool ComputeThumbsLayoutInfo(float aContainerWidth, float aThumbWidth, float aMargin, UINT aThumbCount, UINT& rThumbsPerRow, float& rNewMargin) { rThumbsPerRow = 0; rNewMargin = 0; if (aThumbWidth <= 0 || aMargin <= 0 || (aThumbWidth + aMargin * 2) <= 0) { return false; } if (aContainerWidth <= 0) { return true; } rThumbsPerRow = (int) aContainerWidth / (aThumbWidth + aMargin * 2); if ((aThumbWidth + aMargin * 2) * aThumbCount < aContainerWidth) { rNewMargin = aMargin; } else { if (rThumbsPerRow > 0) { rNewMargin = (aContainerWidth - rThumbsPerRow * aThumbWidth); if (rNewMargin > 0) { rNewMargin = (float)rNewMargin / rThumbsPerRow / 2.0f; } } } return true; } QColor ScaleColor(const QColor& c, float aScale) { QColor aColor = c; if (!aColor.isValid()) { // help out scaling, by starting at very low black aColor = QColor(1, 1, 1); } int r = aColor.red(); int g = aColor.green(); int b = aColor.blue(); r *= aScale; g *= aScale; b *= aScale; return QColor(CLAMP(r, 0, 255), CLAMP(g, 0, 255), CLAMP(b, 0, 255)); } CAlphaBitmap::CAlphaBitmap() { m_width = m_height = 0; } CAlphaBitmap::~CAlphaBitmap() { Free(); } bool CAlphaBitmap::Create(void* pData, UINT aWidth, UINT aHeight, bool bVerticalFlip, bool bPremultiplyAlpha) { if (!aWidth || !aHeight) { return false; } m_bmp = QImage(aWidth, aHeight, QImage::Format_RGBA8888); if (m_bmp.isNull()) { return false; } std::vector vBuffer; if (pData) { // copy over the raw 32bpp data bVerticalFlip = !bVerticalFlip; // in Qt, the flip is not required. Still, keep the API behaving the same if (bVerticalFlip) { UINT nBufLen = aWidth * aHeight; vBuffer.resize(nBufLen); if (IsBadReadPtr(pData, nBufLen * 4)) { //TODO: remove after testing alot the browser, it doesnt happen anymore QMessageBox::critical(QApplication::activeWindow(), QString(), QObject::tr("Bad image data ptr!")); Free(); return false; } assert(!vBuffer.empty()); if (vBuffer.empty()) { Free(); return false; } UINT scanlineSize = aWidth * 4; for (UINT i = 0, iCount = aHeight; i < iCount; ++i) { // top scanline position UINT* pTopScanPos = (UINT*)&vBuffer[0] + i * aWidth; // bottom scanline position UINT* pBottomScanPos = (UINT*)pData + (aHeight - i - 1) * aWidth; // save a scanline from top memcpy(pTopScanPos, pBottomScanPos, scanlineSize); } pData = &vBuffer[0]; } // premultiply alpha, AlphaBlend GDI expects it if (bPremultiplyAlpha) { for (UINT y = 0; y < aHeight; ++y) { BYTE* pPixel = (BYTE*) pData + aWidth * 4 * y; for (UINT x = 0; x < aWidth; ++x) { pPixel[0] = ((int)pPixel[0] * pPixel[3] + 127) >> 8; pPixel[1] = ((int)pPixel[1] * pPixel[3] + 127) >> 8; pPixel[2] = ((int)pPixel[2] * pPixel[3] + 127) >> 8; pPixel += 4; } } } memcpy(m_bmp.bits(), pData, aWidth * aHeight * 4); if (m_bmp.isNull()) { return false; } } else { m_bmp.fill(Qt::transparent); } // we dont need this screen DC anymore m_width = aWidth; m_height = aHeight; return true; } QImage& CAlphaBitmap::GetBitmap() { return m_bmp; } void CAlphaBitmap::Free() { } UINT CAlphaBitmap::GetWidth() { return m_width; } UINT CAlphaBitmap::GetHeight() { return m_height; } void CheckerboardFillRect(QPainter* pGraphics, const QRect& rRect, int checkDiameter, const QColor& aColor1, const QColor& aColor2) { pGraphics->save(); pGraphics->setClipRect(rRect); // Create a checkerboard background for easier readability pGraphics->fillRect(rRect, aColor1); QBrush lightBrush(aColor2); // QRect bottom/right methods are short one unit for legacy reasons. Compute bottomr/right of the rectange ourselves to get the full size. const int rectRight = rRect.x() + rRect.width(); const int rectBottom = rRect.y() + rRect.height(); for (int i = rRect.left(); i < rectRight; i += checkDiameter) { for (int j = rRect.top(); j < rectBottom; j += checkDiameter) { if ((i / checkDiameter) % 2 ^ (j / checkDiameter) % 2) { pGraphics->fillRect(QRect(i, j, checkDiameter, checkDiameter), lightBrush); } } } pGraphics->restore(); }