CloverBootloader/CloverApp/Clover/ThemeImage.m
vectorsigma72 00e5e5e7a7 Inproved theme manager resize ability during optimization
Now the theme manager can resize images based on the screen resolution detected into the config.plist or from the main screen of the pc. The resize of the icons only trigger when icons have different size.
2020-04-22 18:01:22 +02:00

166 lines
6.2 KiB
Objective-C

//
// PNG8Image.m
// Clover
//
// Created by vector sigma on 07/03/2020.
// Copyright © 2020 CloverHackyColor. All rights reserved.
//
#import "ThemeImage.h"
@implementation ThemeImage
- (id _Nullable)initWithData:(nonnull NSData *)data
error:(NSError *_Nullable*_Nullable)errorPtr
atPath:(nonnull NSString *)path {
if (!(self = [super init])) {
return nil;
}
NSData *mainData = data;
NSString *domain = @"org.slice.Clover.PNG8Image.Error";
if (!mainData || [mainData length] < 4) {
NSString *desc = [NSString stringWithFormat:@"Size of %@ is too small to be an image\n", path];
NSDictionary *userInfo = @{ NSLocalizedDescriptionKey : desc };
*errorPtr = [NSError errorWithDomain:domain
code:1
userInfo:userInfo];
return nil;
}
UInt8 * bytes = (UInt8 *)[mainData bytes];
if (bytes[0] != 0x89 || bytes[0] != 0x50 || bytes[0] != 0x4E || bytes[0] != 0x47) {
NSBitmapImageRep *bir = [[NSBitmapImageRep alloc] initWithData:mainData];
if (bir) {
mainData = [bir representationUsingType:NSPNGFileType properties:@{ NSImageInterlaced: @0,
NSImageCompressionFactor: @1 }];
if (mainData == nil) {
NSString *desc = [NSString stringWithFormat:@"Can't convert %@ to png\n", path];
NSDictionary *userInfo = @{ NSLocalizedDescriptionKey : desc };
*errorPtr = [NSError errorWithDomain:domain
code:2
userInfo:userInfo];
return nil;
} else {
[self addRepresentation: [[NSBitmapImageRep alloc] initWithData:mainData]];
}
}
}
unsigned int width, height;
unsigned char *raw_rgba_pixels;
unsigned int status = lodepng_decode32(&raw_rgba_pixels,
&width,
&height,
[mainData bytes],
[mainData length]);
if (status) {
NSString *desc = [NSString stringWithFormat:@"%@, %s\n",
path,
lodepng_error_text(status)];
NSDictionary *userInfo = @{ NSLocalizedDescriptionKey : desc };
*errorPtr = [NSError errorWithDomain:domain
code:3
userInfo:userInfo];
return nil;
}
// Use libimagequant to make a palette for the RGBA pixels
liq_attr *handle = liq_attr_create();
liq_image *input_image = liq_image_create_rgba(handle,
raw_rgba_pixels,
width,
height,
0);
// You could set more options here, like liq_set_quality
liq_result *quantization_result;
if (liq_image_quantize(input_image, handle, &quantization_result) != LIQ_OK) {
NSString *desc = [NSString stringWithFormat:@"Quantization failed for %@", path];
NSDictionary *userInfo = @{ NSLocalizedDescriptionKey : desc };
*errorPtr = [NSError errorWithDomain:domain
code:4
userInfo:userInfo];
return nil;
}
// Use libimagequant to make new image pixels from the palette
size_t pixels_size = width * height;
unsigned char *raw_8bit_pixels = malloc(pixels_size);
liq_set_dithering_level(quantization_result, 1.0);
liq_write_remapped_image(quantization_result,
input_image,
raw_8bit_pixels,
pixels_size);
const liq_palette *palette = liq_get_palette(quantization_result);
// Save converted pixels as a PNG file
// This uses lodepng library for PNG writing (not part of libimagequant)
LodePNGState state;
lodepng_state_init(&state);
state.info_raw.colortype = LCT_PALETTE;
state.info_raw.bitdepth = 8;
state.info_png.color.colortype = LCT_PALETTE;
state.info_png.color.bitdepth = 8;
for(int i = 0; i < palette->count; i++) {
lodepng_palette_add(&state.info_png.color,
palette->entries[i].r,
palette->entries[i].g,
palette->entries[i].b,
palette->entries[i].a);
lodepng_palette_add(&state.info_raw,
palette->entries[i].r,
palette->entries[i].g,
palette->entries[i].b,
palette->entries[i].a);
}
unsigned char *output_file_data;
size_t output_file_size;
unsigned int out_status = lodepng_encode(&output_file_data,
&output_file_size,
raw_8bit_pixels,
width,
height,
&state);
if (out_status) {
NSString *desc = [NSString stringWithFormat:@"Can't encode %@: %s\n",
path,
lodepng_error_text(out_status)];
NSDictionary *userInfo = @{ NSLocalizedDescriptionKey : desc };
*errorPtr = [NSError errorWithDomain:domain
code:5
userInfo:userInfo];
return nil;
}
// Prove the conversion
self.pngData = [NSData dataWithBytes: output_file_data length: output_file_size];
NSImage *convertedImage = [[NSImage alloc] initWithData:self.pngData];
if (convertedImage == nil) {
NSString *desc = [NSString stringWithFormat:@"Can't convert data to NSImage (%@)", path];
NSDictionary *userInfo = @{ NSLocalizedDescriptionKey : desc };
*errorPtr = [NSError errorWithDomain:domain
code:6
userInfo:userInfo];
return nil;
}
liq_result_destroy(quantization_result); // Must be freed only after you're done using the palette
liq_image_destroy(input_image);
liq_attr_destroy(handle);
free(raw_8bit_pixels);
lodepng_state_cleanup(&state);
return self;
}
@end