mirror of
https://github.com/Nyx0uf/qlImageSize.git
synced 2026-03-03 18:23:19 +01:00
124 lines
3.2 KiB
Objective-C
124 lines
3.2 KiB
Objective-C
//
|
|
// webp_decode.m
|
|
// qlImageSize
|
|
//
|
|
// Created by @Nyx0uf on 30/12/14.
|
|
// Copyright (c) 2014 Nyx0uf. All rights reserved.
|
|
//
|
|
|
|
|
|
#import "webp_decode.h"
|
|
#import "decode.h"
|
|
|
|
|
|
#ifdef NYX_QL_SUPPORT_WEBP_DECODE
|
|
CF_RETURNS_RETAINED CGImageRef decode_webp_at_path(CFStringRef filepath, image_infos* infos)
|
|
{
|
|
// Init WebP decoder
|
|
WebPDecoderConfig webp_cfg;
|
|
if (!WebPInitDecoderConfig(&webp_cfg))
|
|
return NULL;
|
|
|
|
// Read file
|
|
uint8_t* buffer = NULL;
|
|
const size_t file_size = read_file(filepath, &buffer);
|
|
if (0 == file_size)
|
|
{
|
|
free(buffer);
|
|
return NULL;
|
|
}
|
|
|
|
// Get image infos
|
|
if (WebPGetFeatures(buffer, file_size, &webp_cfg.input) != VP8_STATUS_OK)
|
|
{
|
|
free(buffer);
|
|
return NULL;
|
|
}
|
|
|
|
// Decode image, always RGBA
|
|
webp_cfg.output.colorspace = webp_cfg.input.has_alpha ? MODE_rgbA : MODE_RGB;
|
|
webp_cfg.options.use_threads = 1;
|
|
WebPIDecoder* const idec = WebPIDecode(buffer, file_size, &webp_cfg);
|
|
if (idec == NULL)
|
|
{
|
|
free(buffer);
|
|
return NULL;
|
|
}
|
|
else
|
|
{
|
|
VP8StatusCode status = VP8_STATUS_OK;
|
|
size_t done_size = 0;
|
|
const size_t incr = 25165824; // 24MB, arbitrary chosen
|
|
while (done_size < file_size)
|
|
{
|
|
size_t next_size = done_size + incr;
|
|
if (next_size > file_size)
|
|
next_size = file_size;
|
|
status = WebPIUpdate(idec, buffer, next_size);
|
|
if (status != VP8_STATUS_OK && status != VP8_STATUS_SUSPENDED)
|
|
break;
|
|
done_size = next_size;
|
|
}
|
|
WebPIDelete(idec);
|
|
}
|
|
free(buffer);
|
|
|
|
const size_t width = (size_t)webp_cfg.input.width;
|
|
const size_t height = (size_t)webp_cfg.input.height;
|
|
if (infos != NULL)
|
|
{
|
|
infos->width = width;
|
|
infos->height = height;
|
|
infos->filesize = (size_t)file_size;
|
|
}
|
|
|
|
// Create CGImage
|
|
CGDataProviderRef data_provider = CGDataProviderCreateWithData(NULL, webp_cfg.output.u.RGBA.rgba, webp_cfg.output.u.RGBA.size, NULL);
|
|
if (data_provider == NULL)
|
|
return NULL;
|
|
CGColorSpaceRef color_space = CGColorSpaceCreateDeviceRGB();
|
|
CGBitmapInfo bitmapInfo = kCGBitmapByteOrder32Big | (webp_cfg.input.has_alpha ? kCGImageAlphaPremultipliedLast : kCGImageAlphaNone);
|
|
const size_t components = webp_cfg.input.has_alpha ? 4 : 3;
|
|
CGImageRef img_ref = CGImageCreate(width, height, 8, components * 8, components * width, color_space, bitmapInfo, data_provider, NULL, false, kCGRenderingIntentDefault);
|
|
|
|
CGColorSpaceRelease(color_space);
|
|
CGDataProviderRelease(data_provider);
|
|
|
|
return img_ref;
|
|
}
|
|
#endif /* NYX_QL_SUPPORT_WEBP_DECODE */
|
|
|
|
#ifdef NYX_MD_SUPPORT_WEBP_DECODE
|
|
bool get_webp_informations_for_filepath(CFStringRef filepath, image_infos* infos)
|
|
{
|
|
WebPDecoderConfig webp_cfg;
|
|
if (!WebPInitDecoderConfig(&webp_cfg))
|
|
return false;
|
|
|
|
// Read file
|
|
uint8_t* buffer = NULL;
|
|
const size_t size = read_file(filepath, &buffer);
|
|
if (0 == size)
|
|
{
|
|
free(buffer);
|
|
return false;
|
|
}
|
|
|
|
// Get file informations
|
|
if (WebPGetFeatures(buffer, size, &webp_cfg.input) != VP8_STATUS_OK)
|
|
{
|
|
free(buffer);
|
|
return false;
|
|
}
|
|
free(buffer);
|
|
|
|
infos->width = (size_t)webp_cfg.input.width;
|
|
infos->height = (size_t)webp_cfg.input.height;
|
|
infos->has_alpha = (uint8_t)webp_cfg.input.has_alpha;
|
|
infos->bit_depth = 8;
|
|
infos->colorspace = (webp_cfg.input.format == 2) ? colorspace_rgb : colorspace_ycbcr; // lossy WebP, always YUV 4:2:0 | lossless WebP, always ARGB
|
|
|
|
return true;
|
|
}
|
|
#endif /* NYX_MD_SUPPORT_WEBP_DECODE */
|