]> git.seodisparate.com - EN605.617.81.FA21_StephenSeo_DitheringProject/commitdiff
Impl SaveAsPNG
authorStephen Seo <seo.disparate@gmail.com>
Fri, 12 Nov 2021 04:12:15 +0000 (13:12 +0900)
committerStephen Seo <seo.disparate@gmail.com>
Fri, 12 Nov 2021 04:12:15 +0000 (13:12 +0900)
src/image.cc
src/image.h
src/main.cc

index 05fc0d74294584b9252b535d86f81254fbdab50c..e39b1083a2253928d13668c4157d8e8db4ecc170 100644 (file)
@@ -60,6 +60,80 @@ unsigned int Image::GetHeight() const { return height_; }
 
 bool Image::IsGrayscale() const { return is_grayscale_; }
 
+bool Image::SaveAsPNG(const std::string &filename, bool overwrite) {
+  if (!overwrite) {
+    std::ifstream ifs(filename);
+    if (ifs.is_open()) {
+      std::cout << "ERROR: File \"" << filename
+                << "\" exists but overwrite == false" << std::endl;
+      return false;
+    }
+  }
+
+  FILE *file = std::fopen(filename.c_str(), "wb");
+  if (!file) {
+    std::cout << "ERROR: Failed to open file \"" << filename
+              << "\" for writing png" << std::endl;
+    return false;
+  }
+
+  // init required structs for png encoding
+  png_structp png_ptr =
+      png_create_write_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
+  if (!png_ptr) {
+    std::cout << "ERROR: Failed to initialize libpng (png_ptr) for encoding "
+                 "PNG file \""
+              << filename << '"' << std::endl;
+    std::fclose(file);
+    return false;
+  }
+
+  png_infop png_info_ptr = png_create_info_struct(png_ptr);
+  if (!png_info_ptr) {
+    std::cout << "ERROR: Failed to initialize libpng (png_infop) for decoding "
+                 "PNG file \""
+              << filename << '"' << std::endl;
+    png_destroy_write_struct(&png_ptr, nullptr);
+    std::fclose(file);
+    return false;
+  }
+
+  // required to handle libpng errors
+  if (setjmp(png_jmpbuf(png_ptr))) {
+    png_destroy_write_struct(&png_ptr, &png_info_ptr);
+    std::fclose(file);
+    return false;
+  }
+
+  // give FILE handle to libpng
+  png_init_io(png_ptr, file);
+
+  // set image information
+  png_set_IHDR(png_ptr, png_info_ptr, width_, height_, 8,
+               PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE,
+               PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
+
+  // write png info
+  png_write_info(png_ptr, png_info_ptr);
+
+  // write rows of image data
+  for (unsigned int y = 0; y < height_; ++y) {
+    png_write_row(png_ptr, &data_.at(y * width_ * 4));
+  }
+
+  // finish writing image data
+  png_write_end(png_ptr, png_info_ptr);
+
+  // cleanup
+  png_destroy_write_struct(&png_ptr, &png_info_ptr);
+  fclose(file);
+  return true;
+}
+
+bool Image::SaveAsPNG(const char *filename, bool overwrite) {
+  return SaveAsPNG(std::string(filename), overwrite);
+}
+
 bool Image::SaveAsPPM(const std::string &filename, bool overwrite,
                       bool packed) {
   if (!IsValid()) {
@@ -243,6 +317,7 @@ void Image::DecodePNG(const std::string &filename) {
 
   // cleanup
   png_destroy_read_struct(&png_ptr, &png_info_ptr, &png_end_info_ptr);
+  fclose(file);
 
   // verify
   if (is_grayscale_) {
index 15bcad580bf5fcd91d17427bdd17feaab5455f96..66f453a54151c9f2f725737b99756ceb4f748e0a 100644 (file)
@@ -58,6 +58,16 @@ class Image {
   /// Returns true if the image is grayscale. If false, then the image is RGBA.
   bool IsGrayscale() const;
 
+  /*!
+   * \brief Saves the current image data as a PNG file.
+   *
+   * Returns false if the filename already exists and overwrite is false, or if
+   * saving failed.
+   */
+  bool SaveAsPNG(const std::string &filename, bool overwrite);
+  /// Same as SaveAsPNG()
+  bool SaveAsPNG(const char *filename, bool overwrite);
+
   /*!
    * \brief Saves the current image data as a PPM file.
    *
index 4eb1d8273a3fea83d0976c8c2dc8f7b3d57d80aa..0c920e92758013a66d43fa8a6913524b203d5b8b 100644 (file)
@@ -3,7 +3,7 @@
 int main(int argc, char **argv) {
   Image image("testin.png");
 
-  image.SaveAsPPM("testout.ppm", true, true);
+  image.SaveAsPNG("testout.png", true);
 
   return 0;
 }