Add script/print-average-pixel.cc
diff --git a/script/print-average-pixel.cc b/script/print-average-pixel.cc
new file mode 100644
index 0000000..ea9e5ed
--- /dev/null
+++ b/script/print-average-pixel.cc
@@ -0,0 +1,194 @@
+// Copyright 2022 The Wuffs Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// ----------------
+
+/*
+print-average-pixel prints the average color of an image's pixels (as well as
+the image file format, width and height). It's a toy program to demonstrate how
+to use the wuffs_aux C++ API to decode an image and iterate over its pixels.
+*/
+
+#include <inttypes.h>
+#include <stdio.h>
+
+// 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__STATIC_FUNCTIONS macro is optional, but when
+// combined with WUFFS_IMPLEMENTATION, it demonstrates making all of Wuffs'
+// functions have static storage.
+//
+// This can help the compiler ignore or discard unused code, which can produce
+// faster compiles and smaller binaries. Other motivations are discussed in the
+// "ALLOW STATIC IMPLEMENTATION" section of
+// https://raw.githubusercontent.com/nothings/stb/master/docs/stb_howto.txt
+#define WUFFS_CONFIG__STATIC_FUNCTIONS
+
+// 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__ADLER32
+#define WUFFS_CONFIG__MODULE__AUX__BASE
+#define WUFFS_CONFIG__MODULE__AUX__IMAGE
+#define WUFFS_CONFIG__MODULE__BASE
+#define WUFFS_CONFIG__MODULE__BMP
+#define WUFFS_CONFIG__MODULE__CRC32
+#define WUFFS_CONFIG__MODULE__DEFLATE
+#define WUFFS_CONFIG__MODULE__GIF
+#define WUFFS_CONFIG__MODULE__LZW
+#define WUFFS_CONFIG__MODULE__NIE
+#define WUFFS_CONFIG__MODULE__PNG
+#define WUFFS_CONFIG__MODULE__TGA
+#define WUFFS_CONFIG__MODULE__WBMP
+#define WUFFS_CONFIG__MODULE__ZLIB
+
+// 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"
+
+class MyCallbacks : public wuffs_aux::DecodeImageCallbacks {
+ public:
+ MyCallbacks() : m_fourcc(0) {}
+
+ uint32_t m_fourcc;
+
+ private:
+ wuffs_base__image_decoder::unique_ptr //
+ SelectDecoder(uint32_t fourcc,
+ wuffs_base__slice_u8 prefix_data,
+ bool prefix_closed) override {
+ // Save the fourcc value (you can think of it as like a 'MIME type' but in
+ // uint32_t form) before calling the superclass' implementation.
+ //
+ // The "if (m_fourcc == 0)" is because SelectDecoder can be called multiple
+ // times. Files that are nominally BMP images can contain complete JPEG or
+ // PNG images. This program prints the outer file format, the first one
+ // encountered, not the inner one.
+ if (m_fourcc == 0) {
+ m_fourcc = fourcc;
+ }
+ return wuffs_aux::DecodeImageCallbacks::SelectDecoder(fourcc, prefix_data,
+ prefix_closed);
+ }
+
+ wuffs_base__pixel_format //
+ SelectPixfmt(const wuffs_base__image_config& image_config) override {
+ // This is the same as the superclass' implementation, but makes it
+ // explicit that this program uses a single-plane pixel buffer (as opposed
+ // to e.g. 3-plane YCbCr) with 4 bytes per pixel (in B, G, R, A order) and
+ // premultiplied alpha.
+ return wuffs_base__make_pixel_format(WUFFS_BASE__PIXEL_FORMAT__BGRA_PREMUL);
+ }
+
+ AllocPixbufResult //
+ AllocPixbuf(const wuffs_base__image_config& image_config,
+ bool allow_uninitialized_memory) override {
+ // This just calls the superclass' implementation, but if you wanted more
+ // control about how the pixel buffer's memory is allocated and freed,
+ // change the code here. For example, if you (the wuffs_aux::DecodeImage
+ // caller) want to use an already-allocated buffer, instead of Wuffs (the
+ // callee) allocating a new buffer.
+ return wuffs_aux::DecodeImageCallbacks::AllocPixbuf(
+ image_config, allow_uninitialized_memory);
+ }
+};
+
+void //
+handle(const char* filename, FILE* f) {
+ MyCallbacks callbacks;
+ wuffs_aux::sync_io::FileInput input(f);
+ wuffs_aux::DecodeImageResult res = wuffs_aux::DecodeImage(callbacks, input);
+ if (!res.error_message.empty()) {
+ printf("%-32s %s\n", filename, res.error_message.c_str());
+ return;
+ } else if (res.pixbuf.pixcfg.pixel_format().repr !=
+ WUFFS_BASE__PIXEL_FORMAT__BGRA_PREMUL) {
+ printf("%-32s internal error: inconsistent pixel format\n", filename);
+ return;
+ }
+
+ wuffs_base__table_u8 table = res.pixbuf.plane(0);
+ uint32_t w = res.pixbuf.pixcfg.width();
+ uint32_t h = res.pixbuf.pixcfg.height();
+
+ uint64_t count = 0;
+ uint64_t color_b = 0;
+ uint64_t color_g = 0;
+ uint64_t color_r = 0;
+ uint64_t color_a = 0;
+ for (uint32_t y = 0; y < h; y++) {
+ const uint8_t* ptr = table.ptr + y * table.stride;
+ for (uint32_t x = 0; x < w; x++) {
+ count++;
+ color_b += *ptr++;
+ color_g += *ptr++;
+ color_r += *ptr++;
+ color_a += *ptr++;
+ }
+ }
+ if (count > 0) {
+ color_b = (color_b + (count / 2)) / count;
+ color_g = (color_g + (count / 2)) / count;
+ color_r = (color_r + (count / 2)) / count;
+ color_a = (color_a + (count / 2)) / count;
+ }
+
+ printf("%-32s %c%c%c%c %5" PRIu32 " x %5" PRIu32
+ " AverageARGB: %02X%02X%02X%02X\n", //
+ filename, //
+ (0xFF & (callbacks.m_fourcc >> 24)), //
+ (0xFF & (callbacks.m_fourcc >> 16)), //
+ (0xFF & (callbacks.m_fourcc >> 8)), //
+ (0xFF & (callbacks.m_fourcc >> 0)), //
+ w, h, //
+ (int)(color_a), //
+ (int)(color_r), //
+ (int)(color_g), //
+ (int)(color_b));
+
+ // While it's valid to deference table.ptr in this function, the end of scope
+ // here means that the res.pixbuf_mem_owner destructor will free the backing
+ // memory (unless you modified the AllocPixbuf method above).
+ //
+ // If you wanted to return the pixel buffer to the caller, either return the
+ // wuffs_aux::MemOwner (a type alias for "std::unique_ptr<void,
+ // decltype(&free)>") too, or call res.pixbuf_mem_owner.release() before
+ // returning and manually free the backing memory at an appropriate time.
+}
+
+int //
+main(int argc, char** argv) {
+ for (int i = 1; i < argc; i++) {
+ FILE* f = fopen(argv[i], "r");
+ if (!f) {
+ printf("%-32s could not open file: %s\n", argv[i], strerror(errno));
+ continue;
+ }
+ handle(argv[i], f);
+ fclose(f);
+ }
+ return 0;
+}