Diff
Modified: trunk/Tools/ChangeLog (215178 => 215179)
--- trunk/Tools/ChangeLog 2017-04-10 11:44:21 UTC (rev 215178)
+++ trunk/Tools/ChangeLog 2017-04-10 11:48:22 UTC (rev 215179)
@@ -1,5 +1,41 @@
2017-04-10 Carlos Garcia Campos <cgar...@igalia.com>
+ [GTK] Remove the GDK dependency from ImageDiff
+ https://bugs.webkit.org/show_bug.cgi?id=85299
+
+ Reviewed by Žan Doberšek.
+
+ Add a cairo only implementation of ImageDiff. We currently have 3 different implementations of ImageDiff: the
+ Gdk based one used by GTK+ port, the cairo based one used by WinCairo and the CG based one. Most of the code is
+ actually common in all of them, but it's duplicated. So, I've taken advantage of this patch to refactor the
+ ImageDiff code to share the common implementation. This patch adds the cross-platform code, and the cairo
+ implementation and enables it in the GTK+ port. In follow up patches we can move WinCairo to this implementation
+ and also add CG implementation.
+
+ * ImageDiff/CMakeLists.txt:
+ * ImageDiff/Cairo.cmake: Added.
+ * ImageDiff/ImageDiff.cpp: Added.
+ (main):
+ * ImageDiff/PlatformGTK.cmake:
+ * ImageDiff/PlatformImage.cpp: Added.
+ (ImageDiff::PlatformImage::isCompatible):
+ (ImageDiff::PlatformImage::difference):
+ * ImageDiff/PlatformImage.h: Added.
+ * ImageDiff/cairo/PlatformImageCairo.cpp: Added.
+ (ImageDiff::PlatformImage::createFromStdin):
+ (ImageDiff::PlatformImage::createFromDiffData):
+ (ImageDiff::PlatformImage::PlatformImage):
+ (ImageDiff::PlatformImage::~PlatformImage):
+ (ImageDiff::PlatformImage::width):
+ (ImageDiff::PlatformImage::height):
+ (ImageDiff::PlatformImage::rowBytes):
+ (ImageDiff::PlatformImage::hasAlpha):
+ (ImageDiff::PlatformImage::pixels):
+ (ImageDiff::PlatformImage::writeAsPNGToStdout):
+ * ImageDiff/gtk/ImageDiff.cpp: Removed.
+
+2017-04-10 Carlos Garcia Campos <cgar...@igalia.com>
+
REGRESSION(r214426): [GTK] Test media/video-click-dblckick-standalone.html started to fail in the bots after r214426
https://bugs.webkit.org/show_bug.cgi?id=170667
Modified: trunk/Tools/ImageDiff/CMakeLists.txt (215178 => 215179)
--- trunk/Tools/ImageDiff/CMakeLists.txt 2017-04-10 11:44:21 UTC (rev 215178)
+++ trunk/Tools/ImageDiff/CMakeLists.txt 2017-04-10 11:48:22 UTC (rev 215179)
@@ -2,6 +2,15 @@
set(IMAGE_DIFF_SYSTEM_INCLUDE_DIRECTORIES "")
+set(IMAGE_DIFF_SOURCES
+ ${IMAGE_DIFF_DIR}/ImageDiff.cpp
+ ${IMAGE_DIFF_DIR}/PlatformImage.cpp
+)
+
+list(APPEND IMAGE_DIFF_INCLUDE_DIRECTORIES
+ ${IMAGE_DIFF_DIR}
+)
+
set(IMAGE_DIFF_LIBRARIES
WTF
)
Added: trunk/Tools/ImageDiff/Cairo.cmake (0 => 215179)
--- trunk/Tools/ImageDiff/Cairo.cmake (rev 0)
+++ trunk/Tools/ImageDiff/Cairo.cmake 2017-04-10 11:48:22 UTC (rev 215179)
@@ -0,0 +1,11 @@
+list(APPEND IMAGE_DIFF_SOURCES
+ ${IMAGE_DIFF_DIR}/cairo/PlatformImageCairo.cpp
+)
+
+list(APPEND IMAGE_DIFF_SYSTEM_INCLUDE_DIRECTORIES
+ ${CAIRO_INCLUDE_DIRS}
+)
+
+list(APPEND IMAGE_DIFF_LIBRARIES
+ ${CAIRO_LIBRARIES}
+)
Added: trunk/Tools/ImageDiff/ImageDiff.cpp (0 => 215179)
--- trunk/Tools/ImageDiff/ImageDiff.cpp (rev 0)
+++ trunk/Tools/ImageDiff/ImageDiff.cpp 2017-04-10 11:48:22 UTC (rev 215179)
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2017 Igalia S.L.
+ * Copyright (C) 2005, 2007, 2015 Apple Inc. All rights reserved.
+ * Copyright (C) 2005 Ben La Monica <ben.lamon...@gmail.com>. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "PlatformImage.h"
+#include <algorithm>
+#include <cstdlib>
+#include <stdio.h>
+#include <string.h>
+
+using namespace ImageDiff;
+
+#if OS(WINDOWS)
+#define FORMAT_SIZE_T "Iu"
+#else
+#define FORMAT_SIZE_T "zu"
+#endif
+
+int main(int argc, const char* argv[])
+{
+#if PLATFORM(WIN)
+ _setmode(0, _O_BINARY);
+ _setmode(1, _O_BINARY);
+#endif
+
+ float tolerance = 0.0f;
+
+ for (int i = 1; i < argc; ++i) {
+ if (!strcmp(argv[i], "-t") || !strcmp(argv[i], "--tolerance")) {
+ if (i >= argc - 1)
+ exit(1);
+ tolerance = strtof(argv[i + 1], 0);
+ ++i;
+ continue;
+ }
+ }
+
+ char buffer[2048];
+ std::unique_ptr<PlatformImage> actualImage;
+ std::unique_ptr<PlatformImage> baselineImage;
+
+ while (fgets(buffer, sizeof(buffer), stdin)) {
+ // Convert the first newline into a NUL character so that strtok doesn't produce it.
+ char* newLineCharacter = strchr(buffer, '\n');
+ if (newLineCharacter)
+ *newLineCharacter = '\0';
+
+ if (!strncmp("Content-Length: ", buffer, 16)) {
+ strtok(buffer, " ");
+
+ int imageSize = strtol(strtok(0, " "), 0, 10);
+ if (imageSize <= 0) {
+ fprintf(stderr, "Error: image size must be specified.\n");
+ return EXIT_FAILURE;
+ }
+
+ if (!actualImage) {
+ if (!(actualImage = PlatformImage::createFromStdin(imageSize))) {
+ fprintf(stderr, "Error: could not read actual image.\n");
+ return EXIT_FAILURE;
+ }
+ } else if (!baselineImage) {
+ if (!(baselineImage = PlatformImage::createFromStdin(imageSize))) {
+ fprintf(stderr, "Error: could not read baseline image.\n");
+ return EXIT_FAILURE;
+ }
+ }
+ }
+
+ if (actualImage && baselineImage) {
+ if (!actualImage->isCompatible(*baselineImage)) {
+ if (actualImage->width() != baselineImage->width() || actualImage->height() != baselineImage->height()) {
+ fprintf(stderr, "Error: test and reference images have different sizes. Test image is %" FORMAT_SIZE_T "x%" FORMAT_SIZE_T ", reference image is %" FORMAT_SIZE_T "x%" FORMAT_SIZE_T "\n",
+ actualImage->width(), actualImage->height(), baselineImage->width(), baselineImage->height());
+ } else if (actualImage->hasAlpha() != baselineImage->hasAlpha()) {
+ fprintf(stderr, "Error: test and reference images differ in alpha. Test image %s alpha, reference image %s alpha.\n",
+ actualImage->hasAlpha() ? "has" : "does not have", baselineImage->hasAlpha() ? "has" : "does not have");
+ }
+
+ return EXIT_FAILURE;
+ }
+
+ float difference = 100.0f;
+ std::unique_ptr<PlatformImage> diffImage = actualImage->difference(*baselineImage, difference);
+ if (difference <= tolerance)
+ difference = 0.0f;
+ else {
+ difference = roundf(difference * 100.0f) / 100.0f;
+ difference = std::max<float>(difference, 0.01f); // round to 2 decimal places
+ }
+
+ if (difference > 0.0f) {
+ if (diffImage)
+ diffImage->writeAsPNGToStdout();
+ fprintf(stdout, "diff: %01.2f%% failed\n", difference);
+ } else
+ fprintf(stdout, "diff: %01.2f%% passed\n", difference);
+
+ actualImage = nullptr;
+ baselineImage = nullptr;
+ }
+
+ fflush(stdout);
+ }
+
+ return EXIT_SUCCESS;
+}
Modified: trunk/Tools/ImageDiff/PlatformGTK.cmake (215178 => 215179)
--- trunk/Tools/ImageDiff/PlatformGTK.cmake 2017-04-10 11:44:21 UTC (rev 215178)
+++ trunk/Tools/ImageDiff/PlatformGTK.cmake 2017-04-10 11:48:22 UTC (rev 215179)
@@ -1,11 +1,2 @@
-set(IMAGE_DIFF_SOURCES
- ${IMAGE_DIFF_DIR}/gtk/ImageDiff.cpp
-)
+include(Cairo.cmake)
-list(APPEND IMAGE_DIFF_SYSTEM_INCLUDE_DIRECTORIES
- ${GTK_INCLUDE_DIRS}
-)
-
-list(APPEND IMAGE_DIFF_LIBRARIES
- ${GTK_LIBRARIES}
-)
Added: trunk/Tools/ImageDiff/PlatformImage.cpp (0 => 215179)
--- trunk/Tools/ImageDiff/PlatformImage.cpp (rev 0)
+++ trunk/Tools/ImageDiff/PlatformImage.cpp 2017-04-10 11:48:22 UTC (rev 215179)
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2005, 2007, 2015 Apple Inc. All rights reserved.
+ * Copyright (C) 2005 Ben La Monica <ben.lamon...@gmail.com>. All rights reserved.
+ * Copyright (C) 2011 Brent Fulgham. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "PlatformImage.h"
+
+#include <algorithm>
+
+namespace ImageDiff {
+
+bool PlatformImage::isCompatible(const PlatformImage& other) const
+{
+ return width() == other.width()
+ && height() == other.height()
+ && rowBytes() == other.rowBytes()
+ && hasAlpha() == other.hasAlpha();
+}
+
+std::unique_ptr<PlatformImage> PlatformImage::difference(const PlatformImage& other, float& percentageDifference)
+{
+ size_t width = this->width();
+ size_t height = this->height();
+
+ // Compare the content of the 2 bitmaps
+ void* diffBuffer = malloc(width * height);
+ float count = 0.0f;
+ float sum = 0.0f;
+ float maxDistance = 0.0f;
+ unsigned char* basePixel = this->pixels();
+ unsigned char* pixel = other.pixels();
+ unsigned char* diffPixel = reinterpret_cast<unsigned char*>(diffBuffer);
+ for (size_t y = 0; y < height; ++y) {
+ for (size_t x = 0; x < width; ++x) {
+ float red = (pixel[0] - basePixel[0]) / std::max<float>(255 - basePixel[0], basePixel[0]);
+ float green = (pixel[1] - basePixel[1]) / std::max<float>(255 - basePixel[1], basePixel[1]);
+ float blue = (pixel[2] - basePixel[2]) / std::max<float>(255 - basePixel[2], basePixel[2]);
+ float alpha = (pixel[3] - basePixel[3]) / std::max<float>(255 - basePixel[3], basePixel[3]);
+ float distance = sqrtf(red * red + green * green + blue * blue + alpha * alpha) / 2.0f;
+
+ *diffPixel++ = static_cast<unsigned char>(distance * 255.0f);
+
+ if (distance >= 1.0f / 255.0f) {
+ count += 1.0f;
+ sum += distance;
+ if (distance > maxDistance)
+ maxDistance = distance;
+ }
+
+ basePixel += 4;
+ pixel += 4;
+ }
+ }
+
+ // Compute the difference as a percentage combining both the number of different pixels and their difference amount i.e. the average distance over the entire image
+ if (count > 0.0f)
+ percentageDifference = 100.0f * sum / (height * width);
+ else
+ percentageDifference = 0.0f;
+
+ if (!percentageDifference) {
+ free(diffBuffer);
+ return nullptr;
+ }
+
+ // Generate a normalized diff image if there is any difference
+ if (maxDistance < 1.0f) {
+ diffPixel = reinterpret_cast<unsigned char*>(diffBuffer);
+ for (size_t p = 0; p < height * width; ++p)
+ diffPixel[p] /= maxDistance;
+ }
+
+ return PlatformImage::createFromDiffData(diffBuffer, width, height);
+}
+
+} // namespace ImageDiff
Added: trunk/Tools/ImageDiff/PlatformImage.h (0 => 215179)
--- trunk/Tools/ImageDiff/PlatformImage.h (rev 0)
+++ trunk/Tools/ImageDiff/PlatformImage.h 2017-04-10 11:48:22 UTC (rev 215179)
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2017 Igalia S.L.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <cmath>
+#include <memory>
+#include <wtf/Platform.h>
+
+#if USE(CAIRO)
+typedef struct _cairo_surface cairo_surface_t;
+#endif
+
+namespace ImageDiff {
+
+class PlatformImage {
+public:
+ static std::unique_ptr<PlatformImage> createFromStdin(size_t);
+ static std::unique_ptr<PlatformImage> createFromDiffData(void*, size_t width, size_t height);
+
+#if USE(CAIRO)
+ PlatformImage(cairo_surface_t*);
+#endif
+ ~PlatformImage();
+
+ size_t width() const;
+ size_t height() const;
+ size_t rowBytes() const;
+ bool hasAlpha() const;
+ unsigned char* pixels() const;
+ bool isCompatible(const PlatformImage&) const;
+ std::unique_ptr<PlatformImage> difference(const PlatformImage&, float& percentageDifference);
+ void writeAsPNGToStdout();
+
+private:
+#if USE(CAIRO)
+ cairo_surface_t* m_image;
+#endif
+};
+
+} // namespace ImageDiff
Added: trunk/Tools/ImageDiff/cairo/PlatformImageCairo.cpp (0 => 215179)
--- trunk/Tools/ImageDiff/cairo/PlatformImageCairo.cpp (rev 0)
+++ trunk/Tools/ImageDiff/cairo/PlatformImageCairo.cpp 2017-04-10 11:48:22 UTC (rev 215179)
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2017 Igalia S.L.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "PlatformImage.h"
+
+#include <cairo.h>
+#include <stdio.h>
+
+#if OS(WINDOWS)
+#define FORMAT_SIZE_T "Iu"
+#else
+#define FORMAT_SIZE_T "zu"
+#endif
+
+namespace ImageDiff {
+
+std::unique_ptr<PlatformImage> PlatformImage::createFromStdin(size_t imageSize)
+{
+ struct ReadContext {
+ char buffer[2048];
+ unsigned long incomingBytes;
+ unsigned long readBytes;
+ } context { { }, imageSize, 0 };
+
+ cairo_surface_t* surface = cairo_image_surface_create_from_png_stream(
+ [](void* closure, unsigned char* data, unsigned length) -> cairo_status_t {
+ auto& context = *static_cast<ReadContext*>(closure);
+ context.readBytes += length;
+
+ fread(data, 1, length, stdin);
+ return CAIRO_STATUS_SUCCESS;
+ }, &context);
+
+ if (cairo_surface_status(surface) != CAIRO_STATUS_SUCCESS) {
+ cairo_surface_destroy(surface);
+ return nullptr;
+ }
+
+ return std::make_unique<PlatformImage>(surface);
+}
+
+std::unique_ptr<PlatformImage> PlatformImage::createFromDiffData(void* data, size_t width, size_t height)
+{
+ cairo_surface_t* surface = cairo_image_surface_create_for_data(reinterpret_cast<unsigned char*>(data), CAIRO_FORMAT_A8,
+ width, height, cairo_format_stride_for_width(CAIRO_FORMAT_A8, width));
+ static cairo_user_data_key_t imageDataKey;
+ cairo_surface_set_user_data(surface, &imageDataKey, data, [](void* data) { free(data); });
+ return std::make_unique<PlatformImage>(surface);
+}
+
+PlatformImage::PlatformImage(cairo_surface_t* surface)
+ : m_image(surface)
+{
+}
+
+PlatformImage::~PlatformImage()
+{
+ cairo_surface_destroy(m_image);
+}
+
+size_t PlatformImage::width() const
+{
+ return cairo_image_surface_get_width(m_image);
+}
+
+size_t PlatformImage::height() const
+{
+ return cairo_image_surface_get_height(m_image);
+}
+
+size_t PlatformImage::rowBytes() const
+{
+ return cairo_image_surface_get_stride(m_image);
+}
+
+bool PlatformImage::hasAlpha() const
+{
+ // What matters here is whether the image data has an alpha channel. In cairo, both
+ // CAIRO_FORMAT_ARGB32 and CAIRO_FORMAT_RGB24 have an alpha channel even if it's
+ // always 0 in the CAIRO_FORMAT_RGB24 case.
+ return cairo_image_surface_get_format(m_image) == CAIRO_FORMAT_ARGB32 || cairo_image_surface_get_format(m_image) == CAIRO_FORMAT_RGB24;
+}
+
+unsigned char* PlatformImage::pixels() const
+{
+ return cairo_image_surface_get_data(m_image);
+}
+
+void PlatformImage::writeAsPNGToStdout()
+{
+ struct WriteContext {
+ unsigned long writtenBytes { 0 };
+ } context;
+
+ // First we sum up the bytes that are to be written.
+ cairo_surface_write_to_png_stream(m_image,
+ [](void* closure, const unsigned char*, unsigned length) -> cairo_status_t {
+ auto& context = *static_cast<WriteContext*>(closure);
+ context.writtenBytes += length;
+ return CAIRO_STATUS_SUCCESS;
+ }, &context);
+ fprintf(stdout, "Content-Length: %" FORMAT_SIZE_T "\n", context.writtenBytes);
+ cairo_surface_write_to_png_stream(m_image,
+ [](void*, const unsigned char* data, unsigned length) -> cairo_status_t {
+ fwrite(data, 1, length, stdout);
+ return CAIRO_STATUS_SUCCESS;
+ }, nullptr);
+}
+
+} // namespace ImageDiff