enc_squeeze.cc (5283B)
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/modular/transform/enc_squeeze.h" 7 8 #include <jxl/memory_manager.h> 9 10 #include <cstdlib> 11 12 #include "lib/jxl/base/data_parallel.h" 13 #include "lib/jxl/modular/modular_image.h" 14 #include "lib/jxl/modular/transform/squeeze.h" 15 #include "lib/jxl/modular/transform/transform.h" 16 17 namespace jxl { 18 19 #define AVERAGE(X, Y) (((X) + (Y) + (((X) > (Y)) ? 1 : 0)) >> 1) 20 21 Status FwdHSqueeze(Image &input, int c, int rc) { 22 const Channel &chin = input.channel[c]; 23 JxlMemoryManager *memory_manager = input.memory_manager(); 24 25 JXL_DEBUG_V(4, "Doing horizontal squeeze of channel %i to new channel %i", c, 26 rc); 27 28 JXL_ASSIGN_OR_RETURN(Channel chout, 29 Channel::Create(memory_manager, (chin.w + 1) / 2, chin.h, 30 chin.hshift + 1, chin.vshift)); 31 JXL_ASSIGN_OR_RETURN(Channel chout_residual, 32 Channel::Create(memory_manager, chin.w - chout.w, 33 chout.h, chin.hshift + 1, chin.vshift)); 34 35 for (size_t y = 0; y < chout.h; y++) { 36 const pixel_type *JXL_RESTRICT p_in = chin.Row(y); 37 pixel_type *JXL_RESTRICT p_out = chout.Row(y); 38 pixel_type *JXL_RESTRICT p_res = chout_residual.Row(y); 39 for (size_t x = 0; x < chout_residual.w; x++) { 40 pixel_type A = p_in[x * 2]; 41 pixel_type B = p_in[x * 2 + 1]; 42 pixel_type avg = AVERAGE(A, B); 43 p_out[x] = avg; 44 45 pixel_type diff = A - B; 46 47 pixel_type next_avg = avg; 48 if (x + 1 < chout_residual.w) { 49 pixel_type C = p_in[x * 2 + 2]; 50 pixel_type D = p_in[x * 2 + 3]; 51 next_avg = AVERAGE(C, D); // which will be chout.value(y,x+1) 52 } else if (chin.w & 1) { 53 next_avg = p_in[x * 2 + 2]; 54 } 55 pixel_type left = (x > 0 ? p_in[x * 2 - 1] : avg); 56 pixel_type tendency = SmoothTendency(left, avg, next_avg); 57 58 p_res[x] = diff - tendency; 59 } 60 if (chin.w & 1) { 61 int x = chout.w - 1; 62 p_out[x] = p_in[x * 2]; 63 } 64 } 65 input.channel[c] = std::move(chout); 66 input.channel.insert(input.channel.begin() + rc, std::move(chout_residual)); 67 return true; 68 } 69 70 Status FwdVSqueeze(Image &input, int c, int rc) { 71 const Channel &chin = input.channel[c]; 72 JxlMemoryManager *memory_manager = input.memory_manager(); 73 74 JXL_DEBUG_V(4, "Doing vertical squeeze of channel %i to new channel %i", c, 75 rc); 76 77 JXL_ASSIGN_OR_RETURN(Channel chout, 78 Channel::Create(memory_manager, chin.w, (chin.h + 1) / 2, 79 chin.hshift, chin.vshift + 1)); 80 JXL_ASSIGN_OR_RETURN(Channel chout_residual, 81 Channel::Create(memory_manager, chin.w, chin.h - chout.h, 82 chin.hshift, chin.vshift + 1)); 83 intptr_t onerow_in = chin.plane.PixelsPerRow(); 84 for (size_t y = 0; y < chout_residual.h; y++) { 85 const pixel_type *JXL_RESTRICT p_in = chin.Row(y * 2); 86 pixel_type *JXL_RESTRICT p_out = chout.Row(y); 87 pixel_type *JXL_RESTRICT p_res = chout_residual.Row(y); 88 for (size_t x = 0; x < chout.w; x++) { 89 pixel_type A = p_in[x]; 90 pixel_type B = p_in[x + onerow_in]; 91 pixel_type avg = AVERAGE(A, B); 92 p_out[x] = avg; 93 94 pixel_type diff = A - B; 95 96 pixel_type next_avg = avg; 97 if (y + 1 < chout_residual.h) { 98 pixel_type C = p_in[x + 2 * onerow_in]; 99 pixel_type D = p_in[x + 3 * onerow_in]; 100 next_avg = AVERAGE(C, D); // which will be chout.value(y+1,x) 101 } else if (chin.h & 1) { 102 next_avg = p_in[x + 2 * onerow_in]; 103 } 104 pixel_type top = 105 (y > 0 ? p_in[static_cast<ssize_t>(x) - onerow_in] : avg); 106 pixel_type tendency = SmoothTendency(top, avg, next_avg); 107 108 p_res[x] = diff - tendency; 109 } 110 } 111 if (chin.h & 1) { 112 size_t y = chout.h - 1; 113 const pixel_type *p_in = chin.Row(y * 2); 114 pixel_type *p_out = chout.Row(y); 115 for (size_t x = 0; x < chout.w; x++) { 116 p_out[x] = p_in[x]; 117 } 118 } 119 input.channel[c] = std::move(chout); 120 input.channel.insert(input.channel.begin() + rc, std::move(chout_residual)); 121 return true; 122 } 123 124 Status FwdSqueeze(Image &input, std::vector<SqueezeParams> parameters, 125 ThreadPool *pool) { 126 if (parameters.empty()) { 127 DefaultSqueezeParameters(¶meters, input); 128 } 129 // if nothing to do, don't do squeeze 130 if (parameters.empty()) return false; 131 for (auto ¶meter : parameters) { 132 JXL_RETURN_IF_ERROR( 133 CheckMetaSqueezeParams(parameter, input.channel.size())); 134 bool horizontal = parameter.horizontal; 135 bool in_place = parameter.in_place; 136 uint32_t beginc = parameter.begin_c; 137 uint32_t endc = parameter.begin_c + parameter.num_c - 1; 138 uint32_t offset; 139 if (in_place) { 140 offset = endc + 1; 141 } else { 142 offset = input.channel.size(); 143 } 144 for (uint32_t c = beginc; c <= endc; c++) { 145 if (horizontal) { 146 JXL_RETURN_IF_ERROR(FwdHSqueeze(input, c, offset + c - beginc)); 147 } else { 148 JXL_RETURN_IF_ERROR(FwdVSqueeze(input, c, offset + c - beginc)); 149 } 150 } 151 } 152 return true; 153 } 154 155 } // namespace jxl