Skip to content

Commit 3dd8718

Browse files
committed
added lanczos sampler
1 parent 78dfd5b commit 3dd8718

File tree

5 files changed

+122
-31
lines changed

5 files changed

+122
-31
lines changed

JxlCoder.podspec

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
Pod::Spec.new do |s|
22
s.name = 'JxlCoder'
3-
s.version = '1.1.7'
3+
s.version = '1.1.8'
44
s.summary = 'JXL coder for iOS and MacOS'
55
s.description = 'Provides support for JXL files in iOS and MacOS'
66
s.homepage = 'https://github.com/awxkee/jxl-coder-swift'

Sources/jxlc/JxlInternalCoder.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,8 @@ typedef NS_ENUM(NSInteger, JxlSampler) {
4949
kNearestNeighbor NS_SWIFT_NAME(nearestNeighbor),
5050
kBilinear NS_SWIFT_NAME(bilinear),
5151
kCubic NS_SWIFT_NAME(cubic),
52-
kMitchell NS_SWIFT_NAME(mitchell)
52+
kMitchell NS_SWIFT_NAME(mitchell),
53+
kLanczos NS_SWIFT_NAME(lanczos)
5354
};
5455

5556
@interface JxlInternalCoder: NSObject

Sources/jxlc/JxlInternalCoder.mm

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,9 @@ - (nullable JXLSystemImage *)decode:(nonnull NSInputStream *)inputStream
284284
case kMitchell:
285285
xSampler = mitchell;
286286
break;
287+
case kLanczos:
288+
xSampler = lanczos;
289+
break;
287290
}
288291

289292
auto scaleResult = [RgbaScaler scaleData:outputData width:(int)xSize height:(int)ySize

Sources/jxlc/XScaler.hpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@ enum XSampler {
1717
bilinear = 1,
1818
nearest = 2,
1919
cubic = 3,
20-
mitchell = 4
20+
mitchell = 4,
21+
lanczos = 5
2122
};
2223

2324
void scaleImageFloat16(uint16_t* input,

Sources/jxlc/XScaler.mm

Lines changed: 114 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -27,38 +27,48 @@
2727

2828
template <typename T>
2929
inline T CubicBSpline(T t) {
30-
T absX = std::abs(t);
30+
T absX = abs(t);
3131
if (absX <= 1.0) {
32-
return (2.0 / 3.0) - (absX * absX) + (0.5 * absX * absX * absX);
32+
return T(2.0 / 3.0) - (absX * absX) + (T(0.5) * absX * absX * absX);
3333
} else if (absX <= 2.0) {
34-
return ((2.0 - absX) * (2.0 - absX) * (2.0 - absX)) / 6.0;
34+
return ((T(2.0) - absX) * (T(2.0) - absX) * (T(2.0) - absX)) / T(6.0);
3535
} else {
36-
return 0.0;
36+
return T(0.0);
3737
}
3838
}
3939

40-
inline half FilterMitchell(half t) {
41-
half x = abs(t);
40+
template <typename T>
41+
inline T FilterMitchell(T t) {
42+
T x = abs(t);
4243

4344
if (x < 1.0f)
44-
return (half(16) + x*x*(half(21) * x - half(36)))/half(18);
45+
return (T(16) + x*x*(T(21) * x - T(36)))/T(18);
4546
else if (x < 2.0f)
46-
return (half(32) + x*(half(-60) + x*(half(36) - half(7)*x)))/half(18);
47+
return (T(32) + x*(T(-60) + x*(T(36) - T(7)*x)))/T(18);
4748

48-
return half(0.0f);
49+
return T(0.0f);
4950
}
5051

51-
inline half CubicBSpline(half t) {
52-
half absX = abs(t);
53-
if (absX <= 1.0) {
54-
return half(2.0 / 3.0) - (absX * absX) + (half(0.5) * absX * absX * absX);
55-
} else if (absX <= 2.0) {
56-
return ((half(2.0) - absX) * (half(2.0) - absX) * (half(2.0) - absX)) / half(6.0);
52+
template <typename T>
53+
T sinc(T x) {
54+
if (x == 0.0) {
55+
return T(1.0);
5756
} else {
58-
return half(0.0);
57+
return sin(T(M_PI) * x) / (T(M_PI) * x);
5958
}
6059
}
6160

61+
template <typename T>
62+
inline T lanczosWindow(T x, T a) {
63+
if (x == 0.0) {
64+
return T(1.0);
65+
}
66+
if (abs(x) < a) {
67+
return a * sin(T(M_PI) * x) * sin(T(M_PI) * x / a) / (T(M_PI) * T(M_PI) * x * x);
68+
}
69+
return T(0.0);
70+
}
71+
6272
void scaleImageFloat16(uint16_t* input,
6373
int srcStride,
6474
int inputWidth, int inputHeight,
@@ -153,6 +163,32 @@ void scaleImageFloat16(uint16_t* input,
153163
}
154164
}
155165

166+
for (int c = 0; c < components; ++c) {
167+
dst16[x*components + c] = rgb[c].data_;
168+
}
169+
} else if (option == lanczos) {
170+
half rgb[components];
171+
172+
int a = 3;
173+
float lanczosFA = float(3.0f);
174+
175+
for (int j = -a + 1; j <= a; j++) {
176+
for (int i = -a + 1; i <= a; i++) {
177+
int xi = x1 + i;
178+
int yj = y1 + j;
179+
180+
if (xi >= 0 && xi < inputWidth && yj >= 0 && yj < inputHeight) {
181+
float weight = lanczosWindow(float(srcX - xi), (float)lanczosFA) * lanczosWindow(float(srcY - yj), (float)lanczosFA);
182+
183+
for (int c = 0; c < components; ++c) {
184+
half clrf = castU16(reinterpret_cast<const uint16_t*>(src8 + yj * srcStride)[xi*components + c]);
185+
half clr = half((float)clrf * weight);
186+
rgb[c] += clr;
187+
}
188+
}
189+
}
190+
}
191+
156192
for (int c = 0; c < components; ++c) {
157193
dst16[x*components + c] = rgb[c].data_;
158194
}
@@ -253,9 +289,6 @@ void scaleImageU16(uint16_t* input,
253289
dst16[x*components + c] = static_cast<uint16_t>(f);
254290
}
255291
} else if (option == mitchell) {
256-
half dx = half(srcX - x);
257-
half dy = half(srcY - y);
258-
259292
half rgb[components];
260293

261294
for (int j = -1; j <= 2; j++) {
@@ -268,7 +301,7 @@ void scaleImageU16(uint16_t* input,
268301

269302
for (int c = 0; c < components; ++c) {
270303
uint16_t p = reinterpret_cast<const uint16_t*>(src8 + yj * srcStride)[xi*components + c];
271-
half clrf(p / maxColors);
304+
half clrf((float)p / maxColors);
272305
half clr = clrf * weight;
273306
rgb[c] += clr;
274307
}
@@ -282,7 +315,36 @@ void scaleImageU16(uint16_t* input,
282315
f = std::clamp(f, 0.0f, maxColors);
283316
dst16[x*components + c] = static_cast<uint16_t>(f);
284317
}
285-
} else {
318+
} else if (option == lanczos) {
319+
half rgb[components];
320+
321+
int a = 3;
322+
float lanczosKernel = 3.0;
323+
324+
for (int j = -a + 1; j <= a; j++) {
325+
for (int i = -a + 1; i <= a; i++) {
326+
int xi = x1 + i;
327+
int yj = y1 + j;
328+
329+
if (xi >= 0 && xi < inputWidth && yj >= 0 && yj < inputHeight) {
330+
float weight = lanczosWindow(float(srcX - xi), lanczosKernel) * lanczosWindow(float(srcY - yj), lanczosKernel);
331+
332+
for (int c = 0; c < components; ++c) {
333+
uint16_t p = reinterpret_cast<const uint16_t*>(src8 + yj * srcStride)[xi*components + c];
334+
half clrf((float)p / maxColors * weight);
335+
rgb[c] += clrf;
336+
}
337+
}
338+
}
339+
}
340+
341+
for (int c = 0; c < components; ++c) {
342+
float cc = rgb[c];
343+
float f = cc * maxColors;
344+
f = std::clamp(f, 0.0f, maxColors);
345+
dst16[x*components + c] = static_cast<uint16_t>(f);
346+
}
347+
} else {
286348
for (int c = 0; c < components; ++c) {
287349
dst16[x*components + c] = reinterpret_cast<const uint16_t*>(src8 + y1 * srcStride)[x1*components + c];
288350
}
@@ -345,9 +407,6 @@ void scaleImageU8(uint8_t* input,
345407

346408
}
347409
} else if (option == cubic) {
348-
half dx = half(srcX - x);
349-
half dy = half(srcY - y);
350-
351410
half rgb[components];
352411

353412
for (int j = -1; j <= 2; j++) {
@@ -375,9 +434,6 @@ void scaleImageU8(uint8_t* input,
375434
dst[x*components + c] = static_cast<uint16_t>(f);
376435
}
377436
} else if (option == mitchell) {
378-
half dx = half(srcX - x);
379-
half dy = half(srcY - y);
380-
381437
half rgb[components];
382438

383439
for (int j = -1; j <= 2; j++) {
@@ -390,14 +446,44 @@ void scaleImageU8(uint8_t* input,
390446

391447
for (int c = 0; c < components; ++c) {
392448
uint8_t p = reinterpret_cast<const uint8_t*>(src8 + yj * srcStride)[xi*components + c];
393-
half clrf(p / maxColors);
449+
half clrf((float)p / maxColors);
394450
half clr = clrf * weight;
395451
rgb[c] += clr;
396452
}
397453
}
398454
}
399455
}
400456

457+
for (int c = 0; c < components; ++c) {
458+
float cc = rgb[c];
459+
float f = cc * maxColors;
460+
f = std::clamp(f, 0.0f, maxColors);
461+
dst[x*components + c] = static_cast<uint16_t>(f);
462+
}
463+
} else if (option == lanczos) {
464+
half rgb[components];
465+
466+
float lanczosFA = float(3.0f);
467+
468+
int a = 3;
469+
470+
for (int j = -a + 1; j <= a; j++) {
471+
for (int i = -a + 1; i <= a; i++) {
472+
int xi = x1 + i;
473+
int yj = y1 + j;
474+
475+
if (xi >= 0 && xi < inputWidth && yj >= 0 && yj < inputHeight) {
476+
float weight = lanczosWindow(float(srcX - xi), lanczosFA) * lanczosWindow(float(srcY - yj), lanczosFA);
477+
478+
for (int c = 0; c < components; ++c) {
479+
uint8_t p = reinterpret_cast<const uint8_t*>(src8 + yj * srcStride)[xi*components + c];
480+
half clrf((float)p / maxColors * weight);
481+
rgb[c] += clrf;
482+
}
483+
}
484+
}
485+
}
486+
401487
for (int c = 0; c < components; ++c) {
402488
float cc = rgb[c];
403489
float f = cc * maxColors;

0 commit comments

Comments
 (0)