diff options
Diffstat (limited to '')
-rw-r--r-- | image/test/gtest/TestADAM7InterpolatingFilter.cpp | 595 |
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)); +} |