Skip to content

Commit

Permalink
added decoding speed
Browse files Browse the repository at this point in the history
  • Loading branch information
awxkee committed Nov 7, 2023
1 parent a4fd578 commit 05dc878
Show file tree
Hide file tree
Showing 11 changed files with 82 additions and 44 deletions.
2 changes: 1 addition & 1 deletion JxlCoder.podspec
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = 'JxlCoder'
s.version = '1.3.6'
s.version = '1.4.0'
s.summary = 'JXL coder for iOS and MacOS'
s.description = 'Provides support for JXL files in iOS and MacOS'
s.homepage = 'https://github.com/awxkee/jxl-coder-swift'
Expand Down
13 changes: 7 additions & 6 deletions Sources/JxlCoder/JXLAnimatedEncoder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,31 +29,32 @@ import jxlc
#endif

public class JXLAnimatedEncoder {

private let enc: CJpegXLAnimatedEncoder

public init(width: Int, height: Int,
numLoops: Int = 0, // 0 - means infinity
colorSpace: JXLColorSpace = .rgba,
compressionOption: JXLCompressionOption = .lossy,
effort: Int = 4, quality: Int = 0) throws {
effort: Int = 4, quality: Int = 0, decodingSpeed: JXLEncoderDecodingSpeed = .slowest) throws {
enc = try CJpegXLAnimatedEncoder(Int32(width),
height: Int32(height),
numLoops: Int32(numLoops),
colorSpace: colorSpace,
compressionOption: compressionOption,
effort: Int32(effort),
quality: Int32(quality))
quality: Int32(quality),
decodingSpeed: decodingSpeed)
}

/**
- Parameter frame: all the frames must match provided width and height in constructor
- Parameter duration: length of the frame in milliseconds
*/
public func add(frame: JXLPlatformImage, duration ms: Int) throws {
try enc.addFrame(frame, duration: Int32(ms))
}

public func finish() throws -> Data {
try enc.finish()
}
Expand Down
6 changes: 4 additions & 2 deletions Sources/JxlCoder/JXLCoder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -102,11 +102,13 @@ public class JXLCoder {
colorSpace: JXLColorSpace = .rgb,
compressionOption: JXLCompressionOption = .lossy,
effort: Int = 7,
quality: Int = 0) throws -> Data {
quality: Int = 0,
decodingSpeed: JXLEncoderDecodingSpeed = .slowest) throws -> Data {
return try shared.encode(image, colorSpace: colorSpace,
compressionOption: compressionOption,
effort: Int32(effort),
quality: Int32(quality))
quality: Int32(quality),
decodingSpeed: decodingSpeed)
}

/***
Expand Down
8 changes: 5 additions & 3 deletions Sources/jxlc/CJpegXLAnimatedEncoder.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,11 @@

@interface CJpegXLAnimatedEncoder : NSObject
-(nullable id)initWith:(int)width height:(int)height numLoops:(int)numLoops colorSpace:(JXLColorSpace)colorSpace
compressionOption:(JXLCompressionOption)compressionOption
effort:(int)effort
quality:(int)quality error:(NSError * _Nullable *_Nullable)error;
compressionOption:(JXLCompressionOption)compressionOption
effort:(int)effort
quality:(int)quality
decodingSpeed:(JXLEncoderDecodingSpeed)decodingSpeed
error:(NSError * _Nullable *_Nullable)error;
-(nullable void*)addFrame:(nonnull JXLSystemImage *)platformImage duration:(int)duration error:(NSError * _Nullable *_Nullable)error;
-(nullable NSData*)finish:(NSError * _Nullable *_Nullable)error;
@end
Expand Down
6 changes: 4 additions & 2 deletions Sources/jxlc/CJpegXLAnimatedEncoder.mm
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,9 @@ -(nullable id)initWith:(int)width height:(int)height
colorSpace:(JXLColorSpace)colorSpace
compressionOption:(JXLCompressionOption)compressionOption
effort:(int)effort
quality:(int)quality error:(NSError * _Nullable *_Nullable)error {
quality:(int)quality
decodingSpeed:(JXLEncoderDecodingSpeed)decodingSpeed
error:(NSError * _Nullable *_Nullable)error {
JxlPixelType jColorspace;
JxlCompressionOption jCompressionOption;

Expand All @@ -73,7 +75,7 @@ -(nullable id)initWith:(int)width height:(int)height
}

try {
enc = new JxlAnimatedEncoder(width, height, jColorspace, er8, jCompressionOption, numLoops, quality, effort);
enc = new JxlAnimatedEncoder(width, height, jColorspace, er8, jCompressionOption, numLoops, quality, effort, (int)decodingSpeed);
} catch (AnimatedEncoderError& err) {
NSString *str = [[NSString alloc] initWithCString:err.what() encoding:NSUTF8StringEncoding];
*error = [[NSError alloc] initWithDomain:@"JXLCoder" code:500 userInfo:@{ NSLocalizedDescriptionKey: str }];
Expand Down
8 changes: 8 additions & 0 deletions Sources/jxlc/JXLSystemImage.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,14 @@ typedef NS_ENUM(NSInteger, JxlSampler) {
kHann NS_SWIFT_NAME(hann)
};

typedef NS_ENUM(NSInteger, JXLEncoderDecodingSpeed) {
kSlowest NS_SWIFT_NAME(slowest) = 0,
kSlow NS_SWIFT_NAME(slow) = 1,
kMedium NS_SWIFT_NAME(medium) = 2,
kFast NS_SWIFT_NAME(fast) = 3,
kFastest NS_SWIFT_NAME(fastest) = 4
};

@interface JXLSystemImage (JXLColorData)
- (nullable uint8_t*)jxlRGBAPixels:(nonnull size_t*)bufferSize width:(nonnull int*)xSize height:(nonnull int*)ySize;
@end
Expand Down
8 changes: 7 additions & 1 deletion Sources/jxlc/JxlAnimatedEncoder.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ class JxlAnimatedEncoder {
JxlAnimatedEncoder(int width, int height, JxlPixelType pixelType,
JxlEncodingPixelFormat encodingPixelFormat,
JxlCompressionOption compressionOption,
int numLoops, int quality, int effort): width(width), height(height),
int numLoops, int quality, int effort, int decodingSpeed): width(width), height(height),
pixelType(pixelType), encodingPixelFormat(encodingPixelFormat),
compressionOption(compressionOption), quality(quality), effort(effort) {
if (!enc || !runner) {
Expand Down Expand Up @@ -166,6 +166,12 @@ class JxlAnimatedEncoder {
throw AnimatedEncoderError(str);
}

if (JXL_ENC_SUCCESS !=
JxlEncoderFrameSettingsSetOption(frameSettings, JXL_ENC_FRAME_SETTING_DECODING_SPEED, decodingSpeed)) {
std::string str = "Set decoding speed has failed";
throw AnimatedEncoderError(str);
}

if (pixelType == rgba) {
if (JXL_ENC_SUCCESS !=
JxlEncoderSetExtraChannelDistance(frameSettings, 0, JXLGetDistance(quality))) {
Expand Down
4 changes: 3 additions & 1 deletion Sources/jxlc/JxlInternalCoder.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,9 @@
colorSpace:(JXLColorSpace)colorSpace
compressionOption:(JXLCompressionOption)compressionOption
effort:(int)effort
quality:(int)quality error:(NSError * _Nullable *_Nullable)error;
quality:(int)quality
decodingSpeed:(JXLEncoderDecodingSpeed)decodingSpeed
error:(NSError * _Nullable *_Nullable)error;
@end

#endif /* JXLCoder_h */
52 changes: 28 additions & 24 deletions Sources/jxlc/JxlInternalCoder.mm
Original file line number Diff line number Diff line change
Expand Up @@ -47,19 +47,21 @@ static inline float JXLGetDistance(const int quality)
if (quality == 0)
return(1.0f);
float distance = quality >= 100 ? 0.0
: quality >= 30
? 0.1 + (100 - quality) * 0.09
: 53.0 / 3000.0 * quality * quality -
23.0 / 20.0 * quality + 25.0;
: quality >= 30
? 0.1 + (100 - quality) * 0.09
: 53.0 / 3000.0 * quality * quality -
23.0 / 20.0 * quality + 25.0;
return distance;
}

@implementation JxlInternalCoder
- (nullable NSData *)encode:(nonnull JXLSystemImage *)platformImage
colorSpace:(JXLColorSpace)colorSpace
compressionOption:(JXLCompressionOption)compressionOption
effort:(int)effort
quality:(int)quality error:(NSError * _Nullable *_Nullable)error {
colorSpace:(JXLColorSpace)colorSpace
compressionOption:(JXLCompressionOption)compressionOption
effort:(int)effort
quality:(int)quality
decodingSpeed:(JXLEncoderDecodingSpeed)decodingSpeed
error:(NSError * _Nullable *_Nullable)error {
try {
if (quality < 0 || quality > 100) {
*error = [[NSError alloc] initWithDomain:@"JXLCoder" code:500 userInfo:@{ NSLocalizedDescriptionKey: @"Quality must be clamped in 0...100" }];
Expand Down Expand Up @@ -117,7 +119,9 @@ - (nullable NSData *)encode:(nonnull JXLSystemImage *)platformImage
}

JXLDataWrapper<uint8_t>* wrapper = new JXLDataWrapper<uint8_t>();
auto encoded = EncodeJxlOneshot(pixels, width, height, &wrapper->data, jColorspace, jCompressionOption, JXLGetDistance(quality), effort);
auto encoded = EncodeJxlOneshot(pixels, width, height, &wrapper->data,
jColorspace, jCompressionOption, JXLGetDistance(quality),
effort, (int)decodingSpeed);
if (!encoded) {
delete wrapper;
*error = [[NSError alloc] initWithDomain:@"JXLCoder" code:500 userInfo:@{ NSLocalizedDescriptionKey: @"Cannot encode JXL image" }];
Expand All @@ -135,8 +139,8 @@ - (nullable NSData *)encode:(nonnull JXLSystemImage *)platformImage
return data;
} catch (std::bad_alloc &err) {
*error = [[NSError alloc] initWithDomain:@"JXLCoder"
code:500
userInfo:@{ NSLocalizedDescriptionKey: [NSString stringWithFormat:@"Encoding image memory error: %s", err.what()] }];
code:500
userInfo:@{ NSLocalizedDescriptionKey: [NSString stringWithFormat:@"Encoding image memory error: %s", err.what()] }];
return nullptr;
}
}
Expand Down Expand Up @@ -191,11 +195,11 @@ - (CGSize)getSize:(nonnull NSInputStream *)inputStream error:(NSError *_Nullable
}

- (nullable JXLSystemImage *)decode:(nonnull NSInputStream *)inputStream
rescale:(CGSize)rescale
pixelFormat:(JXLPreferredPixelFormat)preferredPixelFormat
sampler:(JxlSampler)sampler
scale:(int)scale
error:(NSError *_Nullable * _Nullable)error {
rescale:(CGSize)rescale
pixelFormat:(JXLPreferredPixelFormat)preferredPixelFormat
sampler:(JxlSampler)sampler
scale:(int)scale
error:(NSError *_Nullable * _Nullable)error {
try {
int buffer_length = 30196;
std::vector<uint8_t> buffer;
Expand Down Expand Up @@ -311,8 +315,8 @@ - (nullable JXLSystemImage *)decode:(nonnull NSInputStream *)inputStream
}

auto scaleResult = [RgbaScaler scaleData:outputData width:(int)xSize height:(int)ySize
newWidth:(int)rescale.width newHeight:(int)rescale.height
components:components pixelFormat:useFloats ? kF16 : kU8 sampler:xSampler];
newWidth:(int)rescale.width newHeight:(int)rescale.height
components:components pixelFormat:useFloats ? kF16 : kU8 sampler:xSampler];
if (!scaleResult) {
*error = [[NSError alloc] initWithDomain:@"JXLCoder" code:500 userInfo:@{ NSLocalizedDescriptionKey: @"Rescale image has failed" }];
return nil;
Expand Down Expand Up @@ -382,17 +386,17 @@ - (nullable JXLSystemImage *)decode:(nonnull NSInputStream *)inputStream
return NULL;
}
JXLSystemImage *image = nil;
#if JXL_PLUGIN_MAC
#if JXL_PLUGIN_MAC
image = [[NSImage alloc] initWithCGImage:imageRef size:CGSizeZero];
#else
#else
image = [UIImage imageWithCGImage:imageRef scale:scale orientation:UIImageOrientationUp];
#endif
#endif

return image;
} catch (std::bad_alloc &err) {
*error = [[NSError alloc] initWithDomain:@"JXLCoder"
code:500
userInfo:@{ NSLocalizedDescriptionKey: [NSString stringWithFormat:@"Decoding image memory error: %s", err.what()] }];
*error = [[NSError alloc] initWithDomain:@"JXLCoder"
code:500
userInfo:@{ NSLocalizedDescriptionKey: [NSString stringWithFormat:@"Decoding image memory error: %s", err.what()] }];
return nullptr;
}
}
Expand Down
12 changes: 10 additions & 2 deletions Sources/jxlc/JxlWorker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -232,8 +232,11 @@ bool DecodeBasicInfo(const uint8_t *jxl, size_t size, size_t *xsize, size_t *ysi
*/
bool EncodeJxlOneshot(const std::vector<uint8_t> &pixels, const uint32_t xsize,
const uint32_t ysize, std::vector<uint8_t> *compressed,
JxlPixelType colorspace, JxlCompressionOption compressionOption,
float compressionDistance, int effort) {
JxlPixelType colorspace,
JxlCompressionOption compressionOption,
float compressionDistance,
int effort,
int decodingSpeed) {
auto enc = JxlEncoderMake(nullptr);
auto runner = JxlThreadParallelRunnerMake(nullptr,
JxlThreadParallelRunnerDefaultNumWorkerThreads());
Expand Down Expand Up @@ -308,6 +311,11 @@ bool EncodeJxlOneshot(const std::vector<uint8_t> &pixels, const uint32_t xsize,
return false;
}

if (JXL_ENC_SUCCESS != JxlEncoderFrameSettingsSetOption(frameSettings,
JXL_ENC_FRAME_SETTING_DECODING_SPEED, decodingSpeed)) {
return false;
}

if (JXL_ENC_SUCCESS !=
JxlEncoderSetFrameDistance(frameSettings, compressionDistance)) {
return false;
Expand Down
7 changes: 5 additions & 2 deletions Sources/jxlc/JxlWorker.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,11 @@ bool DecodeJpegXlOneShot(const uint8_t *jxl, size_t size,
bool DecodeBasicInfo(const uint8_t *jxl, size_t size, size_t *xsize, size_t *ysize);
bool EncodeJxlOneshot(const std::vector<uint8_t> &pixels, const uint32_t xsize,
const uint32_t ysize, std::vector<uint8_t> *compressed,
JxlPixelType colorspace, JxlCompressionOption compression_option,
float compression_distance, int effort);
JxlPixelType colorspace,
JxlCompressionOption compressionOption,
float compressionDistance,
int effort,
int decodingSpeed);

bool isJXL(std::vector<uint8_t>& src);

Expand Down

0 comments on commit 05dc878

Please sign in to comment.