summaryrefslogtreecommitdiffstats
path: root/image/test/gtest/TestADAM7InterpolatingFilter.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'image/test/gtest/TestADAM7InterpolatingFilter.cpp')
-rw-r--r--image/test/gtest/TestADAM7InterpolatingFilter.cpp595
1 files changed, 595 insertions, 0 deletions
diff --git a/image/test/gtest/TestADAM7InterpolatingFilter.cpp b/image/test/gtest/TestADAM7InterpolatingFilter.cpp
new file mode 100644
index 0000000000..b2ae6b5a58
--- /dev/null
+++ b/image/test/gtest/TestADAM7InterpolatingFilter.cpp
@@ -0,0 +1,595 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include <algorithm>
+#include <vector>
+
+#include "gtest/gtest.h"
+
+#include "mozilla/gfx/2D.h"
+#include "mozilla/Maybe.h"
+#include "Common.h"
+#include "Decoder.h"
+#include "DecoderFactory.h"
+#include "SourceBuffer.h"
+#include "SurfaceFilters.h"
+#include "SurfacePipe.h"
+
+using namespace mozilla;
+using namespace mozilla::gfx;
+using namespace mozilla::image;
+
+using std::generate;
+using std::vector;
+
+template <typename Func>
+void WithADAM7InterpolatingFilter(const IntSize& aSize, Func aFunc) {
+ RefPtr<image::Decoder> decoder = CreateTrivialDecoder();
+ ASSERT_TRUE(bool(decoder));
+
+ WithFilterPipeline(
+ decoder, std::forward<Func>(aFunc), ADAM7InterpolatingConfig{},
+ SurfaceConfig{decoder, aSize, SurfaceFormat::OS_RGBA, false});
+}
+
+void AssertConfiguringADAM7InterpolatingFilterFails(const IntSize& aSize) {
+ RefPtr<image::Decoder> decoder = CreateTrivialDecoder();
+ ASSERT_TRUE(bool(decoder));
+
+ AssertConfiguringPipelineFails(
+ decoder, ADAM7InterpolatingConfig{},
+ SurfaceConfig{decoder, aSize, SurfaceFormat::OS_RGBA, false});
+}
+
+uint8_t InterpolateByte(uint8_t aByteA, uint8_t aByteB, float aWeight) {
+ return uint8_t(aByteA * aWeight + aByteB * (1.0f - aWeight));
+}
+
+BGRAColor InterpolateColors(BGRAColor aColor1, BGRAColor aColor2,
+ float aWeight) {
+ return BGRAColor(InterpolateByte(aColor1.mBlue, aColor2.mBlue, aWeight),
+ InterpolateByte(aColor1.mGreen, aColor2.mGreen, aWeight),
+ InterpolateByte(aColor1.mRed, aColor2.mRed, aWeight),
+ InterpolateByte(aColor1.mAlpha, aColor2.mAlpha, aWeight));
+}
+
+enum class ShouldInterpolate { eYes, eNo };
+
+BGRAColor HorizontallyInterpolatedPixel(uint32_t aCol, uint32_t aWidth,
+ const vector<float>& aWeights,
+ ShouldInterpolate aShouldInterpolate,
+ const vector<BGRAColor>& aColors) {
+ // We cycle through the vector of weights forever.
+ float weight = aWeights[aCol % aWeights.size()];
+
+ // Find the columns of the two final pixels for this set of weights.
+ uint32_t finalPixel1 = aCol - aCol % aWeights.size();
+ uint32_t finalPixel2 = finalPixel1 + aWeights.size();
+
+ // If |finalPixel2| is past the end of the row, that means that there is no
+ // final pixel after the pixel at |finalPixel1|. In that case, we just want to
+ // duplicate |finalPixel1|'s color until the end of the row. We can do that by
+ // setting |finalPixel2| equal to |finalPixel1| so that the interpolation has
+ // no effect.
+ if (finalPixel2 >= aWidth) {
+ finalPixel2 = finalPixel1;
+ }
+
+ // We cycle through the vector of colors forever (subject to the above
+ // constraint about the end of the row).
+ BGRAColor color1 = aColors[finalPixel1 % aColors.size()];
+ BGRAColor color2 = aColors[finalPixel2 % aColors.size()];
+
+ // If we're not interpolating, we treat all pixels which aren't final as
+ // transparent. Since the number of weights we have is equal to the stride
+ // between final pixels, we can check if |aCol| is a final pixel by checking
+ // whether |aCol| is a multiple of |aWeights.size()|.
+ if (aShouldInterpolate == ShouldInterpolate::eNo) {
+ return aCol % aWeights.size() == 0 ? color1 : BGRAColor::Transparent();
+ }
+
+ // Interpolate.
+ return InterpolateColors(color1, color2, weight);
+}
+
+vector<float>& InterpolationWeights(int32_t aStride) {
+ // Precalculated interpolation weights. These are used to interpolate
+ // between final pixels or between important rows. Although no interpolation
+ // is actually applied to the previous final pixel or important row value,
+ // the arrays still start with 1.0f, which is always skipped, primarily
+ // because otherwise |stride1Weights| would have zero elements.
+ static vector<float> stride8Weights = {1.0f, 7 / 8.0f, 6 / 8.0f,
+ 5 / 8.0f, 4 / 8.0f, 3 / 8.0f,
+ 2 / 8.0f, 1 / 8.0f};
+ static vector<float> stride4Weights = {1.0f, 3 / 4.0f, 2 / 4.0f, 1 / 4.0f};
+ static vector<float> stride2Weights = {1.0f, 1 / 2.0f};
+ static vector<float> stride1Weights = {1.0f};
+
+ switch (aStride) {
+ case 8:
+ return stride8Weights;
+ case 4:
+ return stride4Weights;
+ case 2:
+ return stride2Weights;
+ case 1:
+ return stride1Weights;
+ default:
+ MOZ_CRASH();
+ }
+}
+
+int32_t ImportantRowStride(uint8_t aPass) {
+ // The stride between important rows for each pass, with a dummy value for
+ // the nonexistent pass 0 and for pass 8, since the tests run an extra pass to
+ // make sure nothing breaks.
+ static int32_t strides[] = {1, 8, 8, 4, 4, 2, 2, 1, 1};
+
+ return strides[aPass];
+}
+
+size_t FinalPixelStride(uint8_t aPass) {
+ // The stride between the final pixels in important rows for each pass, with
+ // a dummy value for the nonexistent pass 0 and for pass 8, since the tests
+ // run an extra pass to make sure nothing breaks.
+ static size_t strides[] = {1, 8, 4, 4, 2, 2, 1, 1, 1};
+
+ return strides[aPass];
+}
+
+bool IsImportantRow(int32_t aRow, uint8_t aPass) {
+ return aRow % ImportantRowStride(aPass) == 0;
+}
+
+/**
+ * ADAM7 breaks up the image into 8x8 blocks. On each of the 7 passes, a new
+ * set of pixels in each block receives their final values, according to the
+ * following pattern:
+ *
+ * 1 6 4 6 2 6 4 6
+ * 7 7 7 7 7 7 7 7
+ * 5 6 5 6 5 6 5 6
+ * 7 7 7 7 7 7 7 7
+ * 3 6 4 6 3 6 4 6
+ * 7 7 7 7 7 7 7 7
+ * 5 6 5 6 5 6 5 6
+ * 7 7 7 7 7 7 7 7
+ *
+ * This function produces a row of pixels @aWidth wide, suitable for testing
+ * horizontal interpolation on pass @aPass. The pattern of pixels used is
+ * determined by @aPass and @aRow, which determine which pixels are final
+ * according to the table above, and @aColors, from which the pixel values
+ * are selected.
+ *
+ * There are two different behaviors: if |eNo| is passed for
+ * @aShouldInterpolate, non-final pixels are treated as transparent. If |eNo|
+ * is passed, non-final pixels get interpolated in from the surrounding final
+ * pixels. The intention is that |eNo| is passed to generate input which will
+ * be run through ADAM7InterpolatingFilter, and |eYes| is passed to generate
+ * reference data to check that the filter is performing horizontal
+ * interpolation correctly.
+ *
+ * This function does not perform vertical interpolation. Rows which aren't on
+ * the current pass are filled with transparent pixels.
+ *
+ * @return a vector<BGRAColor> representing a row of pixels.
+ */
+vector<BGRAColor> ADAM7HorizontallyInterpolatedRow(
+ uint8_t aPass, uint32_t aRow, uint32_t aWidth,
+ ShouldInterpolate aShouldInterpolate, const vector<BGRAColor>& aColors) {
+ EXPECT_GT(aPass, 0);
+ EXPECT_LE(aPass, 8);
+ EXPECT_GT(aColors.size(), 0u);
+
+ vector<BGRAColor> result(aWidth);
+
+ if (IsImportantRow(aRow, aPass)) {
+ vector<float>& weights = InterpolationWeights(FinalPixelStride(aPass));
+
+ // Compute the horizontally interpolated row.
+ uint32_t col = 0;
+ generate(result.begin(), result.end(), [&] {
+ return HorizontallyInterpolatedPixel(col++, aWidth, weights,
+ aShouldInterpolate, aColors);
+ });
+ } else {
+ // This is an unimportant row; just make the entire thing transparent.
+ generate(result.begin(), result.end(),
+ [] { return BGRAColor::Transparent(); });
+ }
+
+ EXPECT_EQ(result.size(), size_t(aWidth));
+
+ return result;
+}
+
+WriteState WriteUninterpolatedPixels(SurfaceFilter* aFilter,
+ const IntSize& aSize, uint8_t aPass,
+ const vector<BGRAColor>& aColors) {
+ WriteState result = WriteState::NEED_MORE_DATA;
+
+ for (int32_t row = 0; row < aSize.height; ++row) {
+ // Compute uninterpolated pixels for this row.
+ vector<BGRAColor> pixels = ADAM7HorizontallyInterpolatedRow(
+ aPass, row, aSize.width, ShouldInterpolate::eNo, aColors);
+
+ // Write them to the surface.
+ auto pixelIterator = pixels.cbegin();
+ result = aFilter->WritePixelsToRow<uint32_t>(
+ [&] { return AsVariant((*pixelIterator++).AsPixel()); });
+
+ if (result != WriteState::NEED_MORE_DATA) {
+ break;
+ }
+ }
+
+ return result;
+}
+
+bool CheckHorizontallyInterpolatedImage(image::Decoder* aDecoder,
+ const IntSize& aSize, uint8_t aPass,
+ const vector<BGRAColor>& aColors) {
+ RawAccessFrameRef currentFrame = aDecoder->GetCurrentFrameRef();
+ RefPtr<SourceSurface> surface = currentFrame->GetSourceSurface();
+
+ for (int32_t row = 0; row < aSize.height; ++row) {
+ if (!IsImportantRow(row, aPass)) {
+ continue; // Don't check rows which aren't important on this pass.
+ }
+
+ // Compute the expected pixels, *with* interpolation to match what the
+ // filter should have done.
+ vector<BGRAColor> expectedPixels = ADAM7HorizontallyInterpolatedRow(
+ aPass, row, aSize.width, ShouldInterpolate::eYes, aColors);
+
+ if (!RowHasPixels(surface, row, expectedPixels)) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+void CheckHorizontalInterpolation(const IntSize& aSize,
+ const vector<BGRAColor>& aColors) {
+ const IntRect surfaceRect(IntPoint(0, 0), aSize);
+
+ WithADAM7InterpolatingFilter(
+ aSize, [&](image::Decoder* aDecoder, SurfaceFilter* aFilter) {
+ // We check horizontal interpolation behavior for each pass
+ // individually. In addition to the normal 7 passes that ADAM7 includes,
+ // we also check an eighth pass to verify that nothing breaks if extra
+ // data is written.
+ for (uint8_t pass = 1; pass <= 8; ++pass) {
+ // Write our color pattern to the surface. We don't perform any
+ // interpolation when writing to the filter so that we can check that
+ // the filter itself *does*.
+ WriteState result =
+ WriteUninterpolatedPixels(aFilter, aSize, pass, aColors);
+
+ EXPECT_EQ(WriteState::FINISHED, result);
+ AssertCorrectPipelineFinalState(aFilter, surfaceRect, surfaceRect);
+
+ // Check that the generated image matches the expected pattern, with
+ // interpolation applied.
+ EXPECT_TRUE(CheckHorizontallyInterpolatedImage(aDecoder, aSize, pass,
+ aColors));
+
+ // Prepare for the next pass.
+ aFilter->ResetToFirstRow();
+ }
+ });
+}
+
+BGRAColor ADAM7RowColor(int32_t aRow, uint8_t aPass,
+ const vector<BGRAColor>& aColors) {
+ EXPECT_LT(0, aPass);
+ EXPECT_GE(8, aPass);
+ EXPECT_LT(0u, aColors.size());
+
+ // If this is an important row, select the color from the provided vector of
+ // colors, which we cycle through infinitely. If not, just fill the row with
+ // transparent pixels.
+ return IsImportantRow(aRow, aPass) ? aColors[aRow % aColors.size()]
+ : BGRAColor::Transparent();
+}
+
+WriteState WriteRowColorPixels(SurfaceFilter* aFilter, const IntSize& aSize,
+ uint8_t aPass,
+ const vector<BGRAColor>& aColors) {
+ WriteState result = WriteState::NEED_MORE_DATA;
+
+ for (int32_t row = 0; row < aSize.height; ++row) {
+ const uint32_t color = ADAM7RowColor(row, aPass, aColors).AsPixel();
+
+ // Fill the surface with |color| pixels.
+ result =
+ aFilter->WritePixelsToRow<uint32_t>([&] { return AsVariant(color); });
+
+ if (result != WriteState::NEED_MORE_DATA) {
+ break;
+ }
+ }
+
+ return result;
+}
+
+bool CheckVerticallyInterpolatedImage(image::Decoder* aDecoder,
+ const IntSize& aSize, uint8_t aPass,
+ const vector<BGRAColor>& aColors) {
+ vector<float>& weights = InterpolationWeights(ImportantRowStride(aPass));
+
+ for (int32_t row = 0; row < aSize.height; ++row) {
+ // Vertically interpolation takes place between two important rows. The
+ // separation between the important rows is determined by the stride of this
+ // pass. When there is no "next" important row because we'd run off the
+ // bottom of the image, we use the same row for both. This matches
+ // ADAM7InterpolatingFilter's behavior of duplicating the last important row
+ // since there isn't another important row to vertically interpolate it
+ // with.
+ const int32_t stride = ImportantRowStride(aPass);
+ const int32_t prevImportantRow = row - row % stride;
+ const int32_t maybeNextImportantRow = prevImportantRow + stride;
+ const int32_t nextImportantRow = maybeNextImportantRow < aSize.height
+ ? maybeNextImportantRow
+ : prevImportantRow;
+
+ // Retrieve the colors for the important rows we're going to interpolate.
+ const BGRAColor prevImportantRowColor =
+ ADAM7RowColor(prevImportantRow, aPass, aColors);
+ const BGRAColor nextImportantRowColor =
+ ADAM7RowColor(nextImportantRow, aPass, aColors);
+
+ // The weight we'll use for interpolation is also determined by the stride.
+ // A row halfway between two important rows should have pixels that have a
+ // 50% contribution from each of the important rows, for example.
+ const float weight = weights[row % stride];
+ const BGRAColor interpolatedColor =
+ InterpolateColors(prevImportantRowColor, nextImportantRowColor, weight);
+
+ // Generate a row of expected pixels. Every pixel in the row is always the
+ // same color since we're only testing vertical interpolation between
+ // solid-colored rows.
+ vector<BGRAColor> expectedPixels(aSize.width);
+ generate(expectedPixels.begin(), expectedPixels.end(),
+ [&] { return interpolatedColor; });
+
+ // Check that the pixels match.
+ RawAccessFrameRef currentFrame = aDecoder->GetCurrentFrameRef();
+ RefPtr<SourceSurface> surface = currentFrame->GetSourceSurface();
+ if (!RowHasPixels(surface, row, expectedPixels)) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+void CheckVerticalInterpolation(const IntSize& aSize,
+ const vector<BGRAColor>& aColors) {
+ const IntRect surfaceRect(IntPoint(0, 0), aSize);
+
+ WithADAM7InterpolatingFilter(aSize, [&](image::Decoder* aDecoder,
+ SurfaceFilter* aFilter) {
+ for (uint8_t pass = 1; pass <= 8; ++pass) {
+ // Write a pattern of rows to the surface. Important rows will receive a
+ // color selected from |aColors|; unimportant rows will be transparent.
+ WriteState result = WriteRowColorPixels(aFilter, aSize, pass, aColors);
+
+ EXPECT_EQ(WriteState::FINISHED, result);
+ AssertCorrectPipelineFinalState(aFilter, surfaceRect, surfaceRect);
+
+ // Check that the generated image matches the expected pattern, with
+ // interpolation applied.
+ EXPECT_TRUE(
+ CheckVerticallyInterpolatedImage(aDecoder, aSize, pass, aColors));
+
+ // Prepare for the next pass.
+ aFilter->ResetToFirstRow();
+ }
+ });
+}
+
+void CheckInterpolation(const IntSize& aSize,
+ const vector<BGRAColor>& aColors) {
+ CheckHorizontalInterpolation(aSize, aColors);
+ CheckVerticalInterpolation(aSize, aColors);
+}
+
+void CheckADAM7InterpolatingWritePixels(const IntSize& aSize) {
+ // This test writes 8 passes of green pixels (the seven ADAM7 passes, plus one
+ // extra to make sure nothing goes wrong if we write too much input) and
+ // verifies that the output is a solid green surface each time. Because all
+ // the pixels are the same color, interpolation doesn't matter; we test the
+ // correctness of the interpolation algorithm itself separately.
+ WithADAM7InterpolatingFilter(
+ aSize, [&](image::Decoder* aDecoder, SurfaceFilter* aFilter) {
+ IntRect rect(IntPoint(0, 0), aSize);
+
+ for (int32_t pass = 1; pass <= 8; ++pass) {
+ // We only actually write up to the last important row for each pass,
+ // because that row unambiguously determines the remaining rows.
+ const int32_t lastRow = aSize.height - 1;
+ const int32_t lastImportantRow =
+ lastRow - (lastRow % ImportantRowStride(pass));
+ const IntRect inputWriteRect(0, 0, aSize.width, lastImportantRow + 1);
+
+ CheckWritePixels(aDecoder, aFilter,
+ /* aOutputRect = */ Some(rect),
+ /* aInputRect = */ Some(rect),
+ /* aInputWriteRect = */ Some(inputWriteRect));
+
+ aFilter->ResetToFirstRow();
+ EXPECT_FALSE(aFilter->IsSurfaceFinished());
+ Maybe<SurfaceInvalidRect> invalidRect = aFilter->TakeInvalidRect();
+ EXPECT_TRUE(invalidRect.isNothing());
+ }
+ });
+}
+
+TEST(ImageADAM7InterpolatingFilter, WritePixels100_100)
+{ CheckADAM7InterpolatingWritePixels(IntSize(100, 100)); }
+
+TEST(ImageADAM7InterpolatingFilter, WritePixels99_99)
+{ CheckADAM7InterpolatingWritePixels(IntSize(99, 99)); }
+
+TEST(ImageADAM7InterpolatingFilter, WritePixels66_33)
+{ CheckADAM7InterpolatingWritePixels(IntSize(66, 33)); }
+
+TEST(ImageADAM7InterpolatingFilter, WritePixels33_66)
+{ CheckADAM7InterpolatingWritePixels(IntSize(33, 66)); }
+
+TEST(ImageADAM7InterpolatingFilter, WritePixels15_15)
+{ CheckADAM7InterpolatingWritePixels(IntSize(15, 15)); }
+
+TEST(ImageADAM7InterpolatingFilter, WritePixels9_9)
+{ CheckADAM7InterpolatingWritePixels(IntSize(9, 9)); }
+
+TEST(ImageADAM7InterpolatingFilter, WritePixels8_8)
+{ CheckADAM7InterpolatingWritePixels(IntSize(8, 8)); }
+
+TEST(ImageADAM7InterpolatingFilter, WritePixels7_7)
+{ CheckADAM7InterpolatingWritePixels(IntSize(7, 7)); }
+
+TEST(ImageADAM7InterpolatingFilter, WritePixels3_3)
+{ CheckADAM7InterpolatingWritePixels(IntSize(3, 3)); }
+
+TEST(ImageADAM7InterpolatingFilter, WritePixels1_1)
+{ CheckADAM7InterpolatingWritePixels(IntSize(1, 1)); }
+
+TEST(ImageADAM7InterpolatingFilter, TrivialInterpolation48_48)
+{ CheckInterpolation(IntSize(48, 48), {BGRAColor::Green()}); }
+
+TEST(ImageADAM7InterpolatingFilter, InterpolationOutput33_17)
+{
+ // We check interpolation using irregular patterns to make sure that the
+ // interpolation will look different for different passes.
+ CheckInterpolation(
+ IntSize(33, 17),
+ {BGRAColor::Green(), BGRAColor::Red(), BGRAColor::Green(),
+ BGRAColor::Blue(), BGRAColor::Blue(), BGRAColor::Blue(),
+ BGRAColor::Red(), BGRAColor::Green(), BGRAColor::Red(),
+ BGRAColor::Red(), BGRAColor::Blue(), BGRAColor::Blue(),
+ BGRAColor::Green(), BGRAColor::Blue(), BGRAColor::Red(),
+ BGRAColor::Blue(), BGRAColor::Red(), BGRAColor::Green(),
+ BGRAColor::Blue(), BGRAColor::Red(), BGRAColor::Green(),
+ BGRAColor::Red(), BGRAColor::Red(), BGRAColor::Blue(),
+ BGRAColor::Blue(), BGRAColor::Blue(), BGRAColor::Red(),
+ BGRAColor::Green(), BGRAColor::Green(), BGRAColor::Blue(),
+ BGRAColor::Red(), BGRAColor::Blue()});
+}
+
+TEST(ImageADAM7InterpolatingFilter, InterpolationOutput32_16)
+{
+ CheckInterpolation(
+ IntSize(32, 16),
+ {BGRAColor::Green(), BGRAColor::Red(), BGRAColor::Green(),
+ BGRAColor::Blue(), BGRAColor::Blue(), BGRAColor::Blue(),
+ BGRAColor::Red(), BGRAColor::Green(), BGRAColor::Red(),
+ BGRAColor::Red(), BGRAColor::Blue(), BGRAColor::Blue(),
+ BGRAColor::Green(), BGRAColor::Blue(), BGRAColor::Red(),
+ BGRAColor::Blue(), BGRAColor::Red(), BGRAColor::Green(),
+ BGRAColor::Blue(), BGRAColor::Red(), BGRAColor::Green(),
+ BGRAColor::Red(), BGRAColor::Red(), BGRAColor::Blue(),
+ BGRAColor::Blue(), BGRAColor::Blue(), BGRAColor::Red(),
+ BGRAColor::Green(), BGRAColor::Green(), BGRAColor::Blue(),
+ BGRAColor::Red(), BGRAColor::Blue()});
+}
+
+TEST(ImageADAM7InterpolatingFilter, InterpolationOutput31_15)
+{
+ CheckInterpolation(
+ IntSize(31, 15),
+ {BGRAColor::Green(), BGRAColor::Red(), BGRAColor::Green(),
+ BGRAColor::Blue(), BGRAColor::Blue(), BGRAColor::Blue(),
+ BGRAColor::Red(), BGRAColor::Green(), BGRAColor::Red(),
+ BGRAColor::Red(), BGRAColor::Blue(), BGRAColor::Blue(),
+ BGRAColor::Green(), BGRAColor::Blue(), BGRAColor::Red(),
+ BGRAColor::Blue(), BGRAColor::Red(), BGRAColor::Green(),
+ BGRAColor::Blue(), BGRAColor::Red(), BGRAColor::Green(),
+ BGRAColor::Red(), BGRAColor::Red(), BGRAColor::Blue(),
+ BGRAColor::Blue(), BGRAColor::Blue(), BGRAColor::Red(),
+ BGRAColor::Green(), BGRAColor::Green(), BGRAColor::Blue(),
+ BGRAColor::Red(), BGRAColor::Blue()});
+}
+
+TEST(ImageADAM7InterpolatingFilter, InterpolationOutput17_33)
+{
+ CheckInterpolation(IntSize(17, 33),
+ {BGRAColor::Green(), BGRAColor::Red(), BGRAColor::Green(),
+ BGRAColor::Blue(), BGRAColor::Red(), BGRAColor::Green(),
+ BGRAColor::Blue(), BGRAColor::Red(), BGRAColor::Blue(),
+ BGRAColor::Blue(), BGRAColor::Red(), BGRAColor::Green(),
+ BGRAColor::Green(), BGRAColor::Red(), BGRAColor::Red(),
+ BGRAColor::Blue()});
+}
+
+TEST(ImageADAM7InterpolatingFilter, InterpolationOutput16_32)
+{
+ CheckInterpolation(IntSize(16, 32),
+ {BGRAColor::Green(), BGRAColor::Red(), BGRAColor::Green(),
+ BGRAColor::Blue(), BGRAColor::Red(), BGRAColor::Green(),
+ BGRAColor::Blue(), BGRAColor::Red(), BGRAColor::Blue(),
+ BGRAColor::Blue(), BGRAColor::Red(), BGRAColor::Green(),
+ BGRAColor::Green(), BGRAColor::Red(), BGRAColor::Red(),
+ BGRAColor::Blue()});
+}
+
+TEST(ImageADAM7InterpolatingFilter, InterpolationOutput15_31)
+{
+ CheckInterpolation(IntSize(15, 31),
+ {BGRAColor::Green(), BGRAColor::Red(), BGRAColor::Green(),
+ BGRAColor::Blue(), BGRAColor::Red(), BGRAColor::Green(),
+ BGRAColor::Blue(), BGRAColor::Red(), BGRAColor::Blue(),
+ BGRAColor::Blue(), BGRAColor::Red(), BGRAColor::Green(),
+ BGRAColor::Green(), BGRAColor::Red(), BGRAColor::Red(),
+ BGRAColor::Blue()});
+}
+
+TEST(ImageADAM7InterpolatingFilter, InterpolationOutput9_9)
+{
+ CheckInterpolation(IntSize(9, 9),
+ {BGRAColor::Blue(), BGRAColor::Blue(), BGRAColor::Red(),
+ BGRAColor::Green(), BGRAColor::Green(), BGRAColor::Red(),
+ BGRAColor::Red(), BGRAColor::Blue()});
+}
+
+TEST(ImageADAM7InterpolatingFilter, InterpolationOutput8_8)
+{
+ CheckInterpolation(IntSize(8, 8),
+ {BGRAColor::Blue(), BGRAColor::Blue(), BGRAColor::Red(),
+ BGRAColor::Green(), BGRAColor::Green(), BGRAColor::Red(),
+ BGRAColor::Red(), BGRAColor::Blue()});
+}
+
+TEST(ImageADAM7InterpolatingFilter, InterpolationOutput7_7)
+{
+ CheckInterpolation(IntSize(7, 7),
+ {BGRAColor::Blue(), BGRAColor::Blue(), BGRAColor::Red(),
+ BGRAColor::Green(), BGRAColor::Green(), BGRAColor::Red(),
+ BGRAColor::Red(), BGRAColor::Blue()});
+}
+
+TEST(ImageADAM7InterpolatingFilter, InterpolationOutput3_3)
+{
+ CheckInterpolation(IntSize(3, 3), {BGRAColor::Green(), BGRAColor::Red(),
+ BGRAColor::Blue(), BGRAColor::Red()});
+}
+
+TEST(ImageADAM7InterpolatingFilter, InterpolationOutput1_1)
+{ CheckInterpolation(IntSize(1, 1), {BGRAColor::Blue()}); }
+
+TEST(ImageADAM7InterpolatingFilter, ADAM7InterpolationFailsFor0_0)
+{
+ // A 0x0 input size is invalid, so configuration should fail.
+ AssertConfiguringADAM7InterpolatingFilterFails(IntSize(0, 0));
+}
+
+TEST(ImageADAM7InterpolatingFilter, ADAM7InterpolationFailsForMinus1_Minus1)
+{
+ // A negative input size is invalid, so configuration should fail.
+ AssertConfiguringADAM7InterpolatingFilterFails(IntSize(-1, -1));
+}