Skip to content

Commit e121c57

Browse files
committed
added low memory footprint scaler
1 parent 3dd8718 commit e121c57

File tree

5 files changed

+124
-13
lines changed

5 files changed

+124
-13
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.8'
3+
s.version = '1.1.9'
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
@@ -50,7 +50,8 @@ typedef NS_ENUM(NSInteger, JxlSampler) {
5050
kBilinear NS_SWIFT_NAME(bilinear),
5151
kCubic NS_SWIFT_NAME(cubic),
5252
kMitchell NS_SWIFT_NAME(mitchell),
53-
kLanczos NS_SWIFT_NAME(lanczos)
53+
kLanczos NS_SWIFT_NAME(lanczos),
54+
kCatmullRom NS_SWIFT_NAME(catmullRom)
5455
};
5556

5657
@interface JxlInternalCoder: NSObject

Sources/jxlc/JxlInternalCoder.mm

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,9 @@ - (nullable JXLSystemImage *)decode:(nonnull NSInputStream *)inputStream
287287
case kLanczos:
288288
xSampler = lanczos;
289289
break;
290+
case kCatmullRom:
291+
xSampler = catmullRom;
292+
break;
290293
}
291294

292295
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
@@ -18,7 +18,8 @@ enum XSampler {
1818
nearest = 2,
1919
cubic = 3,
2020
mitchell = 4,
21-
lanczos = 5
21+
lanczos = 5,
22+
catmullRom = 6,
2223
};
2324

2425
void scaleImageFloat16(uint16_t* input,

Sources/jxlc/XScaler.mm

Lines changed: 116 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include <algorithm>
1313

1414
using namespace half_float;
15+
using namespace std;
1516

1617
inline half_float::half castU16(uint16_t t) {
1718
half_float::half result;
@@ -69,6 +70,18 @@ inline T lanczosWindow(T x, T a) {
6970
return T(0.0);
7071
}
7172

73+
template <typename T>
74+
inline T CatmullRom(T x) {
75+
x = (float)fabs(x);
76+
77+
if (x < 1.0f)
78+
return T(1) - x*x*(T(2.5f) - T(1.5f)*x);
79+
else if (x < 2.0f)
80+
return T(2) - x*(T(4) + x*(T(0.5f)*x - T(2.5f)));
81+
82+
return T(0.0f);
83+
}
84+
7285
void scaleImageFloat16(uint16_t* input,
7386
int srcStride,
7487
int inputWidth, int inputHeight,
@@ -163,6 +176,33 @@ void scaleImageFloat16(uint16_t* input,
163176
}
164177
}
165178

179+
for (int c = 0; c < components; ++c) {
180+
dst16[x*components + c] = rgb[c].data_;
181+
}
182+
} else if (option == catmullRom) {
183+
184+
half rgb[components];
185+
186+
float kx1 = floor(srcX);
187+
float ky1 = floor(srcY);
188+
189+
for (int j = -1; j <= 2; j++) {
190+
for (int i = -1; i <= 2; i++) {
191+
int xi = kx1 + i;
192+
int yj = ky1 + j;
193+
194+
if (xi >= 0 && xi < inputWidth && yj >= 0 && yj < inputHeight) {
195+
half weight = CatmullRom(half(srcX - xi)) * CatmullRom(half(srcY - yj));
196+
197+
for (int c = 0; c < components; ++c) {
198+
half clrf = castU16(reinterpret_cast<const uint16_t*>(src8 + yj * srcStride)[xi*components + c]);
199+
half clr = clrf * weight;
200+
rgb[c] += clr;
201+
}
202+
}
203+
}
204+
}
205+
166206
for (int c = 0; c < components; ++c) {
167207
dst16[x*components + c] = rgb[c].data_;
168208
}
@@ -172,10 +212,13 @@ void scaleImageFloat16(uint16_t* input,
172212
int a = 3;
173213
float lanczosFA = float(3.0f);
174214

215+
float kx1 = floor(srcX);
216+
float ky1 = floor(srcY);
217+
175218
for (int j = -a + 1; j <= a; j++) {
176219
for (int i = -a + 1; i <= a; i++) {
177-
int xi = x1 + i;
178-
int yj = y1 + j;
220+
int xi = kx1 + i;
221+
int yj = ky1 + j;
179222

180223
if (xi >= 0 && xi < inputWidth && yj >= 0 && yj < inputHeight) {
181224
float weight = lanczosWindow(float(srcX - xi), (float)lanczosFA) * lanczosWindow(float(srcY - yj), (float)lanczosFA);
@@ -254,7 +297,7 @@ void scaleImageU16(uint16_t* input,
254297

255298
half result = (c1 + c2 + c3 + c4);
256299
float f = result * maxColors;
257-
f = std::clamp(f, 0.0f, maxColors);
300+
f = clamp(f, 0.0f, maxColors);
258301
dst16[x*components + c] = static_cast<uint16_t>(f);
259302
}
260303

@@ -285,7 +328,7 @@ void scaleImageU16(uint16_t* input,
285328
for (int c = 0; c < components; ++c) {
286329
float cc = rgb[c];
287330
float f = cc * maxColors;
288-
f = std::clamp(f, 0.0f, maxColors);
331+
f = clamp(f, 0.0f, maxColors);
289332
dst16[x*components + c] = static_cast<uint16_t>(f);
290333
}
291334
} else if (option == mitchell) {
@@ -312,7 +355,37 @@ void scaleImageU16(uint16_t* input,
312355
for (int c = 0; c < components; ++c) {
313356
float cc = rgb[c];
314357
float f = cc * maxColors;
315-
f = std::clamp(f, 0.0f, maxColors);
358+
f = clamp(f, 0.0f, maxColors);
359+
dst16[x*components + c] = static_cast<uint16_t>(f);
360+
}
361+
} else if (option == catmullRom) {
362+
half rgb[components];
363+
364+
float kx1 = floor(srcX);
365+
float ky1 = floor(srcY);
366+
367+
for (int j = -1; j <= 2; j++) {
368+
for (int i = -1; i <= 2; i++) {
369+
int xi = kx1 + i;
370+
int yj = ky1 + j;
371+
372+
if (xi >= 0 && xi < inputWidth && yj >= 0 && yj < inputHeight) {
373+
half weight = CatmullRom(half(srcX - xi)) * CatmullRom(half(srcY - yj));
374+
375+
for (int c = 0; c < components; ++c) {
376+
uint16_t p = reinterpret_cast<const uint16_t*>(src8 + yj * srcStride)[xi*components + c];
377+
half clrf((float)p / maxColors);
378+
half clr = clrf * weight;
379+
rgb[c] += clr;
380+
}
381+
}
382+
}
383+
}
384+
385+
for (int c = 0; c < components; ++c) {
386+
float cc = rgb[c];
387+
float f = cc * maxColors;
388+
f = clamp(f, 0.0f, maxColors);
316389
dst16[x*components + c] = static_cast<uint16_t>(f);
317390
}
318391
} else if (option == lanczos) {
@@ -341,7 +414,7 @@ void scaleImageU16(uint16_t* input,
341414
for (int c = 0; c < components; ++c) {
342415
float cc = rgb[c];
343416
float f = cc * maxColors;
344-
f = std::clamp(f, 0.0f, maxColors);
417+
f = clamp(f, 0.0f, maxColors);
345418
dst16[x*components + c] = static_cast<uint16_t>(f);
346419
}
347420
} else {
@@ -402,7 +475,7 @@ void scaleImageU8(uint8_t* input,
402475

403476
half result = (c1 + c2 + c3 + c4);
404477
float f = result * maxColors;
405-
f = std::clamp(f, 0.0f, maxColors);
478+
f = clamp(f, 0.0f, maxColors);
406479
dst[x*components + c] = static_cast<uint8_t>(f);
407480

408481
}
@@ -460,17 +533,50 @@ void scaleImageU8(uint8_t* input,
460533
f = std::clamp(f, 0.0f, maxColors);
461534
dst[x*components + c] = static_cast<uint16_t>(f);
462535
}
536+
} else if (option == catmullRom) {
537+
half rgb[components];
538+
539+
float kx1 = floor(srcX);
540+
float ky1 = floor(srcY);
541+
542+
for (int j = -1; j <= 2; j++) {
543+
for (int i = -1; i <= 2; i++) {
544+
int xi = kx1 + i;
545+
int yj = ky1 + j;
546+
547+
if (xi >= 0 && xi < inputWidth && yj >= 0 && yj < inputHeight) {
548+
half weight = CatmullRom(half(srcX - xi)) * CatmullRom(half(srcY - yj));
549+
550+
for (int c = 0; c < components; ++c) {
551+
uint8_t p = reinterpret_cast<const uint8_t*>(src8 + yj * srcStride)[xi*components + c];
552+
half clrf((float)p / maxColors);
553+
half clr = clrf * weight;
554+
rgb[c] += clr;
555+
}
556+
}
557+
}
558+
}
559+
560+
for (int c = 0; c < components; ++c) {
561+
float cc = rgb[c];
562+
float f = cc * maxColors;
563+
f = clamp(f, 0.0f, maxColors);
564+
dst[x*components + c] = static_cast<uint16_t>(f);
565+
}
463566
} else if (option == lanczos) {
464567
half rgb[components];
465568

466569
float lanczosFA = float(3.0f);
467570

468571
int a = 3;
469572

573+
float kx1 = floor(srcX);
574+
float ky1 = floor(srcY);
575+
470576
for (int j = -a + 1; j <= a; j++) {
471577
for (int i = -a + 1; i <= a; i++) {
472-
int xi = x1 + i;
473-
int yj = y1 + j;
578+
int xi = kx1 + i;
579+
int yj = ky1 + j;
474580

475581
if (xi >= 0 && xi < inputWidth && yj >= 0 && yj < inputHeight) {
476582
float weight = lanczosWindow(float(srcX - xi), lanczosFA) * lanczosWindow(float(srcY - yj), lanczosFA);
@@ -487,7 +593,7 @@ void scaleImageU8(uint8_t* input,
487593
for (int c = 0; c < components; ++c) {
488594
float cc = rgb[c];
489595
float f = cc * maxColors;
490-
f = std::clamp(f, 0.0f, maxColors);
596+
f = clamp(f, 0.0f, maxColors);
491597
dst[x*components + c] = static_cast<uint16_t>(f);
492598
}
493599
} else {

0 commit comments

Comments
 (0)