void FEBlend::platformApplySoftware() { FilterEffect* in = inputEffect(0); FilterEffect* in2 = inputEffect(1); ASSERT(m_mode > FEBLEND_MODE_UNKNOWN); ASSERT(m_mode <= FEBLEND_MODE_LIGHTEN); Uint8ClampedArray* dstPixelArray = createPremultipliedImageResult(); if (!dstPixelArray) return; IntRect effectADrawingRect = requestedRegionOfInputImageData(in->absolutePaintRect()); RefPtr<Uint8ClampedArray> srcPixelArrayA = in->asPremultipliedImage(effectADrawingRect); IntRect effectBDrawingRect = requestedRegionOfInputImageData(in2->absolutePaintRect()); RefPtr<Uint8ClampedArray> srcPixelArrayB = in2->asPremultipliedImage(effectBDrawingRect); unsigned pixelArrayLength = srcPixelArrayA->length(); ASSERT(pixelArrayLength == srcPixelArrayB->length()); for (unsigned pixelOffset = 0; pixelOffset < pixelArrayLength; pixelOffset += 4) { unsigned char alphaA = srcPixelArrayA->item(pixelOffset + 3); unsigned char alphaB = srcPixelArrayB->item(pixelOffset + 3); for (unsigned channel = 0; channel < 3; ++channel) { unsigned char colorA = srcPixelArrayA->item(pixelOffset + channel); unsigned char colorB = srcPixelArrayB->item(pixelOffset + channel); unsigned char result; switch (m_mode) { case FEBLEND_MODE_NORMAL: result = normal(colorA, colorB, alphaA, alphaB); break; case FEBLEND_MODE_MULTIPLY: result = multiply(colorA, colorB, alphaA, alphaB); break; case FEBLEND_MODE_SCREEN: result = screen(colorA, colorB, alphaA, alphaB); break; case FEBLEND_MODE_DARKEN: result = darken(colorA, colorB, alphaA, alphaB); break; case FEBLEND_MODE_LIGHTEN: result = lighten(colorA, colorB, alphaA, alphaB); break; case FEBLEND_MODE_UNKNOWN: default: result = 0; break; } dstPixelArray->set(pixelOffset + channel, result); } unsigned char alphaR = 255 - ((255 - alphaA) * (255 - alphaB)) / 255; dstPixelArray->set(pixelOffset + 3, alphaR); } }
void FEDisplacementMap::applySoftware() { FilterEffect* in = inputEffect(0); FilterEffect* in2 = inputEffect(1); ASSERT(m_xChannelSelector != CHANNEL_UNKNOWN); ASSERT(m_yChannelSelector != CHANNEL_UNKNOWN); Uint8ClampedArray* dstPixelArray = createPremultipliedImageResult(); if (!dstPixelArray) return; IntRect effectADrawingRect = requestedRegionOfInputImageData(in->absolutePaintRect()); RefPtr<Uint8ClampedArray> srcPixelArrayA = in->asPremultipliedImage(effectADrawingRect); IntRect effectBDrawingRect = requestedRegionOfInputImageData(in2->absolutePaintRect()); RefPtr<Uint8ClampedArray> srcPixelArrayB = in2->asUnmultipliedImage(effectBDrawingRect); ASSERT(srcPixelArrayA->length() == srcPixelArrayB->length()); Filter* filter = this->filter(); IntSize paintSize = absolutePaintRect().size(); float scaleX = filter->applyHorizontalScale(m_scale); float scaleY = filter->applyVerticalScale(m_scale); float scaleForColorX = scaleX / 255.0; float scaleForColorY = scaleY / 255.0; float scaledOffsetX = 0.5 - scaleX * 0.5; float scaledOffsetY = 0.5 - scaleY * 0.5; int stride = paintSize.width() * 4; for (int y = 0; y < paintSize.height(); ++y) { int line = y * stride; for (int x = 0; x < paintSize.width(); ++x) { int dstIndex = line + x * 4; int srcX = x + static_cast<int>(scaleForColorX * srcPixelArrayB->item(dstIndex + m_xChannelSelector - 1) + scaledOffsetX); int srcY = y + static_cast<int>(scaleForColorY * srcPixelArrayB->item(dstIndex + m_yChannelSelector - 1) + scaledOffsetY); for (unsigned channel = 0; channel < 4; ++channel) { if (srcX < 0 || srcX >= paintSize.width() || srcY < 0 || srcY >= paintSize.height()) { dstPixelArray->set(dstIndex + channel, static_cast<unsigned char>(0)); } else { unsigned char pixelValue = srcPixelArrayA->item(srcY * stride + srcX * 4 + channel); dstPixelArray->set(dstIndex + channel, pixelValue); } } } } }
void FEMorphology::platformApplyGeneric(PaintingData* paintingData, int yStart, int yEnd) { Uint8ClampedArray* srcPixelArray = paintingData->srcPixelArray; Uint8ClampedArray* dstPixelArray = paintingData->dstPixelArray; const int width = paintingData->width; const int height = paintingData->height; const int effectWidth = width * 4; const int radiusX = paintingData->radiusX; const int radiusY = paintingData->radiusY; Vector<unsigned char> extrema; for (int y = yStart; y < yEnd; ++y) { int extremaStartY = std::max(0, y - radiusY); int extremaEndY = std::min(height - 1, y + radiusY); for (unsigned int clrChannel = 0; clrChannel < 4; ++clrChannel) { extrema.clear(); // Compute extremas for each columns for (int x = 0; x <= radiusX; ++x) { unsigned char columnExtrema = srcPixelArray->item(extremaStartY * effectWidth + 4 * x + clrChannel); for (int eY = extremaStartY + 1; eY < extremaEndY; ++eY) { unsigned char pixel = srcPixelArray->item(eY * effectWidth + 4 * x + clrChannel); if ((m_type == FEMORPHOLOGY_OPERATOR_ERODE && pixel <= columnExtrema) || (m_type == FEMORPHOLOGY_OPERATOR_DILATE && pixel >= columnExtrema)) { columnExtrema = pixel; } } extrema.append(columnExtrema); } // Kernel is filled, get extrema of next column for (int x = 0; x < width; ++x) { const int endX = std::min(x + radiusX, width - 1); unsigned char columnExtrema = srcPixelArray->item(extremaStartY * effectWidth + endX * 4 + clrChannel); for (int i = extremaStartY + 1; i <= extremaEndY; ++i) { unsigned char pixel = srcPixelArray->item(i * effectWidth + endX * 4 + clrChannel); if ((m_type == FEMORPHOLOGY_OPERATOR_ERODE && pixel <= columnExtrema) || (m_type == FEMORPHOLOGY_OPERATOR_DILATE && pixel >= columnExtrema)) columnExtrema = pixel; } if (x - radiusX >= 0) extrema.remove(0); if (x + radiusX <= width) extrema.append(columnExtrema); unsigned char entireExtrema = extrema[0]; for (unsigned kernelIndex = 1; kernelIndex < extrema.size(); ++kernelIndex) { if ((m_type == FEMORPHOLOGY_OPERATOR_ERODE && extrema[kernelIndex] <= entireExtrema) || (m_type == FEMORPHOLOGY_OPERATOR_DILATE && extrema[kernelIndex] >= entireExtrema)) entireExtrema = extrema[kernelIndex]; } dstPixelArray->set(y * effectWidth + 4 * x + clrChannel, entireExtrema); } } } }
void FEMorphology::platformApplyGeneric(PaintingData* paintingData, int yStart, int yEnd) { Uint8ClampedArray* srcPixelArray = paintingData->srcPixelArray; Uint8ClampedArray* dstPixelArray = paintingData->dstPixelArray; const int radiusX = paintingData->radiusX; const int radiusY = paintingData->radiusY; const int width = paintingData->width; const int height = paintingData->height; ASSERT(radiusX <= width || radiusY <= height); ASSERT(yStart >= 0 && yEnd <= height && yStart < yEnd); Vector<unsigned char> extrema; for (int y = yStart; y < yEnd; ++y) { int yStartExtrema = std::max(0, y - radiusY); int yEndExtrema = std::min(height - 1, y + radiusY); for (unsigned colorChannel = 0; colorChannel < 4; ++colorChannel) { extrema.clear(); // Compute extremas for each columns for (int x = 0; x < radiusX; ++x) extrema.append(columnExtremum(srcPixelArray, x, yStartExtrema, yEndExtrema, width, colorChannel, m_type)); // Kernel is filled, get extrema of next column for (int x = 0; x < width; ++x) { if (x < width - radiusX) { int xEnd = std::min(x + radiusX, width - 1); extrema.append(columnExtremum(srcPixelArray, xEnd, yStartExtrema, yEndExtrema + 1, width, colorChannel, m_type)); } if (x > radiusX) extrema.remove(0); // The extrema original size = radiusX. // Number of new addition = width - radiusX. // Number of removals = width - radiusX - 1. ASSERT(extrema.size() >= static_cast<size_t>(radiusX + 1)); dstPixelArray->set(pixelArrayIndex(x, y, width, colorChannel), kernelExtremum(extrema, m_type)); } } } }
void FEComponentTransfer::platformApplySoftware() { FilterEffect* in = inputEffect(0); Uint8ClampedArray* pixelArray = createUnmultipliedImageResult(); if (!pixelArray) return; unsigned char rValues[256], gValues[256], bValues[256], aValues[256]; getValues(rValues, gValues, bValues, aValues); unsigned char* tables[] = { rValues, gValues, bValues, aValues }; IntRect drawingRect = requestedRegionOfInputImageData(in->absolutePaintRect()); in->copyUnmultipliedImage(pixelArray, drawingRect); unsigned pixelArrayLength = pixelArray->length(); for (unsigned pixelOffset = 0; pixelOffset < pixelArrayLength; pixelOffset += 4) { for (unsigned channel = 0; channel < 4; ++channel) { unsigned char c = pixelArray->item(pixelOffset + channel); pixelArray->set(pixelOffset + channel, tables[channel][c]); } } }