/////////////////////////////////////////////////////////////////////////////// // Copyright (C) 2002-2025, Open Design Alliance (the "Alliance"). // All rights reserved. // // This software and its documentation and related materials are owned by // the Alliance. The software may only be incorporated into application // programs owned by members of the Alliance, subject to a signed // Membership Agreement and Supplemental Software License Agreement with the // Alliance. The structure and organization of this software are the valuable // trade secrets of the Alliance and its suppliers. The software is also // protected by copyright law and international treaty provisions. Application // programs incorporating this software must include the following statement // with their copyright notices: // // This application incorporates Open Design Alliance software pursuant to a license // agreement with Open Design Alliance. // Open Design Alliance Copyright (C) 2002-2025 by Open Design Alliance. // All rights reserved. // // By use of this software, its documentation or related materials, you // acknowledge and accept the above terms. /////////////////////////////////////////////////////////////////////////////// #include "OdaCommon.h" #include "GsSrVectorizeDevice.h" #include "GsSrVectorizeView.h" #include "ExColorConverterCallback.h" #include "update/SrUpdateManager.h" OdGsSrVectorizerDevice::OdGsSrVectorizerDevice(bool isBitmap /*= false*/) : m_isBitmap(isBitmap) { m_updateManager = new OdSrUpdateManager(this); initMetrics(); } void OdGsSrVectorizerDevice::initMetrics() { m_width = width(); m_height = height(); m_scanLineLength = scanLineSize(); m_scanLinesArray.resize(m_scanLineLength * m_height); m_pScanLinesBuffer = m_scanLinesArray.asArrayPtr(); } bool OdGsSrVectorizerDevice::get_DrawTransparency() const { return m_bDrawTransparency; } void OdGsSrVectorizerDevice::put_DrawTransparency(bool drawTransparency) { m_bDrawTransparency = drawTransparency; } bool OdGsSrVectorizerDevice::get_EnableSoftwareHLR() const { return m_hlrEnabled; } void OdGsSrVectorizerDevice::put_EnableSoftwareHLR(bool enableSoftwareHLR) { m_hlrEnabled = enableSoftwareHLR; } #define SET_PIXEL_REVERSE(dst, value) \ { \ dst[0] = reinterpret_cast(&value)[2]; \ dst[1] = reinterpret_cast(&value)[1]; \ dst[2] = reinterpret_cast(&value)[0]; \ } #define SET_PIXEL_REVERSE(dst, value) \ { \ dst[0] = reinterpret_cast(&value)[2]; \ dst[1] = reinterpret_cast(&value)[1]; \ dst[2] = reinterpret_cast(&value)[0]; \ } #define OD_OPAQUE(x) ((x) | 0xFF000000) void OdGsSrVectorizerDevice::fillBackgroundRect(const OdGsDCRect& rect) { ODCOLORREF bgColor = getBackgroundColor(); { OdColorConverterCallback* pColorConverter = getColorConverter(); if (pColorConverter && pColorConverter->convertBackgroundColors()) bgColor = pColorConverter->convert(bgColor); } // Ensure coordinates are within image boundaries OdInt32 startY = odmax(0, rect.m_min.y - 1); OdInt32 startX = odmax(0, rect.m_min.x - 1); OdInt32 endY = odmin(m_height - 1, rect.m_max.y - 1); OdInt32 endX = odmin(m_width - 1, rect.m_max.x - 1); // Additional boundary check if (startX >= (OdInt32)m_width || endX >= (OdInt32)m_width) return; // Check if we have a valid rectangle after clipping if (startX <= endX && startY <= endY) { for (OdInt32 i = startY; i <= endY; i++) { OdInt32 y = m_height - 1 - i; for (OdInt32 j = startX; j <= endX; j++) SET_PIXEL_REVERSE(getPixPtr(j, y), bgColor); } } } void OdGsSrVectorizerDevice::invertYRect(OdGsDCRect& dcRect) const { dcRect.m_max.y = m_height - 1 - dcRect.m_max.y; dcRect.m_min.y = m_height - 1 - dcRect.m_min.y; if (dcRect.m_min.x > dcRect.m_max.x) std::swap(dcRect.m_min.x, dcRect.m_max.x); if (dcRect.m_min.y > dcRect.m_max.y) std::swap(dcRect.m_min.y, dcRect.m_max.y); if (dcRect.m_min.x < 0) dcRect.m_min.x = 0; if (dcRect.m_min.y < 0) dcRect.m_min.y = 0; if (dcRect.m_max.x > (int)m_width - 1) dcRect.m_max.x = m_width - 1; if (dcRect.m_max.y > (int)m_height - 1) dcRect.m_max.y = m_height - 1; } #define COPY_PIXEL(x1, y1, x2, y2) \ { \ OdUInt8* p1 = getPixPtr(x1, y1); \ OdUInt8* p2 = getPixPtr(x2, y2); \ p1[0] = p2[0]; \ p1[1] = p2[1]; \ p1[2] = p2[2]; \ } void OdGsSrVectorizerDevice::movePictureRect(const OdGsDCRect& rect, OdInt32 x, OdInt32 y) { OdGsDCRect dcRect(rect); invertYRect(dcRect); // Calculate absolute values for shifts OdInt32 dx = abs(x); OdInt32 dy = abs(y); ODCOLORREF bgColor = getBackgroundColor(); { OdColorConverterCallback* pColorConverter = getColorConverter(); if (pColorConverter && pColorConverter->convertBackgroundColors()) bgColor = pColorConverter->convert(bgColor); } if (x < 0) { if (y > 0) // (x < 0) && (y > 0) { for (OdInt32 j = dcRect.m_min.x; j < dcRect.m_max.x; ++j) { int newJ = j + dx; for (OdInt32 i = dcRect.m_min.y; i < (OdInt32)dcRect.m_max.y; ++i) if (newJ < (OdInt32)dcRect.m_max.x && (i + dy) < (OdInt32)dcRect.m_max.y) COPY_PIXEL(j, i, j - x, i + y) else SET_PIXEL_REVERSE(getPixPtr(j, i), bgColor) } } else // (x < 0) && (y < 0) { for (OdInt32 j = dcRect.m_min.x; j < (OdInt32)dcRect.m_max.x; ++j) { int newJ = j + dx; for (OdInt32 i = (OdInt32)dcRect.m_max.y - 1; i >= dcRect.m_min.y; --i) if (newJ < (OdInt32)dcRect.m_max.x && (i - dy) >= dcRect.m_min.y) COPY_PIXEL(j, i, j - x, i + y) else SET_PIXEL_REVERSE(getPixPtr(j, i), bgColor) } } } else { if (y > 0) // (x > 0) && (y > 0) { for (OdInt32 j = dcRect.m_max.x - 1; j >= dcRect.m_min.x; --j) { int newJ = j - dx; for (OdInt32 i = dcRect.m_min.y; i < (OdInt32)dcRect.m_max.y; ++i) if (newJ >= dcRect.m_min.x && (i + dy) < (OdInt32)dcRect.m_max.y) COPY_PIXEL(j, i, j - x, i + y) else SET_PIXEL_REVERSE(getPixPtr(j, i), bgColor) } } else // (x > 0) && (y < 0) { for (OdInt32 j = dcRect.m_max.x - 1; j >= dcRect.m_min.x; --j) { int newJ = j - dx; for (OdInt32 i = (OdInt32)dcRect.m_max.y - 1; i >= dcRect.m_min.y; --i) if (newJ >= dcRect.m_min.x && (i - dy) >= dcRect.m_min.y) COPY_PIXEL(j, i, j - x, i + y) else SET_PIXEL_REVERSE(getPixPtr(j, i), bgColor) } } } } OdGsSrVectorizerDevice::~OdGsSrVectorizerDevice() { delete m_updateManager; } bool OdGsSrVectorizerDevice::supportPartialUpdate() const { return true; } bool OdGsSrVectorizerDevice::isRasterImageProcessible(const OdGiRasterImage* pImage) const { switch (pImage->colorDepth()) { case 1: case 4: case 8: case 24: case 32: return true; } return false; } typedef OdSrTextureParams::RasterImageBitDepth BitDepth; typedef OdSrTextureParams::RasterImage32TransparencyType TransparencyType; void OdGsSrVectorizerDevice::setRasterImage(const OdGiRasterImage* pImage, bool bTransparent) { m_textureParams.rasterWidth = pImage->pixelWidth(); m_textureParams.rasterHeight = pImage->pixelHeight(); m_textureParams.rasterScanLineLength = pImage->scanLineSize(); m_textureParams.bRasterTransparency = false; m_textureParams.bRasterRGB = false; m_textureParams.raster32TranspMode = TransparencyType::kRI32TTDef; switch (pImage->colorDepth()) { case 1: m_textureParams.rasterBitDepth = BitDepth::kRIBDMono; m_textureParams.bRasterTransparency = bTransparent && (pImage->transparentColor() >= 0); break; case 4: m_textureParams.rasterBitDepth = BitDepth::kRIBD16Clr; m_textureParams.bRasterTransparency = bTransparent && (pImage->transparentColor() >= 0); break; case 8: m_textureParams.rasterBitDepth = BitDepth::kRIBD256Clr; m_textureParams.bRasterTransparency = bTransparent && (pImage->transparentColor() >= 0); break; case 24: m_textureParams.rasterBitDepth = BitDepth::kRIBD24Bpp; m_textureParams.bRasterRGB = (pImage->pixelFormat().isRGB() || pImage->pixelFormat().isRGBA()); break; case 32: m_textureParams.rasterBitDepth = BitDepth::kRIBD32Bpp; m_textureParams.bRasterRGB = (pImage->pixelFormat().isRGB() || pImage->pixelFormat().isRGBA()); m_textureParams.bRasterTransparency = bTransparent && pImage->transparencyMode() != OdGiRasterImage::kTransparencyOff; if (m_textureParams.bRasterTransparency) { switch (pImage->transparencyMode()) { case OdGiRasterImage::kTransparency1Bit: m_textureParams.raster32TranspMode = TransparencyType::kRI32TT1; break; case OdGiRasterImage::kTransparency8Bit: m_textureParams.raster32TranspMode = TransparencyType::kRI32TT8; break; default: break; } } break; default: throw OdError(eNotApplicable); }; m_textureParams.pRasterImagePtr = pImage; if (m_textureParams.rasterBitDepth <= BitDepth::kRIBD256Clr) { OdUInt32 nClrs = pImage->numColors(); m_textureParams.rasterPalette.resize(sizeof(ODCOLORREF) * nClrs); ODCOLORREF* clRefs = (ODCOLORREF*)m_textureParams.rasterPalette.asArrayPtr(); for (OdUInt32 nClr = 0; nClr < nClrs; nClr++) clRefs[nClr] = OD_OPAQUE(pImage->color(nClr)); if (m_textureParams.bRasterTransparency) clRefs[pImage->transparentColor()] &= 0x00FFFFFF; m_textureParams.pRasterPalette = clRefs; } m_textureParams.pRasterScanLines = pImage->scanLines(); if (!m_textureParams.pRasterScanLines) { m_textureParams.rasterScanLines.resize(m_textureParams.rasterHeight * m_textureParams.rasterScanLineLength); pImage->scanLines(m_textureParams.rasterScanLines.asArrayPtr(), 0, m_textureParams.rasterHeight); m_textureParams.pRasterScanLines = m_textureParams.rasterScanLines.asArrayPtr(); } } const OdSrTextureParams& OdGsSrVectorizerDevice::textureParams() const { return m_textureParams; } void OdGsSrVectorizerDevice::clearRasterImage() { m_textureParams.pRasterPalette = nullptr; m_textureParams.rasterPalette.clear(); m_textureParams.pRasterScanLines = nullptr; m_textureParams.rasterScanLines.clear(); m_textureParams.pRasterImagePtr = nullptr; } OdGsModelPtr OdGsSrVectorizerDevice::createModel() { return OdGsBaseVectorizeDevice::createModel(); } void OdGsSrVectorizerDevice::scanLines(OdUInt8* pBytes, OdUInt32 index, OdUInt32 numLines) const { ::memcpy(pBytes, m_pScanLinesBuffer + index * m_scanLineLength, numLines * m_scanLineLength); } const OdUInt8* OdGsSrVectorizerDevice::scanLines() const { return m_pScanLinesBuffer; } OdUInt8Array& OdGsSrVectorizerDevice::frameBuffer() { return m_scanLinesArray; } void OdGsSrVectorizerDevice::update(OdGsDCRect* pRect) { initMetrics(); m_updateManager->updateViews(pRect); } void OdGsSrVectorizerDevice::setInvalidRectsDirectly(const OdGsDCRectArray& rects) { // this is temporary, it's wrong to clear all the rects before adding m_overlayData.getOverlayData(kGsMainOverlay)->m_invalidRects.clear(); m_overlayData.getOverlayData(kGsMainOverlay)->m_invalidRects.assign(rects.begin(), rects.end()); }