/* * Copyright 2024 Google LLC. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #include "include/codec/SkCodec.h" #include "include/core/SkBitmap.h" #include "include/core/SkColor.h" #include "include/core/SkData.h" #include "include/core/SkImage.h" #include "include/core/SkImageGenerator.h" #include "include/core/SkImageInfo.h" #include "include/core/SkM44.h" #include "include/core/SkRefCnt.h" #include "include/core/SkStream.h" #include "src/base/SkAutoMalloc.h" #include "src/codec/SkCodecImageGenerator.h" #include "src/codec/SkPixmapUtilsPriv.h" #include "src/image/SkImageGeneratorPriv.h" #include "tests/Test.h" #include "tools/Resources.h" #if defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS) #include "include/ports/SkImageGeneratorCG.h" #elif defined(SK_BUILD_FOR_WIN) #include "include/ports/SkImageGeneratorWIC.h" #include "src/utils/win/SkAutoCoInitialize.h" #elif defined(SK_ENABLE_NDK_IMAGES) #include "include/ports/SkImageGeneratorNDK.h" #endif static bool nearly_equal(SkColor4f a, SkColor4f b) { float d = SkV3{a.fR - b.fR, a.fG - b.fG, a.fB - b.fB}.length(); static constexpr float kTol = 0.02f; return d <= kTol; } DEF_TEST(ImageGeneratorOrientationTest, reporter) { #if defined(SK_BUILD_FOR_WIN) SkAutoCoInitialize com; REPORTER_ASSERT(reporter, com.succeeded()); #endif for (char i = '1'; i <= '8'; i++) { SkString path = SkStringPrintf("images/orientation/%c_444.jpg", i); // Get the image as data sk_sp data(GetResourceAsData(path.c_str())); std::unique_ptr gen; #if defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS) gen = SkImageGeneratorCG::MakeFromEncodedCG(data); #elif defined(SK_BUILD_FOR_WIN) gen = SkImageGeneratorWIC::MakeFromEncodedWIC(data); #elif defined(SK_ENABLE_NDK_IMAGES) gen = SkImageGeneratorNDK::MakeFromEncodedNDK(data); #else gen = SkCodecImageGenerator::MakeFromEncodedCodec(data); #endif REPORTER_ASSERT(reporter, gen); bool success; // Get bitmap from image generator. SkImageInfo genInfo = gen->getInfo(); SkBitmap genBitmap; success = genBitmap.tryAllocPixels(genInfo); SkPixmap genPM = genBitmap.pixmap(); REPORTER_ASSERT(reporter, genPM.addr()); success = gen->getPixels(genPM); REPORTER_ASSERT(reporter, success); // Get bitmap from codec. SkCodec::getPixels does not automatically apply // the origin so we rotate it manually. SkBitmap codecBitmap; std::unique_ptr stream(GetResourceAsStream(path.c_str())); std::unique_ptr codec(SkCodec::MakeFromStream(std::move(stream))); REPORTER_ASSERT(reporter, codec); SkImageInfo codecInfo = codec->getInfo(); SkEncodedOrigin origin = codec->getOrigin(); success = codecBitmap.tryAllocPixels(codecInfo); REPORTER_ASSERT(reporter, success); SkCodec::Result result = codec->getPixels(codecInfo, codecBitmap.getPixels(), codecBitmap.rowBytes()); REPORTER_ASSERT(reporter, result == SkCodec::kSuccess); SkBitmap tmpBitmap; if (SkEncodedOriginSwapsWidthHeight(origin)) { codecInfo = SkPixmapUtils::SwapWidthHeight(codecInfo); } success = tmpBitmap.tryAllocPixels(codecInfo); REPORTER_ASSERT(reporter, success); success = SkPixmapUtils::Orient(tmpBitmap.pixmap(), codecBitmap.pixmap(), origin); REPORTER_ASSERT(reporter, success); codecBitmap.swap(tmpBitmap); // Compare the decoded SkCodec and the bits from the SkImageGenerator. // They should be the same because both should respect orientation. if (codecBitmap.dimensions() != genInfo.dimensions()) { ERRORF(reporter, "Bitmaps do not have the same dimentions.\n" "\tgenBitmap: (%i, %i)\tcodecBitmap: (%i, %i)", codecBitmap.dimensions().fWidth, codecBitmap.dimensions().fHeight, genBitmap.dimensions().fWidth, genBitmap.dimensions().fHeight); } for (int k = 0; k < codecBitmap.width(); ++k) { for (int j = 0; j < codecBitmap.height(); ++j) { SkColor4f c1 = genBitmap.getColor4f(k, j); SkColor4f c2 = codecBitmap.getColor4f(k, j); if (!nearly_equal(c1, c2)) { ERRORF(reporter, "Bitmaps for %s do not match starting at position %i, %i\n" "\tgenBitmap: %x\tcodecBitmap: %x", path.c_str(), i, j, c1.toSkColor(), c2.toSkColor()); return; } } } } }