mirror of
https://github.com/google/wuffs.git
synced 2026-01-18 17:11:32 +01:00
std/handsum: add new package
This commit is contained in:
@@ -19,6 +19,7 @@ The LICENSE has changed from a single license (Apache 2) to a dual license
|
||||
- Added `get_quirk(key: u32) u64`.
|
||||
- Added `std/crc64`.
|
||||
- Added `std/etc2`.
|
||||
- Added `std/handsum`.
|
||||
- Added `std/jpeg`.
|
||||
- Added `std/lzip`.
|
||||
- Added `std/lzma`.
|
||||
|
||||
@@ -55,6 +55,7 @@ to enable.
|
||||
- `ETC2: BASE`
|
||||
- `GIF: BASE`
|
||||
- `GZIP: BASE, CRC32, DEFLATE`
|
||||
- `HANDSUM: BASE`
|
||||
- `JPEG: BASE`
|
||||
- `JSON: BASE`
|
||||
- `LZIP: BASE, CRC32, LZMA`
|
||||
|
||||
@@ -126,6 +126,7 @@ In Wuffs syntax, the `base.image_decoder` methods are:
|
||||
- [std/bmp](/std/bmp)
|
||||
- [std/etc2](/std/etc2)
|
||||
- [std/gif](/std/gif)
|
||||
- [std/handsum](/std/handsum)
|
||||
- [std/jpeg](/std/jpeg)
|
||||
- [std/netpbm](/std/netpbm)
|
||||
- [std/nie](/std/nie)
|
||||
|
||||
@@ -68,6 +68,7 @@ that Wuffs decodes to just JPEG, for smaller binaries and faster compiles.
|
||||
#define WUFFS_CONFIG__MODULE__DEFLATE
|
||||
#define WUFFS_CONFIG__MODULE__ETC2
|
||||
#define WUFFS_CONFIG__MODULE__GIF
|
||||
#define WUFFS_CONFIG__MODULE__HANDSUM
|
||||
#define WUFFS_CONFIG__MODULE__NETPBM
|
||||
#define WUFFS_CONFIG__MODULE__NIE
|
||||
#define WUFFS_CONFIG__MODULE__PNG
|
||||
@@ -184,6 +185,7 @@ union {
|
||||
wuffs_bmp__decoder bmp;
|
||||
wuffs_etc2__decoder etc2;
|
||||
wuffs_gif__decoder gif;
|
||||
wuffs_handsum__decoder handsum;
|
||||
wuffs_netpbm__decoder netpbm;
|
||||
wuffs_nie__decoder nie;
|
||||
wuffs_png__decoder png;
|
||||
@@ -416,6 +418,16 @@ initialize_image_decoder() {
|
||||
&g_potential_decoders.gif);
|
||||
return NULL;
|
||||
|
||||
case WUFFS_BASE__FOURCC__HNSM:
|
||||
status = wuffs_handsum__decoder__initialize(
|
||||
&g_potential_decoders.handsum, sizeof g_potential_decoders.handsum,
|
||||
WUFFS_VERSION, WUFFS_INITIALIZE__DEFAULT_OPTIONS);
|
||||
TRY(wuffs_base__status__message(&status));
|
||||
g_image_decoder =
|
||||
wuffs_handsum__decoder__upcast_as__wuffs_base__image_decoder(
|
||||
&g_potential_decoders.handsum);
|
||||
return NULL;
|
||||
|
||||
case WUFFS_BASE__FOURCC__NIE:
|
||||
status = wuffs_nie__decoder__initialize(
|
||||
&g_potential_decoders.nie, sizeof g_potential_decoders.nie,
|
||||
|
||||
@@ -76,6 +76,7 @@ The Escape key quits.
|
||||
#define WUFFS_CONFIG__MODULE__DEFLATE
|
||||
#define WUFFS_CONFIG__MODULE__ETC2
|
||||
#define WUFFS_CONFIG__MODULE__GIF
|
||||
#define WUFFS_CONFIG__MODULE__HANDSUM
|
||||
#define WUFFS_CONFIG__MODULE__JPEG
|
||||
#define WUFFS_CONFIG__MODULE__NETPBM
|
||||
#define WUFFS_CONFIG__MODULE__NIE
|
||||
|
||||
@@ -74,6 +74,7 @@ isn't otherwise doing anything.
|
||||
#define WUFFS_CONFIG__MODULE__DEFLATE
|
||||
#define WUFFS_CONFIG__MODULE__ETC2
|
||||
#define WUFFS_CONFIG__MODULE__GIF
|
||||
#define WUFFS_CONFIG__MODULE__HANDSUM
|
||||
#define WUFFS_CONFIG__MODULE__JPEG
|
||||
#define WUFFS_CONFIG__MODULE__NETPBM
|
||||
#define WUFFS_CONFIG__MODULE__NIE
|
||||
|
||||
@@ -127,6 +127,7 @@ for a C compiler $CC, such as clang or gcc.
|
||||
#define WUFFS_CONFIG__MODULE__DEFLATE
|
||||
#define WUFFS_CONFIG__MODULE__ETC2
|
||||
#define WUFFS_CONFIG__MODULE__GIF
|
||||
#define WUFFS_CONFIG__MODULE__HANDSUM
|
||||
#define WUFFS_CONFIG__MODULE__NETPBM
|
||||
#define WUFFS_CONFIG__MODULE__NIE
|
||||
#define WUFFS_CONFIG__MODULE__PNG
|
||||
|
||||
@@ -72,6 +72,11 @@ DecodeImageCallbacks::SelectDecoder(uint32_t fourcc,
|
||||
return wuffs_gif__decoder::alloc_as__wuffs_base__image_decoder();
|
||||
#endif
|
||||
|
||||
#if !defined(WUFFS_CONFIG__MODULES) || defined(WUFFS_CONFIG__MODULE__HANDSUM)
|
||||
case WUFFS_BASE__FOURCC__HNSM:
|
||||
return wuffs_handsum__decoder::alloc_as__wuffs_base__image_decoder();
|
||||
#endif
|
||||
|
||||
#if !defined(WUFFS_CONFIG__MODULES) || defined(WUFFS_CONFIG__MODULE__JPEG)
|
||||
case WUFFS_BASE__FOURCC__JPEG:
|
||||
return wuffs_jpeg__decoder::alloc_as__wuffs_base__image_decoder();
|
||||
|
||||
@@ -87,6 +87,7 @@ class DecodeImageCallbacks {
|
||||
// - WUFFS_BASE__FOURCC__BMP
|
||||
// - WUFFS_BASE__FOURCC__ETC2
|
||||
// - WUFFS_BASE__FOURCC__GIF
|
||||
// - WUFFS_BASE__FOURCC__HNSM
|
||||
// - WUFFS_BASE__FOURCC__JPEG
|
||||
// - WUFFS_BASE__FOURCC__NIE
|
||||
// - WUFFS_BASE__FOURCC__NPBM
|
||||
|
||||
@@ -91,6 +91,11 @@ wuffs_drop_in__stb__make_decoder( //
|
||||
return wuffs_gif__decoder__alloc_as__wuffs_base__image_decoder();
|
||||
#endif
|
||||
|
||||
#if !defined(WUFFS_CONFIG__MODULES) || defined(WUFFS_CONFIG__MODULE__HANDSUM)
|
||||
case WUFFS_BASE__FOURCC__HNSM:
|
||||
return wuffs_handsum__decoder__alloc_as__wuffs_base__image_decoder();
|
||||
#endif
|
||||
|
||||
#if !defined(WUFFS_CONFIG__MODULES) || defined(WUFFS_CONFIG__MODULE__JPEG)
|
||||
case WUFFS_BASE__FOURCC__JPEG:
|
||||
return wuffs_jpeg__decoder__alloc_as__wuffs_base__image_decoder();
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -62,6 +62,7 @@
|
||||
#define WUFFS_CONFIG__MODULE__ETC2
|
||||
#define WUFFS_CONFIG__MODULE__GIF
|
||||
#define WUFFS_CONFIG__MODULE__GZIP
|
||||
#define WUFFS_CONFIG__MODULE__HANDSUM
|
||||
#define WUFFS_CONFIG__MODULE__JPEG
|
||||
#define WUFFS_CONFIG__MODULE__NETPBM
|
||||
#define WUFFS_CONFIG__MODULE__NIE
|
||||
@@ -119,6 +120,9 @@ handle_image_decoder(wuffs_base__io_buffer src,
|
||||
case WUFFS_BASE__FOURCC__GIF:
|
||||
dec = wuffs_gif__decoder::alloc_as__wuffs_base__image_decoder();
|
||||
break;
|
||||
case WUFFS_BASE__FOURCC__HNSM:
|
||||
dec = wuffs_handsum__decoder::alloc_as__wuffs_base__image_decoder();
|
||||
break;
|
||||
case WUFFS_BASE__FOURCC__JPEG:
|
||||
dec = wuffs_jpeg__decoder::alloc_as__wuffs_base__image_decoder();
|
||||
break;
|
||||
|
||||
@@ -54,6 +54,7 @@ to use the wuffs_aux C++ API to decode an image and iterate over its pixels.
|
||||
#define WUFFS_CONFIG__MODULE__DEFLATE
|
||||
#define WUFFS_CONFIG__MODULE__ETC2
|
||||
#define WUFFS_CONFIG__MODULE__GIF
|
||||
#define WUFFS_CONFIG__MODULE__HANDSUM
|
||||
#define WUFFS_CONFIG__MODULE__JPEG
|
||||
#define WUFFS_CONFIG__MODULE__NETPBM
|
||||
#define WUFFS_CONFIG__MODULE__NIE
|
||||
|
||||
@@ -50,6 +50,7 @@ print-image-metadata prints images' metadata.
|
||||
#define WUFFS_CONFIG__MODULE__DEFLATE
|
||||
#define WUFFS_CONFIG__MODULE__ETC2
|
||||
#define WUFFS_CONFIG__MODULE__GIF
|
||||
#define WUFFS_CONFIG__MODULE__HANDSUM
|
||||
#define WUFFS_CONFIG__MODULE__JPEG
|
||||
#define WUFFS_CONFIG__MODULE__NETPBM
|
||||
#define WUFFS_CONFIG__MODULE__NIE
|
||||
@@ -381,6 +382,9 @@ redirect:
|
||||
case WUFFS_BASE__FOURCC__GIF:
|
||||
dec = wuffs_gif__decoder::alloc_as__wuffs_base__image_decoder();
|
||||
break;
|
||||
case WUFFS_BASE__FOURCC__HNSM:
|
||||
dec = wuffs_handsum__decoder::alloc_as__wuffs_base__image_decoder();
|
||||
break;
|
||||
case WUFFS_BASE__FOURCC__JPEG:
|
||||
dec = wuffs_jpeg__decoder::alloc_as__wuffs_base__image_decoder();
|
||||
break;
|
||||
|
||||
304
std/handsum/decode_handsum.wuffs
Normal file
304
std/handsum/decode_handsum.wuffs
Normal file
@@ -0,0 +1,304 @@
|
||||
// Copyright 2025 The Wuffs Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
|
||||
// --------
|
||||
|
||||
// Handsum is a very lossy format for very small thumbnails. Very small in
|
||||
// terms of image dimensions, up to 32×32 pixels, but also in terms of file
|
||||
// size. Every Handsum image file is exactly 48 bytes (384 bits) long. This can
|
||||
// imply using as little as 0.046875 bytes (0.375 bits) per pixel.
|
||||
//
|
||||
// Each Handsum image is essentially a scaled 16×16 pixel YCbCr 4:2:0 JPEG MCU
|
||||
// (Minimum Coded Unit; 4 Luma and 2 Chroma blocks), keeping only the 15 lowest
|
||||
// frequency DCT (Discrete Cosine Transform) coefficients. Each of the (6 × 15)
|
||||
// = 90 coefficients are encoded as one nibble (4 bits) with fixed quantization
|
||||
// factors, totalling 45 bytes. The initial 3 bytes holds a 16-bit magic
|
||||
// signature, 2-bit version number and 6-bit aspect ratio.
|
||||
//
|
||||
// As of February 2025, the latest version is Version 0. All Version 0 files
|
||||
// use the sRGB color profile.
|
||||
|
||||
pub status "#bad header"
|
||||
pub status "#truncated input"
|
||||
pub status "#unsupported Handsum file"
|
||||
|
||||
pub const DECODER_WORKBUF_LEN_MAX_INCL_WORST_CASE : base.u64 = 0
|
||||
|
||||
pub struct decoder? implements base.image_decoder(
|
||||
width : base.u32[..= 32],
|
||||
height : base.u32[..= 32],
|
||||
|
||||
// The call sequence state machine is discussed in
|
||||
// (/doc/std/image-decoders-call-sequence.md).
|
||||
call_sequence : base.u8,
|
||||
|
||||
swizzler : base.pixel_swizzler,
|
||||
util : base.utility,
|
||||
) + (
|
||||
buffers : array[2] array[32] array[128] base.u8,
|
||||
)
|
||||
|
||||
pub func decoder.get_quirk(key: base.u32) base.u64 {
|
||||
return 0
|
||||
}
|
||||
|
||||
pub func decoder.set_quirk!(key: base.u32, value: base.u64) base.status {
|
||||
return base."#unsupported option"
|
||||
}
|
||||
|
||||
pub func decoder.decode_image_config?(dst: nptr base.image_config, src: base.io_reader) {
|
||||
var status : base.status
|
||||
|
||||
while true {
|
||||
status =? this.do_decode_image_config?(dst: args.dst, src: args.src)
|
||||
if (status == base."$short read") and args.src.is_closed() {
|
||||
return "#truncated input"
|
||||
}
|
||||
yield? status
|
||||
}
|
||||
}
|
||||
|
||||
pri func decoder.do_decode_image_config?(dst: nptr base.image_config, src: base.io_reader) {
|
||||
var c32 : base.u32
|
||||
|
||||
if this.call_sequence <> 0x00 {
|
||||
return base."#bad call sequence"
|
||||
}
|
||||
|
||||
c32 = args.src.read_u16le_as_u32?()
|
||||
if c32 <> '\xFE\xD7'le {
|
||||
return "#bad header"
|
||||
}
|
||||
c32 = args.src.read_u8_as_u32?()
|
||||
if (c32 & 0xC0) <> 0x00 {
|
||||
return "#unsupported Handsum file"
|
||||
}
|
||||
|
||||
if (c32 & 0x20) == 0x00 { // Landscape.
|
||||
this.width = 32
|
||||
this.height = (c32 & 0x1F) + 1
|
||||
} else { // Portrait.
|
||||
this.width = (c32 & 0x1F) + 1
|
||||
this.height = 32
|
||||
}
|
||||
|
||||
if args.dst <> nullptr {
|
||||
args.dst.set!(
|
||||
pixfmt: base.PIXEL_FORMAT__BGRX,
|
||||
pixsub: 0,
|
||||
width: this.width,
|
||||
height: this.height,
|
||||
first_frame_io_position: 3,
|
||||
first_frame_is_opaque: true)
|
||||
}
|
||||
|
||||
this.call_sequence = 0x20
|
||||
}
|
||||
|
||||
pub func decoder.decode_frame_config?(dst: nptr base.frame_config, src: base.io_reader) {
|
||||
var status : base.status
|
||||
|
||||
while true {
|
||||
status =? this.do_decode_frame_config?(dst: args.dst, src: args.src)
|
||||
if (status == base."$short read") and args.src.is_closed() {
|
||||
return "#truncated input"
|
||||
}
|
||||
yield? status
|
||||
}
|
||||
}
|
||||
|
||||
pri func decoder.do_decode_frame_config?(dst: nptr base.frame_config, src: base.io_reader) {
|
||||
if this.call_sequence == 0x20 {
|
||||
// No-op.
|
||||
} else if this.call_sequence < 0x20 {
|
||||
this.do_decode_image_config?(dst: nullptr, src: args.src)
|
||||
} else if this.call_sequence == 0x28 {
|
||||
if 3 <> args.src.position() {
|
||||
return base."#bad restart"
|
||||
}
|
||||
} else if this.call_sequence == 0x40 {
|
||||
this.call_sequence = 0x60
|
||||
return base."@end of data"
|
||||
} else {
|
||||
return base."@end of data"
|
||||
}
|
||||
|
||||
if args.dst <> nullptr {
|
||||
args.dst.set!(bounds: this.util.make_rect_ie_u32(
|
||||
min_incl_x: 0,
|
||||
min_incl_y: 0,
|
||||
max_excl_x: this.width,
|
||||
max_excl_y: this.height),
|
||||
duration: 0,
|
||||
index: 0,
|
||||
io_position: 3,
|
||||
disposal: 0,
|
||||
opaque_within_bounds: true,
|
||||
overwrite_instead_of_blend: false,
|
||||
background_color: 0xFF00_0000)
|
||||
}
|
||||
|
||||
this.call_sequence = 0x40
|
||||
}
|
||||
|
||||
pub func decoder.decode_frame?(dst: ptr base.pixel_buffer, src: base.io_reader, blend: base.pixel_blend, workbuf: slice base.u8, opts: nptr base.decode_frame_options) {
|
||||
var status : base.status
|
||||
|
||||
while true {
|
||||
status =? this.do_decode_frame?(dst: args.dst, src: args.src, blend: args.blend, workbuf: args.workbuf, opts: args.opts)
|
||||
if (status == base."$short read") and args.src.is_closed() {
|
||||
return "#truncated input"
|
||||
}
|
||||
yield? status
|
||||
}
|
||||
}
|
||||
|
||||
pri func decoder.do_decode_frame?(dst: ptr base.pixel_buffer, src: base.io_reader, blend: base.pixel_blend, workbuf: slice base.u8, opts: nptr base.decode_frame_options) {
|
||||
var status : base.status
|
||||
|
||||
if this.call_sequence == 0x40 {
|
||||
// No-op.
|
||||
} else if this.call_sequence < 0x40 {
|
||||
this.do_decode_frame_config?(dst: nullptr, src: args.src)
|
||||
} else {
|
||||
return base."@end of data"
|
||||
}
|
||||
|
||||
status = this.swizzler.prepare!(
|
||||
dst_pixfmt: args.dst.pixel_format(),
|
||||
dst_palette: args.dst.palette(),
|
||||
src_pixfmt: this.util.make_pixel_format(repr: base.PIXEL_FORMAT__BGRX),
|
||||
src_palette: this.util.empty_slice_u8(),
|
||||
blend: args.blend)
|
||||
if not status.is_ok() {
|
||||
return status
|
||||
}
|
||||
|
||||
this.from_src_to_pixels?(src: args.src)
|
||||
status = this.from_pixels_to_dst!(dst: args.dst, which: 0)
|
||||
if not status.is_ok() {
|
||||
return status
|
||||
}
|
||||
|
||||
this.call_sequence = 0x60
|
||||
}
|
||||
|
||||
pri func decoder.from_src_to_pixels?(src: base.io_reader) {
|
||||
var y : base.u32
|
||||
var x : base.u32
|
||||
|
||||
// TODO: actually implement the format. For now, fill in a placeholder
|
||||
// blue-green gradient.
|
||||
|
||||
y = 0
|
||||
while y < 32 {
|
||||
x = 0
|
||||
while x < 32,
|
||||
inv y < 32,
|
||||
{
|
||||
this.buffers[0][y][(4 * x) + 0] = (x * 8) as base.u8
|
||||
this.buffers[0][y][(4 * x) + 1] = (y * 8) as base.u8
|
||||
this.buffers[0][y][(4 * x) + 2] = 0x00
|
||||
this.buffers[0][y][(4 * x) + 3] = 0xFF
|
||||
x += 1
|
||||
}
|
||||
y += 1
|
||||
}
|
||||
}
|
||||
|
||||
pri func decoder.from_pixels_to_dst!(dst: ptr base.pixel_buffer, which: base.u32[..= 1]) base.status {
|
||||
var dst_pixfmt : base.pixel_format
|
||||
var dst_bits_per_pixel : base.u32[..= 256]
|
||||
var dst_bytes_per_pixel : base.u32[..= 32]
|
||||
var dst_bytes_per_row : base.u64
|
||||
var tab : table base.u8
|
||||
var y : base.u32
|
||||
var dst : slice base.u8
|
||||
var src : slice base.u8
|
||||
|
||||
// TODO: the dst_pixfmt variable shouldn't be necessary. We should be able
|
||||
// to chain the two calls: "args.dst.pixel_format().bits_per_pixel()".
|
||||
dst_pixfmt = args.dst.pixel_format()
|
||||
dst_bits_per_pixel = dst_pixfmt.bits_per_pixel()
|
||||
if (dst_bits_per_pixel & 7) <> 0 {
|
||||
return base."#unsupported option"
|
||||
}
|
||||
dst_bytes_per_pixel = dst_bits_per_pixel / 8
|
||||
dst_bytes_per_row = (this.width * dst_bytes_per_pixel) as base.u64
|
||||
tab = args.dst.plane(p: 0)
|
||||
|
||||
while y < this.height {
|
||||
assert y < 32 via "a < b: a < c; c <= b"(c: this.height)
|
||||
src = this.buffers[args.which][y][.. this.width * 4]
|
||||
|
||||
dst = tab.row_u32(y: y)
|
||||
if dst_bytes_per_row < dst.length() {
|
||||
dst = dst[.. dst_bytes_per_row]
|
||||
}
|
||||
|
||||
this.swizzler.swizzle_interleaved_from_slice!(
|
||||
dst: dst,
|
||||
dst_palette: args.dst.palette(),
|
||||
src: src)
|
||||
|
||||
y += 1
|
||||
}
|
||||
|
||||
return ok
|
||||
}
|
||||
|
||||
pub func decoder.frame_dirty_rect() base.rect_ie_u32 {
|
||||
return this.util.make_rect_ie_u32(
|
||||
min_incl_x: 0,
|
||||
min_incl_y: 0,
|
||||
max_excl_x: this.width,
|
||||
max_excl_y: this.height)
|
||||
}
|
||||
|
||||
pub func decoder.num_animation_loops() base.u32 {
|
||||
return 0
|
||||
}
|
||||
|
||||
pub func decoder.num_decoded_frame_configs() base.u64 {
|
||||
if this.call_sequence > 0x20 {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
pub func decoder.num_decoded_frames() base.u64 {
|
||||
if this.call_sequence > 0x40 {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
pub func decoder.restart_frame!(index: base.u64, io_position: base.u64) base.status {
|
||||
if this.call_sequence < 0x20 {
|
||||
return base."#bad call sequence"
|
||||
}
|
||||
if (args.index <> 0) or (args.io_position <> 3) {
|
||||
return base."#bad argument"
|
||||
}
|
||||
this.call_sequence = 0x28
|
||||
return ok
|
||||
}
|
||||
|
||||
pub func decoder.set_report_metadata!(fourcc: base.u32, report: base.bool) {
|
||||
// No-op. Handsum doesn't support metadata.
|
||||
}
|
||||
|
||||
pub func decoder.tell_me_more?(dst: base.io_writer, minfo: nptr base.more_information, src: base.io_reader) {
|
||||
return base."#no more information"
|
||||
}
|
||||
|
||||
pub func decoder.workbuf_len() base.range_ii_u64 {
|
||||
return this.util.make_range_ii_u64(min_incl: 0, max_incl: 0)
|
||||
}
|
||||
196
test/c/std/handsum.c
Normal file
196
test/c/std/handsum.c
Normal file
@@ -0,0 +1,196 @@
|
||||
// Copyright 2025 The Wuffs Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
|
||||
// ----------------
|
||||
|
||||
/*
|
||||
This test program is typically run indirectly, by the "wuffs test" or "wuffs
|
||||
bench" commands. These commands take an optional "-mimic" flag to check that
|
||||
Wuffs' output mimics (i.e. exactly matches) other libraries' output, such as
|
||||
giflib for GIF, libpng for PNG, etc.
|
||||
|
||||
To manually run this test:
|
||||
|
||||
for CC in clang gcc; do
|
||||
$CC -std=c99 -Wall -Werror handsum.c && ./a.out
|
||||
rm -f a.out
|
||||
done
|
||||
|
||||
Each edition should print "PASS", amongst other information, and exit(0).
|
||||
|
||||
Add the "wuffs mimic cflags" (everything after the colon below) to the C
|
||||
compiler flags (after the .c file) to run the mimic tests.
|
||||
|
||||
To manually run the benchmarks, replace "-Wall -Werror" with "-O3" and replace
|
||||
the first "./a.out" with "./a.out -bench". Combine these changes with the
|
||||
"wuffs mimic cflags" to run the mimic benchmarks.
|
||||
*/
|
||||
|
||||
// ¿ wuffs mimic cflags: -DWUFFS_MIMIC
|
||||
|
||||
// Wuffs ships as a "single file C library" or "header file library" as per
|
||||
// https://github.com/nothings/stb/blob/master/docs/stb_howto.txt
|
||||
//
|
||||
// To use that single file as a "foo.c"-like implementation, instead of a
|
||||
// "foo.h"-like header, #define WUFFS_IMPLEMENTATION before #include'ing or
|
||||
// compiling it.
|
||||
#define WUFFS_IMPLEMENTATION
|
||||
|
||||
// Defining the WUFFS_CONFIG__MODULE* macros are optional, but it lets users of
|
||||
// release/c/etc.c choose which parts of Wuffs to build. That file contains the
|
||||
// entire Wuffs standard library, implementing a variety of codecs and file
|
||||
// formats. Without this macro definition, an optimizing compiler or linker may
|
||||
// very well discard Wuffs code for unused codecs, but listing the Wuffs
|
||||
// modules we use makes that process explicit. Preprocessing means that such
|
||||
// code simply isn't compiled.
|
||||
#define WUFFS_CONFIG__MODULES
|
||||
#define WUFFS_CONFIG__MODULE__BASE
|
||||
#define WUFFS_CONFIG__MODULE__HANDSUM
|
||||
|
||||
// If building this program in an environment that doesn't easily accommodate
|
||||
// relative includes, you can use the script/inline-c-relative-includes.go
|
||||
// program to generate a stand-alone C file.
|
||||
#include "../../../release/c/wuffs-unsupported-snapshot.c"
|
||||
#include "../testlib/testlib.c"
|
||||
#ifdef WUFFS_MIMIC
|
||||
// No mimic library.
|
||||
#endif
|
||||
|
||||
// ---------------- Handsum Tests
|
||||
|
||||
const char* //
|
||||
test_wuffs_handsum_decode_interface() {
|
||||
CHECK_FOCUS(__func__);
|
||||
wuffs_handsum__decoder dec;
|
||||
CHECK_STATUS("initialize",
|
||||
wuffs_handsum__decoder__initialize(
|
||||
&dec, sizeof dec, WUFFS_VERSION,
|
||||
WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED));
|
||||
return do_test__wuffs_base__image_decoder(
|
||||
wuffs_handsum__decoder__upcast_as__wuffs_base__image_decoder(&dec),
|
||||
"test/data/bricks-color.handsum", 0, SIZE_MAX, 32, 24, 0xFF00B8F8);
|
||||
}
|
||||
|
||||
const char* //
|
||||
test_wuffs_handsum_decode_truncated_input() {
|
||||
CHECK_FOCUS(__func__);
|
||||
|
||||
wuffs_base__io_buffer src =
|
||||
wuffs_base__ptr_u8__reader(g_src_array_u8, 0, false);
|
||||
wuffs_handsum__decoder dec;
|
||||
CHECK_STATUS("initialize",
|
||||
wuffs_handsum__decoder__initialize(
|
||||
&dec, sizeof dec, WUFFS_VERSION,
|
||||
WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED));
|
||||
|
||||
wuffs_base__status status =
|
||||
wuffs_handsum__decoder__decode_image_config(&dec, NULL, &src);
|
||||
if (status.repr != wuffs_base__suspension__short_read) {
|
||||
RETURN_FAIL("closed=false: have \"%s\", want \"%s\"", status.repr,
|
||||
wuffs_base__suspension__short_read);
|
||||
}
|
||||
|
||||
src.meta.closed = true;
|
||||
status = wuffs_handsum__decoder__decode_image_config(&dec, NULL, &src);
|
||||
if (status.repr != wuffs_handsum__error__truncated_input) {
|
||||
RETURN_FAIL("closed=true: have \"%s\", want \"%s\"", status.repr,
|
||||
wuffs_handsum__error__truncated_input);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char* //
|
||||
test_wuffs_handsum_decode_frame_config() {
|
||||
CHECK_FOCUS(__func__);
|
||||
wuffs_handsum__decoder dec;
|
||||
CHECK_STATUS("initialize",
|
||||
wuffs_handsum__decoder__initialize(
|
||||
&dec, sizeof dec, WUFFS_VERSION,
|
||||
WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED));
|
||||
|
||||
wuffs_base__frame_config fc = ((wuffs_base__frame_config){});
|
||||
wuffs_base__io_buffer src = ((wuffs_base__io_buffer){
|
||||
.data = g_src_slice_u8,
|
||||
});
|
||||
CHECK_STRING(read_file(&src, "test/data/mona-lisa.21x32.handsum"));
|
||||
|
||||
CHECK_STATUS("decode_frame_config #0",
|
||||
wuffs_handsum__decoder__decode_frame_config(&dec, &fc, &src));
|
||||
|
||||
uint32_t have = wuffs_base__frame_config__width(&fc);
|
||||
uint32_t want = 21;
|
||||
if (have != want) {
|
||||
RETURN_FAIL("width: have %u, want %u", have, want);
|
||||
}
|
||||
|
||||
wuffs_base__status status =
|
||||
wuffs_handsum__decoder__decode_frame_config(&dec, &fc, &src);
|
||||
if (status.repr != wuffs_base__note__end_of_data) {
|
||||
RETURN_FAIL("decode_frame_config #1: have \"%s\", want \"%s\"", status.repr,
|
||||
wuffs_base__note__end_of_data);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// ---------------- Mimic Tests
|
||||
|
||||
#ifdef WUFFS_MIMIC
|
||||
|
||||
// No mimic tests.
|
||||
|
||||
#endif // WUFFS_MIMIC
|
||||
|
||||
// ---------------- Handsum Benches
|
||||
|
||||
// No Handsum benches.
|
||||
|
||||
// ---------------- Mimic Benches
|
||||
|
||||
#ifdef WUFFS_MIMIC
|
||||
|
||||
// No mimic benches.
|
||||
|
||||
#endif // WUFFS_MIMIC
|
||||
|
||||
// ---------------- Manifest
|
||||
|
||||
proc g_tests[] = {
|
||||
|
||||
test_wuffs_handsum_decode_frame_config,
|
||||
test_wuffs_handsum_decode_interface,
|
||||
test_wuffs_handsum_decode_truncated_input,
|
||||
|
||||
#ifdef WUFFS_MIMIC
|
||||
|
||||
// No mimic tests.
|
||||
|
||||
#endif // WUFFS_MIMIC
|
||||
|
||||
NULL,
|
||||
};
|
||||
|
||||
proc g_benches[] = {
|
||||
|
||||
// No Handsum benches.
|
||||
|
||||
#ifdef WUFFS_MIMIC
|
||||
|
||||
// No mimic benches.
|
||||
|
||||
#endif // WUFFS_MIMIC
|
||||
|
||||
NULL,
|
||||
};
|
||||
|
||||
int //
|
||||
main(int argc, char** argv) {
|
||||
g_proc_package_name = "std/handsum";
|
||||
return test_main(argc, argv, g_tests, g_benches);
|
||||
}
|
||||
@@ -48,6 +48,7 @@ OK. 076cb375 test/data/bricks-color.bmp
|
||||
OK. bdbbfadb test/data/bricks-color.etc1.pkm
|
||||
OK. 41e6110e test/data/bricks-color.etc1s.pkm
|
||||
OK. 5670f263 test/data/bricks-color.etc2.pkm
|
||||
OK. 16e19d11 test/data/bricks-color.handsum
|
||||
OK. 72a1f9cc test/data/bricks-color.jpeg
|
||||
OK. 076cb375 test/data/bricks-color.lossless.webp
|
||||
OK. 9d451b1c test/data/bricks-color.lossy.webp
|
||||
@@ -121,6 +122,7 @@ OK. ed4b78fc test/data/hippopotamus.regular.gif
|
||||
OK. dcbb225a test/data/hippopotamus.regular.png
|
||||
BAD e4c5926b test/data/hippopotamus.regular.truncated.png
|
||||
OK. f6bb81e2 test/data/mona-lisa.21x32.etc2.pkm
|
||||
OK. e93a8448 test/data/mona-lisa.21x32.handsum
|
||||
OK. 012ce4cf test/data/mona-lisa.21x32.png
|
||||
OK. 0a22e689 test/data/mona-lisa.21x32.q50.jpeg
|
||||
OK. 059ecb80 test/data/mona-lisa.21x32.q90.jpeg
|
||||
|
||||
Reference in New Issue
Block a user