]> git.seodisparate.com - EN605.617.81.FA21_StephenSeo_DitheringProject/commitdiff
WIP libpng image decoding
authorStephen Seo <seo.disparate@gmail.com>
Thu, 11 Nov 2021 13:15:51 +0000 (22:15 +0900)
committerStephen Seo <seo.disparate@gmail.com>
Thu, 11 Nov 2021 13:17:00 +0000 (22:17 +0900)
Also added Doxyfile for generation of doxygen-based documentation.

.gitignore
.lvimrc
CMakeLists.txt
Doxyfile [new file with mode: 0644]
doxygen/mainpage.md [new file with mode: 0644]
src/image.cc [new file with mode: 0644]
src/image.h [new file with mode: 0644]

index eb32573573d6d888f2461f08b0feb1b8174e2578..73479079b70ff20d6558f04d2eac4e29c9b52ba9 100644 (file)
@@ -1,3 +1,4 @@
 build*/
 compile_commands.json
 .cache/
+doxygen_out/
diff --git a/.lvimrc b/.lvimrc
index b32befcd66f4a81b04f39e21f57350e01ddeb90b..976bb70b2479e17a2b804a25ee384cacbab8365d 100644 (file)
--- a/.lvimrc
+++ b/.lvimrc
@@ -1,2 +1,4 @@
+set expandtab
 set tabstop=2
 set shiftwidth=2
+set textwidth=80
index a0317a4450dbdff8ce14ef4e1fc3217b0ad84e69..b850316f58c429cf772eef686d1abda6db44372c 100644 (file)
@@ -3,6 +3,7 @@ project(EN605.617.81.FA21_StephenSeo_DitheringProject)
 
 set(Project_SOURCES
   ${CMAKE_CURRENT_SOURCE_DIR}/src/main.cc
+  ${CMAKE_CURRENT_SOURCE_DIR}/src/image.cc
 )
 
 set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wpedantic")
@@ -16,3 +17,12 @@ endif()
 
 add_executable(DitheringProject
   ${Project_SOURCES})
+
+find_package(PNG REQUIRED)
+
+target_include_directories(DitheringProject PUBLIC
+  ${PNG_INCLUDE_DIRS}
+)
+target_link_libraries(DitheringProject PUBLIC
+  ${PNG_LIBRARIES}
+)
diff --git a/Doxyfile b/Doxyfile
new file mode 100644 (file)
index 0000000..b0a3cad
--- /dev/null
+++ b/Doxyfile
@@ -0,0 +1,332 @@
+DOXYFILE_ENCODING      = UTF-8
+PROJECT_NAME           = "EN605.617.81.FA21_StephenSeo_DitheringProject"
+PROJECT_NUMBER         =
+PROJECT_BRIEF          = "Dithers an image using OpenCL"
+PROJECT_LOGO           =
+OUTPUT_DIRECTORY       = "doxygen_out"
+CREATE_SUBDIRS         = NO
+ALLOW_UNICODE_NAMES    = NO
+OUTPUT_LANGUAGE        = English
+BRIEF_MEMBER_DESC      = YES
+REPEAT_BRIEF           = YES
+ABBREVIATE_BRIEF       = "The $name class" \
+                         "The $name widget" \
+                         "The $name file" \
+                         is \
+                         provides \
+                         specifies \
+                         contains \
+                         represents \
+                         a \
+                         an \
+                         the
+ALWAYS_DETAILED_SEC    = NO
+INLINE_INHERITED_MEMB  = NO
+FULL_PATH_NAMES        = YES
+STRIP_FROM_PATH        =
+STRIP_FROM_INC_PATH    =
+SHORT_NAMES            = NO
+JAVADOC_AUTOBRIEF      = NO
+JAVADOC_BANNER         = NO
+QT_AUTOBRIEF           = NO
+MULTILINE_CPP_IS_BRIEF = NO
+PYTHON_DOCSTRING       = YES
+INHERIT_DOCS           = YES
+SEPARATE_MEMBER_PAGES  = NO
+TAB_SIZE               = 2
+ALIASES                =
+OPTIMIZE_OUTPUT_FOR_C  = NO
+OPTIMIZE_OUTPUT_JAVA   = NO
+OPTIMIZE_FOR_FORTRAN   = NO
+OPTIMIZE_OUTPUT_VHDL   = NO
+OPTIMIZE_OUTPUT_SLICE  = NO
+EXTENSION_MAPPING      =
+MARKDOWN_SUPPORT       = YES
+TOC_INCLUDE_HEADINGS   = 5
+AUTOLINK_SUPPORT       = YES
+BUILTIN_STL_SUPPORT    = YES
+CPP_CLI_SUPPORT        = NO
+SIP_SUPPORT            = NO
+IDL_PROPERTY_SUPPORT   = YES
+DISTRIBUTE_GROUP_DOC   = NO
+GROUP_NESTED_COMPOUNDS = NO
+SUBGROUPING            = YES
+INLINE_GROUPED_CLASSES = NO
+INLINE_SIMPLE_STRUCTS  = NO
+TYPEDEF_HIDES_STRUCT   = NO
+LOOKUP_CACHE_SIZE      = 0
+NUM_PROC_THREADS       = 1
+EXTRACT_ALL            = NO
+EXTRACT_PRIVATE        = NO
+EXTRACT_PRIV_VIRTUAL   = NO
+EXTRACT_PACKAGE        = NO
+EXTRACT_STATIC         = NO
+EXTRACT_LOCAL_CLASSES  = YES
+EXTRACT_LOCAL_METHODS  = NO
+EXTRACT_ANON_NSPACES   = NO
+RESOLVE_UNNAMED_PARAMS = YES
+HIDE_UNDOC_MEMBERS     = NO
+HIDE_UNDOC_CLASSES     = NO
+HIDE_FRIEND_COMPOUNDS  = NO
+HIDE_IN_BODY_DOCS      = NO
+INTERNAL_DOCS          = NO
+CASE_SENSE_NAMES       = YES
+HIDE_SCOPE_NAMES       = NO
+HIDE_COMPOUND_REFERENCE= NO
+SHOW_HEADERFILE        = YES
+SHOW_INCLUDE_FILES     = YES
+SHOW_GROUPED_MEMB_INC  = NO
+FORCE_LOCAL_INCLUDES   = NO
+INLINE_INFO            = YES
+SORT_MEMBER_DOCS       = YES
+SORT_BRIEF_DOCS        = NO
+SORT_MEMBERS_CTORS_1ST = NO
+SORT_GROUP_NAMES       = NO
+SORT_BY_SCOPE_NAME     = NO
+STRICT_PROTO_MATCHING  = NO
+GENERATE_TODOLIST      = YES
+GENERATE_TESTLIST      = YES
+GENERATE_BUGLIST       = YES
+GENERATE_DEPRECATEDLIST= YES
+ENABLED_SECTIONS       =
+MAX_INITIALIZER_LINES  = 30
+SHOW_USED_FILES        = YES
+SHOW_FILES             = YES
+SHOW_NAMESPACES        = YES
+FILE_VERSION_FILTER    =
+LAYOUT_FILE            =
+CITE_BIB_FILES         =
+QUIET                  = NO
+WARNINGS               = YES
+WARN_IF_UNDOCUMENTED   = YES
+WARN_IF_DOC_ERROR      = YES
+WARN_IF_INCOMPLETE_DOC = YES
+WARN_NO_PARAMDOC       = NO
+WARN_AS_ERROR          = NO
+WARN_FORMAT            = "$file:$line: $text"
+WARN_LOGFILE           =
+INPUT                  = doxygen src
+INPUT_ENCODING         = UTF-8
+FILE_PATTERNS          = *.c \
+                         *.cc \
+                         *.cxx \
+                         *.cpp \
+                         *.c++ \
+                         *.java \
+                         *.ii \
+                         *.ixx \
+                         *.ipp \
+                         *.i++ \
+                         *.inl \
+                         *.idl \
+                         *.ddl \
+                         *.odl \
+                         *.h \
+                         *.hh \
+                         *.hxx \
+                         *.hpp \
+                         *.h++ \
+                         *.l \
+                         *.cs \
+                         *.d \
+                         *.php \
+                         *.php4 \
+                         *.php5 \
+                         *.phtml \
+                         *.inc \
+                         *.m \
+                         *.markdown \
+                         *.md \
+                         *.mm \
+                         *.dox \
+                         *.py \
+                         *.pyw \
+                         *.f90 \
+                         *.f95 \
+                         *.f03 \
+                         *.f08 \
+                         *.f18 \
+                         *.f \
+                         *.for \
+                         *.vhd \
+                         *.vhdl \
+                         *.ucf \
+                         *.qsf \
+                         *.ice
+RECURSIVE              = NO
+EXCLUDE                =
+EXCLUDE_SYMLINKS       = NO
+EXCLUDE_PATTERNS       =
+EXCLUDE_SYMBOLS        =
+EXAMPLE_PATH           =
+EXAMPLE_PATTERNS       = *
+EXAMPLE_RECURSIVE      = NO
+IMAGE_PATH             =
+INPUT_FILTER           =
+FILTER_PATTERNS        =
+FILTER_SOURCE_FILES    = NO
+FILTER_SOURCE_PATTERNS =
+USE_MDFILE_AS_MAINPAGE = doxygen/mainpage.md
+SOURCE_BROWSER         = NO
+INLINE_SOURCES         = NO
+STRIP_CODE_COMMENTS    = YES
+REFERENCED_BY_RELATION = NO
+REFERENCES_RELATION    = NO
+REFERENCES_LINK_SOURCE = YES
+SOURCE_TOOLTIPS        = YES
+USE_HTAGS              = NO
+VERBATIM_HEADERS       = YES
+ALPHABETICAL_INDEX     = YES
+IGNORE_PREFIX          =
+GENERATE_HTML          = YES
+HTML_OUTPUT            = html
+HTML_FILE_EXTENSION    = .html
+HTML_HEADER            =
+HTML_FOOTER            =
+HTML_STYLESHEET        =
+HTML_EXTRA_STYLESHEET  =
+HTML_EXTRA_FILES       =
+HTML_COLORSTYLE_HUE    = 220
+HTML_COLORSTYLE_SAT    = 100
+HTML_COLORSTYLE_GAMMA  = 80
+HTML_TIMESTAMP         = NO
+HTML_DYNAMIC_MENUS     = YES
+HTML_DYNAMIC_SECTIONS  = NO
+HTML_INDEX_NUM_ENTRIES = 100
+GENERATE_DOCSET        = NO
+DOCSET_FEEDNAME        = "Doxygen generated docs"
+DOCSET_BUNDLE_ID       = org.doxygen.Project
+DOCSET_PUBLISHER_ID    = org.doxygen.Publisher
+DOCSET_PUBLISHER_NAME  = Publisher
+GENERATE_HTMLHELP      = NO
+CHM_FILE               =
+HHC_LOCATION           =
+GENERATE_CHI           = NO
+CHM_INDEX_ENCODING     =
+BINARY_TOC             = NO
+TOC_EXPAND             = NO
+GENERATE_QHP           = NO
+QCH_FILE               =
+QHP_NAMESPACE          = org.doxygen.Project
+QHP_VIRTUAL_FOLDER     = doc
+QHP_CUST_FILTER_NAME   =
+QHP_CUST_FILTER_ATTRS  =
+QHP_SECT_FILTER_ATTRS  =
+QHG_LOCATION           =
+GENERATE_ECLIPSEHELP   = NO
+ECLIPSE_DOC_ID         = org.doxygen.Project
+DISABLE_INDEX          = NO
+GENERATE_TREEVIEW      = NO
+FULL_SIDEBAR           = NO
+ENUM_VALUES_PER_LINE   = 4
+TREEVIEW_WIDTH         = 250
+EXT_LINKS_IN_WINDOW    = NO
+HTML_FORMULA_FORMAT    = png
+FORMULA_FONTSIZE       = 10
+FORMULA_TRANSPARENT    = YES
+FORMULA_MACROFILE      =
+USE_MATHJAX            = NO
+MATHJAX_VERSION        = MathJax_2
+MATHJAX_FORMAT         = HTML-CSS
+MATHJAX_RELPATH        =
+MATHJAX_EXTENSIONS     =
+MATHJAX_CODEFILE       =
+SEARCHENGINE           = YES
+SERVER_BASED_SEARCH    = NO
+EXTERNAL_SEARCH        = NO
+SEARCHENGINE_URL       =
+SEARCHDATA_FILE        = searchdata.xml
+EXTERNAL_SEARCH_ID     =
+EXTRA_SEARCH_MAPPINGS  =
+GENERATE_LATEX         = YES
+LATEX_OUTPUT           = latex
+LATEX_CMD_NAME         =
+MAKEINDEX_CMD_NAME     = makeindex
+LATEX_MAKEINDEX_CMD    = makeindex
+COMPACT_LATEX          = NO
+PAPER_TYPE             = a4
+EXTRA_PACKAGES         =
+LATEX_HEADER           =
+LATEX_FOOTER           =
+LATEX_EXTRA_STYLESHEET =
+LATEX_EXTRA_FILES      =
+PDF_HYPERLINKS         = YES
+USE_PDFLATEX           = YES
+LATEX_BATCHMODE        = NO
+LATEX_HIDE_INDICES     = NO
+LATEX_BIB_STYLE        = plain
+LATEX_TIMESTAMP        = NO
+LATEX_EMOJI_DIRECTORY  =
+GENERATE_RTF           = NO
+RTF_OUTPUT             = rtf
+COMPACT_RTF            = NO
+RTF_HYPERLINKS         = NO
+RTF_STYLESHEET_FILE    =
+RTF_EXTENSIONS_FILE    =
+GENERATE_MAN           = NO
+MAN_OUTPUT             = man
+MAN_EXTENSION          = .3
+MAN_SUBDIR             =
+MAN_LINKS              = NO
+GENERATE_XML           = NO
+XML_OUTPUT             = xml
+XML_PROGRAMLISTING     = YES
+XML_NS_MEMB_FILE_SCOPE = NO
+GENERATE_DOCBOOK       = NO
+DOCBOOK_OUTPUT         = docbook
+GENERATE_AUTOGEN_DEF   = NO
+GENERATE_PERLMOD       = NO
+PERLMOD_LATEX          = NO
+PERLMOD_PRETTY         = YES
+PERLMOD_MAKEVAR_PREFIX =
+ENABLE_PREPROCESSING   = YES
+MACRO_EXPANSION        = NO
+EXPAND_ONLY_PREDEF     = NO
+SEARCH_INCLUDES        = YES
+INCLUDE_PATH           =
+INCLUDE_FILE_PATTERNS  =
+PREDEFINED             =
+EXPAND_AS_DEFINED      =
+SKIP_FUNCTION_MACROS   = YES
+TAGFILES               =
+GENERATE_TAGFILE       =
+ALLEXTERNALS           = NO
+EXTERNAL_GROUPS        = YES
+EXTERNAL_PAGES         = YES
+CLASS_DIAGRAMS         = YES
+DIA_PATH               =
+HIDE_UNDOC_RELATIONS   = YES
+HAVE_DOT               = NO
+DOT_NUM_THREADS        = 0
+DOT_FONTNAME           = Helvetica
+DOT_FONTSIZE           = 10
+DOT_FONTPATH           =
+CLASS_GRAPH            = YES
+COLLABORATION_GRAPH    = YES
+GROUP_GRAPHS           = YES
+UML_LOOK               = NO
+UML_LIMIT_NUM_FIELDS   = 10
+DOT_UML_DETAILS        = NO
+DOT_WRAP_THRESHOLD     = 17
+TEMPLATE_RELATIONS     = NO
+INCLUDE_GRAPH          = YES
+INCLUDED_BY_GRAPH      = YES
+CALL_GRAPH             = NO
+CALLER_GRAPH           = NO
+GRAPHICAL_HIERARCHY    = YES
+DIRECTORY_GRAPH        = YES
+DOT_IMAGE_FORMAT       = png
+INTERACTIVE_SVG        = NO
+DOT_PATH               =
+DOTFILE_DIRS           =
+MSCFILE_DIRS           =
+DIAFILE_DIRS           =
+PLANTUML_JAR_PATH      =
+PLANTUML_CFG_FILE      =
+PLANTUML_INCLUDE_PATH  =
+DOT_GRAPH_MAX_NODES    = 50
+MAX_DOT_GRAPH_DEPTH    = 0
+DOT_TRANSPARENT        = NO
+DOT_MULTI_TARGETS      = NO
+GENERATE_LEGEND        = YES
+DOT_CLEANUP            = YES
diff --git a/doxygen/mainpage.md b/doxygen/mainpage.md
new file mode 100644 (file)
index 0000000..87759b3
--- /dev/null
@@ -0,0 +1,3 @@
+# Dithering Project
+
+<a href="annotated.html">Classes</a>
diff --git a/src/image.cc b/src/image.cc
new file mode 100644 (file)
index 0000000..8f8d9b9
--- /dev/null
@@ -0,0 +1,131 @@
+#include "image.h"
+
+#include <array>
+#include <cstdio>
+#include <iostream>
+
+#include <png.h>
+
+Image::Image() : data_(), width_(0), height_(0), is_grayscale_(true) {}
+
+Image::Image(const char *filename) : Image(std::string(filename)) {}
+
+Image::Image(const std::string &filename)
+    : data_(), width_(0), height_(0), is_grayscale_(true) {
+  if (filename.compare(filename.size() - 4, filename.size(), ".png") == 0) {
+    // filename expected to be .png
+    DecodePNG(filename);
+  } else if (filename.compare(filename.size() - 4, filename.size(), ".pgm") ==
+             0) {
+    // filename expected to be .pgm
+    DecodePGM(filename);
+  } else if (filename.compare(filename.size() - 4, filename.size(), ".ppm") ==
+             0) {
+    // filename expected to be .ppm
+    DecodePPM(filename);
+  } else {
+    // unknown filename extension
+    return;
+  }
+}
+
+bool Image::IsValid() const {
+  return !data_.empty() && width_ > 0 && height_ > 0;
+}
+
+uint8_t *Image::GetData() { return data_.data(); }
+
+const uint8_t *Image::GetData() const { return data_.data(); }
+
+unsigned int Image::GetSize() const { return data_.size(); }
+
+unsigned int Image::GetWidth() const { return width_; }
+
+unsigned int Image::GetHeight() const { return height_; }
+
+bool Image::IsGrayscale() const { return is_grayscale_; }
+
+void Image::DecodePNG(const std::string &filename) {
+  FILE *file = std::fopen(filename.c_str(), "rb");
+
+  // Check header of file to check if it is actually a png file.
+  {
+    std::array<unsigned char, 8> buf;
+    if (std::fread(buf.data(), 1, 8, file) != 8) {
+      std::cout << "ERROR: File \"" << filename << "\" is smaller than 8 bytes"
+                << std::endl;
+      std::fclose(file);
+      return;
+    } else if (!png_sig_cmp(reinterpret_cast<png_const_bytep>(buf.data()), 0,
+                            8)) {
+      // not png file, do nothing
+      std::fclose(file);
+      return;
+    }
+  }
+
+  // seek to head of file
+  std::rewind(file);
+
+  // init required structs for png decoding
+  png_structp png_ptr =
+      png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
+  if (!png_ptr) {
+    std::cout << "ERROR: Failed to initialize libpng (png_ptr) for decoding "
+                 "PNG file \""
+              << filename << '"' << std::endl;
+    std::fclose(file);
+    return;
+  }
+
+  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_read_struct(&png_ptr, nullptr, nullptr);
+    std::fclose(file);
+    return;
+  }
+
+  png_infop png_end_info_ptr = png_create_info_struct(png_ptr);
+  if (!png_end_info_ptr) {
+    std::cout << "ERROR: Failed to initialize libpng (end png_infop) for "
+                 "decoding PNG file \""
+              << filename << '"' << std::endl;
+    png_destroy_read_struct(&png_ptr, &png_info_ptr, nullptr);
+    std::fclose(file);
+    return;
+  }
+
+  // required to handle libpng errors
+  if (setjmp(png_jmpbuf(png_ptr))) {
+    png_destroy_read_struct(&png_ptr, &png_info_ptr, &png_end_info_ptr);
+    std::fclose(file);
+    return;
+  }
+
+  // pass the FILE pointer to libpng
+  png_init_io(png_ptr, file);
+
+  // TODO BEGIN
+  //// have libpng process the png data
+  // png_read_png(png_ptr, png_info_ptr, PNG_TRANSFORM_IDENTITY, nullptr);
+
+  //// get rows of pixels from libpng
+  // png_bytep row_pointer = nullptr;
+  // png_read_row(png_ptr, row_pointer, nullptr);
+
+  // TODO END
+
+  // cleanup
+  png_destroy_read_struct(&png_ptr, &png_info_ptr, &png_end_info_ptr);
+}
+
+void Image::DecodePGM(const std::string &filename) {
+  // TODO
+}
+
+void Image::DecodePPM(const std::string &filename) {
+  // TODO
+}
diff --git a/src/image.h b/src/image.h
new file mode 100644 (file)
index 0000000..db5730a
--- /dev/null
@@ -0,0 +1,72 @@
+#ifndef IGPUP_DITHERING_PROJECT_IMAGE_H_
+#define IGPUP_DITHERING_PROJECT_IMAGE_H_
+
+#include <cstdint>
+#include <string>
+#include <vector>
+
+class Image {
+ public:
+  Image();
+
+  /*!
+   * \brief Decodes the given file's data and stores the pixels internally.
+   *
+   * Use IsValid() to check if the file was successfully decoded.
+   *
+   * Image supports decoding .png, .pgm, and .ppm . Decoding only checks the
+   * filename suffix as a guide on which file-type to expect.
+   */
+  Image(const char *filename);
+
+  /// Same constructor as Image(const char *filename)
+  Image(const std::string &filename);
+
+  // allow copy
+  Image(const Image &other) = default;
+  Image &operator=(const Image &other) = default;
+
+  // allow move
+  Image(Image &&other) = default;
+  Image &operator=(Image &&other) = default;
+
+  /*!
+   * \brief Is true if the Image instance is valid.
+   *
+   * This will return false on an Image instance that failed to decode an input
+   * image when constructed.
+   */
+  bool IsValid() const;
+
+  /// Returns a raw pointer to the image's data.
+  uint8_t *GetData();
+  /// Returns a const raw pointer to the image's data.
+  const uint8_t *GetData() const;
+
+  /*!
+   * \brief Returns the number of bytes in the image.
+   *
+   * For grayscale images, each pixel is one byte.
+   * For colored images, each pixel is 4 bytes: R, G, B, and Alpha.
+   */
+  unsigned int GetSize() const;
+  /// Returns the width of the image.
+  unsigned int GetWidth() const;
+  /// Returns the height of the image.
+  unsigned int GetHeight() const;
+
+  /// Returns true if the image is grayscale. If false, then the image is RGBA.
+  bool IsGrayscale() const;
+
+ private:
+  std::vector<uint8_t> data_;
+  unsigned int width_;
+  unsigned int height_;
+  bool is_grayscale_;
+
+  void DecodePNG(const std::string &filename);
+  void DecodePGM(const std::string &filename);
+  void DecodePPM(const std::string &filename);
+};
+
+#endif