image_ops_test.cc (4292B)
1 // Copyright (c) the JPEG XL Project Authors. All rights reserved. 2 // 3 // Use of this source code is governed by a BSD-style 4 // license that can be found in the LICENSE file. 5 6 #include "lib/jxl/image_ops.h" 7 8 #include <stdint.h> 9 #include <stdlib.h> 10 11 #include <cstring> 12 13 #include "lib/jxl/base/compiler_specific.h" 14 #include "lib/jxl/base/printf_macros.h" 15 #include "lib/jxl/base/random.h" 16 #include "lib/jxl/base/status.h" 17 #include "lib/jxl/cache_aligned.h" 18 #include "lib/jxl/image.h" 19 #include "lib/jxl/testing.h" 20 21 namespace jxl { 22 namespace { 23 24 // Ensure entire payload is readable/writable for various size/offset combos. 25 TEST(ImageTest, TestAllocator) { 26 Rng rng(0); 27 const size_t k32 = 32; 28 const size_t kAlign = CacheAligned::kAlignment; 29 for (size_t size : {k32 * 1, k32 * 2, k32 * 3, k32 * 4, k32 * 5, 30 CacheAligned::kAlias, 2 * CacheAligned::kAlias + 4}) { 31 for (size_t offset = 0; offset <= CacheAligned::kAlias; offset += kAlign) { 32 uint8_t* bytes = 33 static_cast<uint8_t*>(CacheAligned::Allocate(size, offset)); 34 JXL_CHECK(reinterpret_cast<uintptr_t>(bytes) % kAlign == 0); 35 // Ensure we can write/read the last byte. Use RNG to fool the compiler 36 // into thinking the write is necessary. 37 memset(bytes, 0, size); 38 bytes[size - 1] = 1; // greatest element 39 uint32_t pos = rng.UniformU(0, size - 1); // random but != greatest 40 JXL_CHECK(bytes[pos] < bytes[size - 1]); 41 42 CacheAligned::Free(bytes); 43 } 44 } 45 } 46 47 template <typename T> 48 void TestFillImpl(Image3<T>* img, const char* layout) { 49 FillImage(static_cast<T>(1), img); 50 for (size_t y = 0; y < img->ysize(); ++y) { 51 for (size_t c = 0; c < 3; ++c) { 52 T* JXL_RESTRICT row = img->PlaneRow(c, y); 53 for (size_t x = 0; x < img->xsize(); ++x) { 54 if (row[x] != static_cast<T>(1)) { 55 printf("Not 1 at c=%" PRIuS " %" PRIuS ", %" PRIuS " (%" PRIuS 56 " x %" PRIuS ") (%s)\n", 57 c, x, y, img->xsize(), img->ysize(), layout); 58 abort(); 59 } 60 row[x] = static_cast<T>(2); 61 } 62 } 63 } 64 65 // Same for ZeroFillImage and swapped c/y loop ordering. 66 ZeroFillImage(img); 67 for (size_t c = 0; c < 3; ++c) { 68 for (size_t y = 0; y < img->ysize(); ++y) { 69 T* JXL_RESTRICT row = img->PlaneRow(c, y); 70 for (size_t x = 0; x < img->xsize(); ++x) { 71 if (row[x] != static_cast<T>(0)) { 72 printf("Not 0 at c=%" PRIuS " %" PRIuS ", %" PRIuS " (%" PRIuS 73 " x %" PRIuS ") (%s)\n", 74 c, x, y, img->xsize(), img->ysize(), layout); 75 abort(); 76 } 77 row[x] = static_cast<T>(3); 78 } 79 } 80 } 81 } 82 83 template <typename T> 84 void TestFillT() { 85 for (uint32_t xsize : {0, 1, 15, 16, 31, 32}) { 86 for (uint32_t ysize : {0, 1, 15, 16, 31, 32}) { 87 JXL_ASSIGN_OR_DIE(Image3<T> image, Image3<T>::Create(xsize, ysize)); 88 TestFillImpl(&image, "size ctor"); 89 } 90 } 91 } 92 93 // Ensure y/c/x and c/y/x loops visit pixels no more than once. 94 TEST(ImageTest, TestFill) { 95 TestFillT<uint8_t>(); 96 TestFillT<int16_t>(); 97 TestFillT<float>(); 98 TestFillT<double>(); 99 } 100 101 TEST(ImageTest, CopyImageToWithPaddingTest) { 102 JXL_ASSIGN_OR_DIE(Plane<uint32_t> src, Plane<uint32_t>::Create(100, 61)); 103 for (size_t y = 0; y < src.ysize(); y++) { 104 for (size_t x = 0; x < src.xsize(); x++) { 105 src.Row(y)[x] = x * 1000 + y; 106 } 107 } 108 Rect src_rect(10, 20, 30, 40); 109 EXPECT_TRUE(src_rect.IsInside(src)); 110 111 JXL_ASSIGN_OR_DIE(Plane<uint32_t> dst, Plane<uint32_t>::Create(60, 50)); 112 FillImage(0u, &dst); 113 Rect dst_rect(20, 5, 30, 40); 114 EXPECT_TRUE(dst_rect.IsInside(dst)); 115 116 CopyImageToWithPadding(src_rect, src, /*padding=*/2, dst_rect, &dst); 117 118 // ysize is + 3 instead of + 4 because we are at the y image boundary on the 119 // source image. 120 Rect padded_dst_rect(20 - 2, 5 - 2, 30 + 4, 40 + 3); 121 for (size_t y = 0; y < dst.ysize(); y++) { 122 for (size_t x = 0; x < dst.xsize(); x++) { 123 if (Rect(x, y, 1, 1).IsInside(padded_dst_rect)) { 124 EXPECT_EQ((x - dst_rect.x0() + src_rect.x0()) * 1000 + 125 (y - dst_rect.y0() + src_rect.y0()), 126 dst.Row(y)[x]); 127 } else { 128 EXPECT_EQ(0u, dst.Row(y)[x]); 129 } 130 } 131 } 132 } 133 134 } // namespace 135 } // namespace jxl