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