mirror of
https://github.com/JakubMelka/PDF4QT.git
synced 2025-02-27 00:47:57 +01:00
Image processing
This commit is contained in:
parent
d632595710
commit
4b291d6db8
@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2019-2020 Jakub Melka
|
||||
// Copyright (C) 2019-2021 Jakub Melka
|
||||
//
|
||||
// This file is part of Pdf4Qt.
|
||||
//
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2019-2020 Jakub Melka
|
||||
// Copyright (C) 2019-2021 Jakub Melka
|
||||
//
|
||||
// This file is part of Pdf4Qt.
|
||||
//
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2020 Jakub Melka
|
||||
// Copyright (C) 2020-2021 Jakub Melka
|
||||
//
|
||||
// This file is part of Pdf4Qt.
|
||||
//
|
||||
@ -700,6 +700,12 @@ PDFFloatBitmapWithColorSpace::PDFFloatBitmapWithColorSpace()
|
||||
|
||||
}
|
||||
|
||||
PDFFloatBitmapWithColorSpace::PDFFloatBitmapWithColorSpace(size_t width, size_t height, PDFPixelFormat format) :
|
||||
PDFFloatBitmap(width, height, format)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
PDFFloatBitmapWithColorSpace::PDFFloatBitmapWithColorSpace(size_t width, size_t height, PDFPixelFormat format, PDFColorSpacePointer blendColorSpace) :
|
||||
PDFFloatBitmap(width, height, format),
|
||||
m_colorSpace(blendColorSpace)
|
||||
@ -1134,11 +1140,126 @@ PDFFloatBitmapWithColorSpace PDFTransparencyRenderer::getColoredImage(const PDFI
|
||||
const PDFImageData& softMask = sourceImage.getSoftMaskData();
|
||||
|
||||
PDFColorSpacePointer imageColorSpace = sourceImage.getColorSpace();
|
||||
const size_t colorComponentCount = imageColorSpace->getColorComponentCount();
|
||||
const bool isCMYK = colorComponentCount == 4;
|
||||
size_t colorComponentCount = imageColorSpace->getColorComponentCount();
|
||||
bool isCMYK = colorComponentCount == 4;
|
||||
const bool useSmoothImageTransformation = m_settings.flags.testFlag(PDFTransparencyRendererSettings::SmoothImageTransformation) && sourceImage.isInterpolated();
|
||||
|
||||
if (!imageColorSpace)
|
||||
{
|
||||
throw PDFException(PDFTranslationContext::tr("Invalid image color space."));
|
||||
}
|
||||
|
||||
Q_ASSERT(imageData.isValid());
|
||||
if (imageColorSpace->getColorSpace() == PDFAbstractColorSpace::ColorSpace::Indexed)
|
||||
{
|
||||
const PDFIndexedColorSpace* indexedColorSpace = dynamic_cast<const PDFIndexedColorSpace*>(imageColorSpace.data());
|
||||
imageColorSpace = indexedColorSpace->getBaseColorSpace();
|
||||
|
||||
if (!imageColorSpace)
|
||||
{
|
||||
throw PDFException(PDFTranslationContext::tr("Invalid base color space of indexed color space."));
|
||||
}
|
||||
|
||||
unsigned int componentCount = imageData.getComponents();
|
||||
PDFBitReader reader(&imageData.getData(), imageData.getBitsPerComponent());
|
||||
|
||||
if (componentCount != colorComponentCount)
|
||||
{
|
||||
throw PDFException(PDFTranslationContext::tr("Invalid colors for indexed color space. Color space has %1 colors. Provided color count is %4.").arg(colorComponentCount).arg(componentCount));
|
||||
}
|
||||
|
||||
const unsigned int imageWidth = imageData.getWidth();
|
||||
const unsigned int imageHeight = imageData.getHeight();
|
||||
Q_ASSERT(componentCount == 1);
|
||||
|
||||
std::vector<PDFColorComponent> colorIndices;
|
||||
colorIndices.reserve(imageData.getWidth() * imageData.getHeight());
|
||||
|
||||
for (unsigned int i = 0; i < imageHeight; ++i)
|
||||
{
|
||||
reader.seek(i * imageData.getStride());
|
||||
|
||||
for (unsigned int j = 0; j < imageWidth; ++j)
|
||||
{
|
||||
PDFBitReader::Value index = reader.read();
|
||||
colorIndices.push_back(index);
|
||||
}
|
||||
}
|
||||
|
||||
PDFColorBuffer indicesBuffer(colorIndices.data(), colorIndices.size());
|
||||
std::vector<PDFColorComponent> transformedColors = indexedColorSpace->transformColorsToBaseColorSpace(indicesBuffer);
|
||||
colorComponentCount = imageColorSpace->getColorComponentCount();
|
||||
isCMYK = colorComponentCount == 4;
|
||||
|
||||
if (transformedColors.size() != colorComponentCount * imageWidth * imageHeight)
|
||||
{
|
||||
throw PDFException(PDFTranslationContext::tr("Conversion of indexed image to base color space failed."));
|
||||
}
|
||||
|
||||
result = PDFFloatBitmapWithColorSpace(imageWidth, imageHeight, PDFPixelFormat::createFormat(uint8_t(colorComponentCount), 0, true, isCMYK, false));
|
||||
result.makeOpaque();
|
||||
|
||||
for (unsigned int i = 0; i < imageHeight; ++i)
|
||||
{
|
||||
for (unsigned int j = 0; j < imageWidth; ++j)
|
||||
{
|
||||
PDFColorBuffer buffer = result.getPixel(j, i);
|
||||
|
||||
size_t pixelIndex = (i * imageWidth + j) * colorComponentCount;
|
||||
for (size_t k = 0; k < colorComponentCount; ++k)
|
||||
{
|
||||
Q_ASSERT(pixelIndex + k < transformedColors.size());
|
||||
buffer[k] = transformedColors[pixelIndex + k];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch (imageData.getMaskingType())
|
||||
{
|
||||
case PDFImageData::MaskingType::None:
|
||||
break;
|
||||
|
||||
case PDFImageData::MaskingType::SoftMask:
|
||||
{
|
||||
PDFFloatBitmap alphaMask = getAlphaMaskFromSoftMask(softMask);
|
||||
if (alphaMask.getWidth() != result.getWidth() || alphaMask.getHeight() != result.getHeight())
|
||||
{
|
||||
// Scale the alpha mask, if it is masked
|
||||
alphaMask = alphaMask.resize(result.getWidth(), result.getHeight(), useSmoothImageTransformation ? Qt::SmoothTransformation : Qt::FastTransformation);
|
||||
}
|
||||
Q_ASSERT(alphaMask.getPixelFormat().getChannelCount() == 2);
|
||||
Q_ASSERT(alphaMask.getPixelFormat().hasOpacityChannel());
|
||||
Q_ASSERT(alphaMask.getPixelFormat().hasShapeChannel());
|
||||
|
||||
Q_ASSERT(result.getPixelFormat().hasShapeChannel());
|
||||
Q_ASSERT(result.getPixelFormat().hasOpacityChannel());
|
||||
|
||||
const uint8_t sourceShapeChannelIndex = alphaMask.getPixelFormat().getShapeChannelIndex();
|
||||
const uint8_t sourceOpacityChannelIndex = alphaMask.getPixelFormat().getOpacityChannelIndex();
|
||||
const uint8_t targetShapeChannelIndex = result.getPixelFormat().getShapeChannelIndex();
|
||||
const uint8_t targetOpacityChannelIndex = result.getPixelFormat().getOpacityChannelIndex();
|
||||
|
||||
for (size_t i = 0; i < imageHeight; ++i)
|
||||
{
|
||||
for (unsigned int j = 0; j < imageWidth; ++j)
|
||||
{
|
||||
PDFColorBuffer targetBuffer = result.getPixel(j, i);
|
||||
PDFColorBuffer alphaBuffer = alphaMask.getPixel(j, i);
|
||||
|
||||
targetBuffer[targetShapeChannelIndex] = alphaBuffer[sourceShapeChannelIndex];
|
||||
targetBuffer[targetOpacityChannelIndex] = alphaBuffer[sourceOpacityChannelIndex];
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
throw PDFRendererException(RenderErrorType::NotImplemented, PDFTranslationContext::tr("Image masking not implemented!"));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (imageData.getMaskingType())
|
||||
{
|
||||
case PDFImageData::MaskingType::None:
|
||||
@ -1380,11 +1501,53 @@ PDFFloatBitmapWithColorSpace PDFTransparencyRenderer::getColoredImage(const PDFI
|
||||
throw PDFRendererException(RenderErrorType::NotImplemented, PDFTranslationContext::tr("Image masking not implemented!"));
|
||||
}
|
||||
}
|
||||
/*
|
||||
mapovani barev, pripadne prevod do blend color space
|
||||
vyresit indexed color space
|
||||
vyresit aktivni barvy
|
||||
*/
|
||||
}
|
||||
|
||||
// Jakub Melka: We are mapping into draw buffer, so we must use draw buffer pixel format
|
||||
PDFInkMapping inkMapping = m_inkMapper->createMapping(imageColorSpace.data(), getBlendColorSpace().data(), m_drawBuffer.getPixelFormat());
|
||||
if (!inkMapping.isValid())
|
||||
{
|
||||
result.convertToColorSpace(getCMS(), getGraphicState()->getRenderingIntent(), getBlendColorSpace(), this);
|
||||
inkMapping = m_inkMapper->createMapping(getBlendColorSpace().data(), getBlendColorSpace().data(), m_drawBuffer.getPixelFormat());
|
||||
}
|
||||
|
||||
Q_ASSERT(inkMapping.isValid());
|
||||
|
||||
PDFFloatBitmapWithColorSpace finalResult(result.getWidth(), result.getHeight(), m_drawBuffer.getPixelFormat(), getBlendColorSpace());
|
||||
|
||||
const uint8_t sourceBufferShapeChannelIndex = result.getPixelFormat().getShapeChannelIndex();
|
||||
const uint8_t sourceBufferOpacityChannelIndex = result.getPixelFormat().getOpacityChannelIndex();
|
||||
const uint8_t targetBufferShapeChannelIndex = finalResult.getPixelFormat().getShapeChannelIndex();
|
||||
const uint8_t targetBufferOpacityChannelIndex = finalResult.getPixelFormat().getOpacityChannelIndex();
|
||||
|
||||
for (size_t y = 0; y < result.getHeight(); ++y)
|
||||
{
|
||||
for (size_t x = 0; x < result.getWidth(); ++x)
|
||||
{
|
||||
PDFColorBuffer sourceBuffer = result.getPixel(x, y);
|
||||
PDFColorBuffer targetBuffer = finalResult.getPixel(x, y);
|
||||
|
||||
for (const PDFInkMapping::Mapping& ink : inkMapping.mapping)
|
||||
{
|
||||
switch (ink.type)
|
||||
{
|
||||
case pdf::PDFInkMapping::Pass:
|
||||
targetBuffer[ink.target] = sourceBuffer[ink.source];
|
||||
break;
|
||||
|
||||
default:
|
||||
Q_ASSERT(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
targetBuffer[targetBufferShapeChannelIndex] = sourceBuffer[sourceBufferShapeChannelIndex];
|
||||
targetBuffer[targetBufferOpacityChannelIndex] = sourceBuffer[sourceBufferOpacityChannelIndex];
|
||||
}
|
||||
}
|
||||
|
||||
result = qMove(finalResult);
|
||||
result.setColorActivity(inkMapping.activeChannels);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user