Consolidate PNG encoding code

Move EncodePng() from testing/helpers/write.cc to
testing/utils/png_encode.cpp. Then reuse it in
testing/utils/bitmap_saver.cpp. Now BitmapSaver::WriteBitmapToPng()
knows how to handle pre-multiplied bitmaps.

Change-Id: I23907a52c93fa3009004ea44cc9853e4afd87fef
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/141273
Reviewed-by: Andy Phan <andyphan@chromium.org>
Commit-Queue: Lei Zhang <thestig@chromium.org>
diff --git a/testing/BUILD.gn b/testing/BUILD.gn
index 6c42ebd..2d0efe5 100644
--- a/testing/BUILD.gn
+++ b/testing/BUILD.gn
@@ -33,6 +33,8 @@
     "utils/file_util.h",
     "utils/hash.cpp",
     "utils/hash.h",
+    "utils/png_encode.cpp",
+    "utils/png_encode.h",
   ]
   data = [ "resources/" ]
   public_deps = [
diff --git a/testing/helpers/write.cc b/testing/helpers/write.cc
index 6eb56a3..365eedf 100644
--- a/testing/helpers/write.cc
+++ b/testing/helpers/write.cc
@@ -19,13 +19,12 @@
 #include "public/fpdf_edit.h"
 #include "public/fpdf_thumbnail.h"
 #include "testing/fx_string_testhelpers.h"
-#include "testing/image_diff/image_diff_png.h"
+#include "testing/utils/png_encode.h"
 
 #ifdef PDF_ENABLE_SKIA
 #include "third_party/skia/include/core/SkData.h"         // nogncheck
 #include "third_party/skia/include/core/SkImage.h"        // nogncheck
 #include "third_party/skia/include/core/SkPicture.h"      // nogncheck
-#include "third_party/skia/include/core/SkPixmap.h"       // nogncheck
 #include "third_party/skia/include/core/SkSerialProcs.h"  // nogncheck
 #include "third_party/skia/include/core/SkStream.h"       // nogncheck
 #ifdef PDF_ENABLE_RUST_PNG
@@ -190,64 +189,6 @@
   NOTREACHED();
 }
 
-#ifdef PDF_ENABLE_SKIA
-std::vector<uint8_t> ConvertToStraightAlpha(pdfium::span<const uint8_t> input,
-                                            int width,
-                                            int height,
-                                            int row_byte_width) {
-  SkImageInfo premul_alpha_image_info = SkImageInfo::Make(
-      width, height, kBGRA_8888_SkColorType, kPremul_SkAlphaType);
-  SkPixmap src_pixmap(premul_alpha_image_info, input.data(), row_byte_width);
-
-  std::vector<uint8_t> result(input.size());
-  SkImageInfo straight_alpha_image_info = SkImageInfo::Make(
-      width, height, kBGRA_8888_SkColorType, kUnpremul_SkAlphaType);
-  SkPixmap dst_pixmap(straight_alpha_image_info, result.data(), row_byte_width);
-
-  CHECK(src_pixmap.readPixels(dst_pixmap));
-  return result;
-}
-#endif
-
-std::vector<uint8_t> EncodePng(pdfium::span<const uint8_t> input,
-                               int width,
-                               int height,
-                               int stride,
-                               int format) {
-  std::vector<uint8_t> png;
-  switch (format) {
-    case FPDFBitmap_Unknown:
-      break;
-    case FPDFBitmap_Gray:
-      png = image_diff_png::EncodeGrayPNG(input, width, height, stride);
-      break;
-    case FPDFBitmap_BGR:
-      png = image_diff_png::EncodeBGRPNG(input, width, height, stride);
-      break;
-    case FPDFBitmap_BGRx:
-      png = image_diff_png::EncodeBGRAPNG(input, width, height, stride,
-                                          /*discard_transparency=*/true);
-      break;
-    case FPDFBitmap_BGRA:
-      png = image_diff_png::EncodeBGRAPNG(input, width, height, stride,
-                                          /*discard_transparency=*/false);
-      break;
-#ifdef PDF_ENABLE_SKIA
-    case FPDFBitmap_BGRA_Premul: {
-      std::vector<uint8_t> input_with_straight_alpha =
-          ConvertToStraightAlpha(input, width, height, stride);
-      png = image_diff_png::EncodeBGRAPNG(input_with_straight_alpha, width,
-                                          height, stride,
-                                          /*discard_transparency=*/false);
-      break;
-    }
-#endif
-    default:
-      NOTREACHED();
-  }
-  return png;
-}
-
 #ifdef _WIN32
 int CALLBACK EnhMetaFileProc(HDC hdc,
                              HANDLETABLE* handle_table,
diff --git a/testing/utils/bitmap_saver.cpp b/testing/utils/bitmap_saver.cpp
index 617c4f7..f5809e2 100644
--- a/testing/utils/bitmap_saver.cpp
+++ b/testing/utils/bitmap_saver.cpp
@@ -9,7 +9,7 @@
 
 #include "core/fxcrt/check.h"
 #include "core/fxcrt/fx_safe_types.h"
-#include "testing/image_diff/image_diff_png.h"
+#include "testing/utils/png_encode.h"
 
 // static
 void BitmapSaver::WriteBitmapToPng(FPDF_BITMAP bitmap,
@@ -26,17 +26,8 @@
       pdfium::span(static_cast<const uint8_t*>(FPDFBitmap_GetBuffer(bitmap)),
                    pdfium::ValueOrDieForType<size_t>(size));
 
-  std::vector<uint8_t> png;
-  int format = FPDFBitmap_GetFormat(bitmap);
-  if (format == FPDFBitmap_Gray) {
-    png = image_diff_png::EncodeGrayPNG(input, width, height, stride);
-  } else if (format == FPDFBitmap_BGR) {
-    png = image_diff_png::EncodeBGRPNG(input, width, height, stride);
-  } else {
-    png = image_diff_png::EncodeBGRAPNG(input, width, height, stride,
-                                        /*discard_transparency=*/false);
-  }
-
+  std::vector<uint8_t> png =
+      EncodePng(input, width, height, stride, FPDFBitmap_GetFormat(bitmap));
   DCHECK(!png.empty());
   DCHECK(filename.size() < 256u);
 
diff --git a/testing/utils/png_encode.cpp b/testing/utils/png_encode.cpp
new file mode 100644
index 0000000..fb15f7e
--- /dev/null
+++ b/testing/utils/png_encode.cpp
@@ -0,0 +1,79 @@
+// Copyright 2026 The PDFium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "testing/utils/png_encode.h"
+
+#include "core/fxcrt/check.h"
+#include "core/fxcrt/notreached.h"
+#include "public/fpdfview.h"
+#include "testing/image_diff/image_diff_png.h"
+
+#ifdef PDF_ENABLE_SKIA
+#include "third_party/skia/include/core/SkAlphaType.h"  // nogncheck
+#include "third_party/skia/include/core/SkColorType.h"  // nogncheck
+#include "third_party/skia/include/core/SkImageInfo.h"  // nogncheck
+#include "third_party/skia/include/core/SkPixmap.h"     // nogncheck
+#endif
+
+namespace {
+
+#ifdef PDF_ENABLE_SKIA
+std::vector<uint8_t> ConvertToStraightAlpha(pdfium::span<const uint8_t> input,
+                                            int width,
+                                            int height,
+                                            int row_byte_width) {
+  SkImageInfo premul_alpha_image_info = SkImageInfo::Make(
+      width, height, kBGRA_8888_SkColorType, kPremul_SkAlphaType);
+  SkPixmap src_pixmap(premul_alpha_image_info, input.data(), row_byte_width);
+
+  std::vector<uint8_t> result(input.size());
+  SkImageInfo straight_alpha_image_info = SkImageInfo::Make(
+      width, height, kBGRA_8888_SkColorType, kUnpremul_SkAlphaType);
+  SkPixmap dst_pixmap(straight_alpha_image_info, result.data(), row_byte_width);
+
+  CHECK(src_pixmap.readPixels(dst_pixmap));
+  return result;
+}
+#endif
+
+}  // namespace
+
+std::vector<uint8_t> EncodePng(pdfium::span<const uint8_t> input,
+                               int width,
+                               int height,
+                               int stride,
+                               int format) {
+  std::vector<uint8_t> png;
+  switch (format) {
+    case FPDFBitmap_Unknown:
+      break;
+    case FPDFBitmap_Gray:
+      png = image_diff_png::EncodeGrayPNG(input, width, height, stride);
+      break;
+    case FPDFBitmap_BGR:
+      png = image_diff_png::EncodeBGRPNG(input, width, height, stride);
+      break;
+    case FPDFBitmap_BGRx:
+      png = image_diff_png::EncodeBGRAPNG(input, width, height, stride,
+                                          /*discard_transparency=*/true);
+      break;
+    case FPDFBitmap_BGRA:
+      png = image_diff_png::EncodeBGRAPNG(input, width, height, stride,
+                                          /*discard_transparency=*/false);
+      break;
+#ifdef PDF_ENABLE_SKIA
+    case FPDFBitmap_BGRA_Premul: {
+      std::vector<uint8_t> input_with_straight_alpha =
+          ConvertToStraightAlpha(input, width, height, stride);
+      png = image_diff_png::EncodeBGRAPNG(input_with_straight_alpha, width,
+                                          height, stride,
+                                          /*discard_transparency=*/false);
+      break;
+    }
+#endif
+    default:
+      NOTREACHED();
+  }
+  return png;
+}
diff --git a/testing/utils/png_encode.h b/testing/utils/png_encode.h
new file mode 100644
index 0000000..4547d67
--- /dev/null
+++ b/testing/utils/png_encode.h
@@ -0,0 +1,20 @@
+// Copyright 2026 The PDFium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef TESTING_UTILS_PNG_ENCODE_H_
+#define TESTING_UTILS_PNG_ENCODE_H_
+
+#include <stdint.h>
+
+#include <vector>
+
+#include "core/fxcrt/span.h"
+
+std::vector<uint8_t> EncodePng(pdfium::span<const uint8_t> input,
+                               int width,
+                               int height,
+                               int stride,
+                               int format);
+
+#endif  // TESTING_UTILS_PNG_ENCODE_H_