gta: add from-png, to-png for import/export of PNG images via libpng
authorMartin Lambers <marlam@marlam.de>
Tue, 28 Oct 2014 21:10:03 +0000 (22:10 +0100)
committerMartin Lambers <marlam@marlam.de>
Tue, 28 Oct 2014 21:10:03 +0000 (22:10 +0100)
gtatool/configure.ac
gtatool/src/Makefile.am
gtatool/src/bash-completion/gta
gtatool/src/cmds.cpp
gtatool/src/conv-png/from-png.cpp [new file with mode: 0644]
gtatool/src/conv-png/to-png.cpp [new file with mode: 0644]
gtatool/src/conv/filters.cpp
gtatool/src/gui/gui.cpp
gtatool/src/gui/gui.hpp
gtatool/tests/Makefile.am
gtatool/tests/conv-png.sh [new file with mode: 0755]

index e2b054d..2f3c971 100644 (file)
@@ -504,6 +504,20 @@ fi
 AC_DEFINE_UNQUOTED([WITH_PMD], [`if test "$pmd" = "yes"; then echo "1"; else echo "0"; fi`], [Use pmd?])
 AM_CONDITIONAL([WITH_PMD], [test "$pmd" = "yes"])
 
+dnl conv-png: libpng
+AC_ARG_WITH([png],
+    [AS_HELP_STRING([--with-png], [Enable PNG import/export. Enabled by default if libpng is available.])],
+    [if test "$withval" = "yes"; then png="yes"; else png="no "; fi], [png="yes"])
+if test "$png" = "yes"; then
+    PKG_CHECK_MODULES([libpng], [libpng >= 1.2.0], [],
+        [png="no "
+        AC_MSG_WARN([PNG library not found:])
+        AC_MSG_WARN([$libpng_PKG_ERRORS])
+        AC_MSG_WARN([Disabled the from-png and to-png commands.])])
+fi
+AC_DEFINE_UNQUOTED([WITH_PNG], [`if test "$png" = "yes"; then echo "1"; else echo "0"; fi`], [Use png?])
+AM_CONDITIONAL([WITH_PNG], [test "$png" = "yes"])
+
 dnl conv-pvm
 AC_ARG_WITH([pvm],
     [AS_HELP_STRING([--with-pvm], [Enable PVM import/export. Enabled by default.])],
@@ -691,6 +705,7 @@ echo "from-pcd, to-pcd:        " "$pcd" "(Requires the Point Cloud Library IO mo
 echo "from-pfs, to-pfs:        " "$pfs" "(Requires pfstools)"
 echo "from-ply, to-ply:        " "$ply" ""
 echo "from-pmd:                " "$pmd" "(Requires the proprietary PMD SDK)"
+echo "from-png, to-png:        " "$png" "(Requires libpng)"
 echo "from-pvm, to-pvm:        " "$pvm" ""
 echo "from-rat, to-rat:        " "$rat" ""
 echo "from-raw, to-raw:        " "$raw" ""
index d169863..653c658 100644 (file)
@@ -22,6 +22,7 @@ AM_CPPFLAGS = -I$(top_srcdir)/src -DPKGLIBDIR=\"$(pkglibdir)\" \
        $(libnetcdf_CFLAGS) \
        $(libpcl_io_CFLAGS) \
        $(libpfs_CFLAGS) \
+       $(libpng_CFLAGS) \
        $(libsndfile_CFLAGS) \
        $(libteem_CFLAGS) \
        $(libqtopengl_CFLAGS) \
@@ -404,6 +405,17 @@ libbuiltin_la_LIBADD += $(LTLIBPMDACCESS2)
 endif
 endif
 
+if WITH_PNG
+if DYNAMIC_MODULES
+pkglib_LTLIBRARIES += conv-png.la
+conv_png_la_SOURCES = conv-png/from-png.cpp conv-png/to-png.cpp
+conv_png_la_LIBADD = $(libpng_LIBS)
+else
+libbuiltin_la_SOURCES += conv-png/from-png.cpp conv-png/to-png.cpp
+libbuiltin_la_LIBADD += $(libpng_LIBS)
+endif
+endif
+
 if WITH_PVM
 EXTRA_DIST += conv-pvm/README
 if DYNAMIC_MODULES
index a205637..6d75ec1 100644 (file)
@@ -1,4 +1,4 @@
-# Copyright (C) 2013
+# Copyright (C) 2013, 2014
 # Martin Lambers <marlam@marlam.de>
 #
 # Copying and distribution of this file, with or without modification, are
@@ -48,6 +48,7 @@ _gta()
        from-pfs
        from-ply
        from-pmd
+       from-png
        from-pvm
        from-rat
        from-raw
@@ -78,6 +79,7 @@ _gta()
        to-pcd
        to-pfs
        to-ply
+       to-png
        to-pvm
        to-rat
        to-raw
@@ -360,6 +362,13 @@ _gta()
            COMPREPLY=( $(compgen -f -o plusdirs -- ${cur}) )
        fi
        ;;
+    from-png)
+       if [[ ${cur} == -* ]]; then
+           COMPREPLY=( $(compgen -W "--help" -- ${cur}) )
+       else
+           COMPREPLY=( $(compgen -f -o plusdirs -- ${cur}) )
+       fi
+       ;;
     from-pvm)
        if [[ ${cur} == -* ]]; then
            COMPREPLY=( $(compgen -W "--help" -- ${cur}) )
@@ -566,6 +575,13 @@ _gta()
            COMPREPLY=( $(compgen -f -o plusdirs -- ${cur}) )
        fi
        ;;
+    to-png)
+       if [[ ${cur} == -* ]]; then
+           COMPREPLY=( $(compgen -W "--help" -- ${cur}) )
+       else
+           COMPREPLY=( $(compgen -f -o plusdirs -- ${cur}) )
+       fi
+       ;;
     to-pvm)
        if [[ ${cur} == -* ]]; then
            COMPREPLY=( $(compgen -W "--help" -- ${cur}) )
index 6cefa71..5868e88 100644 (file)
@@ -115,6 +115,7 @@ CMD_DECL(from_pcd)
 CMD_DECL(from_pfs)
 CMD_DECL(from_ply)
 CMD_DECL(from_pmd)
+CMD_DECL(from_png)
 CMD_DECL(from_pvm)
 CMD_DECL(from_rat)
 CMD_DECL(from_raw)
@@ -145,6 +146,7 @@ CMD_DECL(to_netpbm)
 CMD_DECL(to_pcd)
 CMD_DECL(to_pfs)
 CMD_DECL(to_ply)
+CMD_DECL(to_png)
 CMD_DECL(to_pvm)
 CMD_DECL(to_rat)
 CMD_DECL(to_raw)
@@ -230,6 +232,8 @@ static cmd_t cmds[] =
             "Import arrays from PLY point data"),
     CMD("from-pmd",          cmd_conversion, from_pmd,          WITH_PMD,      "conv-pmd",
             "Import arrays from PMD ToF sensor data files"),
+    CMD("from-png",          cmd_conversion, from_png,          WITH_PNG,      "conv-png",
+            "Import arrays from PNG files"),
     CMD("from-pvm",          cmd_conversion, from_pvm,          WITH_PVM,      "conv-pvm",
             "Import arrays from PVM volume data"),
     CMD("from-rat",          cmd_conversion, from_rat,          WITH_RAT,      "conv-rat",
@@ -290,6 +294,8 @@ static cmd_t cmds[] =
             "Export arrays to PFS images"),
     CMD("to-ply",            cmd_conversion, to_ply,            WITH_PLY,      "conv-ply",
             "Export arrays to PLY point data"),
+    CMD("to-png",            cmd_conversion, to_png,            WITH_PNG,      "conv-png",
+            "Export arrays to PNG files"),
     CMD("to-pvm",            cmd_conversion, to_pvm,            WITH_PVM,      "conv-pvm",
             "Export arrays to PVM volume data"),
     CMD("to-rat",            cmd_conversion, to_rat,            WITH_RAT,      "conv-rat",
diff --git a/gtatool/src/conv-png/from-png.cpp b/gtatool/src/conv-png/from-png.cpp
new file mode 100644 (file)
index 0000000..a9cd4e2
--- /dev/null
@@ -0,0 +1,164 @@
+/*
+ * This file is part of gtatool, a tool to manipulate Generic Tagged Arrays
+ * (GTAs).
+ *
+ * Copyright (C) 2014
+ * Martin Lambers <marlam@marlam.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include <string>
+
+#include <png.h>
+
+#include <gta/gta.hpp>
+
+#include "base/msg.h"
+#include "base/blb.h"
+#include "base/fio.h"
+#include "base/opt.h"
+#include "base/str.h"
+#include "base/end.h"
+
+#include "lib.h"
+
+
+extern "C" void gtatool_from_png_help(void)
+{
+    msg::req_txt("from-png <input-file> [<output-file>]\n"
+            "\n"
+            "Converts PNG images to GTAs.");
+}
+
+static std::string namei;
+
+static void my_png_error(png_structp /* png_ptr */, png_const_charp error_msg)
+{
+    throw exc(namei + ": " + error_msg);
+}
+
+static void my_png_warning(png_structp /* png_ptr */, png_const_charp warning_msg)
+{
+    msg::wrn(namei + ": " + warning_msg);
+}
+
+extern "C" int gtatool_from_png(int argc, char *argv[])
+{
+    std::vector<opt::option *> options;
+    opt::info help("help", '\0', opt::optional);
+    options.push_back(&help);
+    std::vector<std::string> arguments;
+    if (!opt::parse(argc, argv, options, 1, 2, arguments))
+    {
+        return 1;
+    }
+    if (help.value())
+    {
+        gtatool_from_png_help();
+        return 0;
+    }
+
+    try
+    {
+        array_loop_t array_loop;
+        array_loop.start(std::vector<std::string>(1, arguments[0]), arguments.size() == 2 ? arguments[1] : "");
+
+        namei = arguments[0];
+
+        FILE* pngfile = fio::open(namei, "r");
+        png_byte header[8];
+        fio::read(header, 8, 1, pngfile, namei);
+        if (png_sig_cmp(header, 0, 8))
+            throw exc(namei + ": not a PNG file");
+        png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+        if (!png_ptr)
+            throw exc(namei + ": png_create_read_struct failed");
+        png_set_error_fn(png_ptr, NULL, my_png_error, my_png_warning);
+        png_set_user_limits(png_ptr, 0x7fffffffL, 0x7fffffffL);
+        png_infop info_ptr = png_create_info_struct(png_ptr);
+        if (!info_ptr)
+            throw exc(namei + ": png_create_info_struct failed");
+        png_init_io(png_ptr, pngfile);
+        png_set_sig_bytes(png_ptr, 8);
+        png_read_png(png_ptr, info_ptr,
+                endianness::endianness == endianness::big
+                ? PNG_TRANSFORM_IDENTITY : PNG_TRANSFORM_SWAP_ENDIAN,
+                NULL);
+        int width = png_get_image_width(png_ptr, info_ptr);
+        int height = png_get_image_height(png_ptr, info_ptr);
+        int channels = png_get_channels(png_ptr, info_ptr);
+        png_byte bit_depth = png_get_bit_depth(png_ptr, info_ptr);
+        png_bytep *row_pointers = png_get_rows(png_ptr, info_ptr);
+        png_textp text_ptr;
+        png_uint_32 num_text = png_get_text(png_ptr, info_ptr, &text_ptr, NULL);
+
+        gta::header hdr;
+        if (width < 1 || height < 1)
+            throw exc(namei + ": invalid image dimensions");
+        for (unsigned int i = 0; i < num_text; i++) {
+            try {
+                std::string key_utf8 = "PNG/";
+                key_utf8 += str::convert(text_ptr[i].key, "ISO-8859-1", "UTF-8");
+                std::string value_utf8 = str::convert(text_ptr[i].text, "ISO-8859-1", "UTF-8");
+                hdr.global_taglist().set(key_utf8.c_str(), value_utf8.c_str());
+            }
+            catch (...) {
+                // ignore tags that we cannot convert; they were invalid anyway
+            }
+        }
+        hdr.set_dimensions(width, height);
+        gta::type gta_type = (bit_depth <= 8 ? gta::uint8 : gta::uint16);
+        if (channels == 1) {
+            hdr.set_components(gta_type);
+            hdr.component_taglist(0).set("INTERPRETATION", "GRAY");
+        } else if (channels == 2) {
+            hdr.set_components(gta_type, gta_type);
+            hdr.component_taglist(0).set("INTERPRETATION", "GRAY");
+            hdr.component_taglist(1).set("INTERPRETATION", "ALPHA");
+        } else if (channels == 3) {
+            hdr.set_components(gta_type, gta_type, gta_type);
+            hdr.component_taglist(0).set("INTERPRETATION", "SRGB/RED");
+            hdr.component_taglist(1).set("INTERPRETATION", "SRGB/GREEN");
+            hdr.component_taglist(2).set("INTERPRETATION", "SRGB/BLUE");
+        } else if (channels == 4) {
+            hdr.set_components(gta_type, gta_type, gta_type, gta_type);
+            hdr.component_taglist(0).set("INTERPRETATION", "SRGB/RED");
+            hdr.component_taglist(1).set("INTERPRETATION", "SRGB/GREEN");
+            hdr.component_taglist(2).set("INTERPRETATION", "SRGB/BLUE");
+            hdr.component_taglist(3).set("INTERPRETATION", "ALPHA");
+        } else {
+            throw exc(namei + ": invalid number of channels");
+        }
+
+        std::string nameo;
+        array_loop.write(hdr, nameo);
+        element_loop_t element_loop;
+        array_loop.start_element_loop(element_loop, gta::header(), hdr);
+        for (int i = 0; i < height; i++)
+            element_loop.write(row_pointers[i], width);
+        png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
+        fio::close(pngfile, namei);
+        array_loop.finish();
+    }
+    catch (std::exception &e)
+    {
+        msg::err_txt("%s", e.what());
+        return 1;
+    }
+
+    return 0;
+}
diff --git a/gtatool/src/conv-png/to-png.cpp b/gtatool/src/conv-png/to-png.cpp
new file mode 100644 (file)
index 0000000..643dd03
--- /dev/null
@@ -0,0 +1,195 @@
+/*
+ * This file is part of gtatool, a tool to manipulate Generic Tagged Arrays
+ * (GTAs).
+ *
+ * Copyright (C) 2014
+ * Martin Lambers <marlam@marlam.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include <string>
+#include <cstring>
+#include <cstdlib>
+
+#include <zlib.h>
+#include <png.h>
+
+#include <gta/gta.hpp>
+
+#include "base/msg.h"
+#include "base/blb.h"
+#include "base/fio.h"
+#include "base/opt.h"
+#include "base/str.h"
+#include "base/end.h"
+
+#include "lib.h"
+
+
+extern "C" void gtatool_to_png_help(void)
+{
+    msg::req_txt("to-png [<input-file>] <output-file>\n"
+            "\n"
+            "Converts GTAs to PNG image file format via libpng.\n"
+            "This will produce PNGs with one of the formats GRAY, GRAY+ALPHA, RGB, or RGB+ALPHA, "
+            "depending on the number of element components in the input array.\n"
+            "It is assumed that the array components are in the correct order and "
+            "contain sRGB data, and are of type uint8 or uint16. If this is not the "
+            "case, use component-convert, component-reorder, and/or component-compute "
+            "to prepare your array.");
+}
+
+static std::string nameo;
+
+static void my_png_error(png_structp /* png_ptr */, png_const_charp error_msg)
+{
+    throw exc(nameo + ": " + error_msg);
+}
+
+static void my_png_warning(png_structp /* png_ptr */, png_const_charp warning_msg)
+{
+    msg::wrn(nameo + ": " + warning_msg);
+}
+
+extern "C" int gtatool_to_png(int argc, char *argv[])
+{
+    std::vector<opt::option *> options;
+    opt::info help("help", '\0', opt::optional);
+    options.push_back(&help);
+    std::vector<std::string> arguments;
+    if (!opt::parse(argc, argv, options, 1, 2, arguments))
+    {
+        return 1;
+    }
+    if (help.value())
+    {
+        gtatool_to_png_help();
+        return 0;
+    }
+
+    try
+    {
+        nameo = arguments.size() == 1 ? arguments[0] : arguments[1];
+        array_loop_t array_loop;
+        gta::header hdr;
+        std::string name;
+
+        array_loop.start(arguments.size() == 1 ? std::vector<std::string>() : std::vector<std::string>(1, arguments[0]), nameo);
+        if (array_loop.read(hdr, name))
+        {
+            if (hdr.dimensions() != 2)
+                throw exc(name + ": only two-dimensional arrays can be converted to PNG.");
+            if (hdr.dimension_size(0) > 0x7fffffffL || hdr.dimension_size(1) > 0x7fffffffL)
+                throw exc(name + ": array too large to be converted to PNG.");
+            if (hdr.components() < 1 && hdr.components() > 4)
+                throw exc(name + ": only arrays with 1-4 element components can be converted to PNG.");
+            for (uintmax_t i = 0; i < hdr.components(); i++)
+                if (hdr.component_type(i) != gta::uint8 && hdr.component_type(i) != gta::uint16)
+                    throw exc(name + ": only arrays with element component type uint8 or uint16 can be converted to PNG.");
+            for (uintmax_t i = 1; i < hdr.components(); i++)
+                if (hdr.component_type(i) != hdr.component_type(0))
+                    throw exc(name + ": only arrays with uniform element component types can be converted to PNG.");
+
+            blob data(checked_cast<size_t>(hdr.data_size()));
+            std::vector<png_bytep> row_pointers(hdr.dimension_size(1));
+            size_t row_size = hdr.dimension_size(0) * hdr.element_size();
+            for (uintmax_t i = 0; i < hdr.dimension_size(1); i++)
+                row_pointers[i] = data.ptr<png_byte>(i * row_size);
+            std::vector<struct png_text_struct> text;
+            for (uintmax_t i = 0; i < hdr.global_taglist().tags(); i++) {
+                std::string key = hdr.global_taglist().name(i);
+                bool add = true;
+                if (key.substr(0, 4) == std::string("PNG/"))
+                    key = key.substr(4);
+                std::string key_latin1, value_latin1;
+                if (key.length() > 79) {
+                    add = false;
+                } else {
+                    try {
+                        key_latin1 = str::convert(key, "UTF-8", "ISO-8859-1");
+                        value_latin1 = (hdr.global_taglist().value(i)
+                                ? str::convert(hdr.global_taglist().value(i), "UTF-8", "ISO-8859-1")
+                                : std::string(""));
+                    }
+                    catch (...) {
+                        add = false;
+                    }
+                }
+                if (add) {
+                    struct png_text_struct t;
+                    std::memset(&t, 0, sizeof(t));
+                    t.compression = -1;
+                    t.key = strdup(key_latin1.c_str());
+                    t.text = strdup(value_latin1.c_str());
+                    t.text_length = std::strlen(t.text);
+                    text.push_back(t);
+                    if (!t.key || !t.text)
+                        throw exc(nameo + ": memory allocation failed");
+                } else {
+                    // silently ignore tags that we cannot set for PNG
+                }
+            }
+
+            FILE* pngfile = fio::open(nameo, "w");
+            png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+            if (!png_ptr)
+                throw exc(nameo + ": png_create_write_struct failed");
+            png_set_error_fn(png_ptr, NULL, my_png_error, my_png_warning);
+            png_set_user_limits(png_ptr, 0x7fffffffL, 0x7fffffffL);
+            png_infop info_ptr = png_create_info_struct(png_ptr);
+            if (!info_ptr)
+                throw exc(nameo + ": png_create_info_struct failed");
+            png_init_io(png_ptr, pngfile);
+            png_set_IHDR(png_ptr, info_ptr,
+                    hdr.dimension_size(0), hdr.dimension_size(1),
+                    hdr.component_type(0) == gta::uint8 ? 8 : 16,
+                    hdr.components() == 1 ? PNG_COLOR_TYPE_GRAY
+                    : hdr.components() == 2 ? PNG_COLOR_TYPE_GRAY_ALPHA
+                    : hdr.components() == 3 ? PNG_COLOR_TYPE_RGB
+                    : PNG_COLOR_TYPE_RGB_ALPHA,
+                    PNG_INTERLACE_NONE,
+                    PNG_COMPRESSION_TYPE_DEFAULT,
+                    PNG_FILTER_TYPE_DEFAULT);
+            png_set_compression_level(png_ptr, Z_BEST_COMPRESSION);
+            png_set_sRGB(png_ptr, info_ptr, PNG_INFO_sRGB);
+            if (text.size() > 0)
+                png_set_text(png_ptr, info_ptr, &(text[0]), text.size());
+            png_set_rows(png_ptr, info_ptr, &(row_pointers[0]));
+
+            array_loop.read_data(hdr, data.ptr());
+            png_write_png(png_ptr, info_ptr,
+                    endianness::endianness == endianness::big
+                    ? PNG_TRANSFORM_IDENTITY : PNG_TRANSFORM_SWAP_ENDIAN,
+                    NULL);
+            png_destroy_write_struct(&png_ptr, &info_ptr);
+            for (size_t i = 0; i < text.size(); i++) {
+                std::free(text[i].key);
+                std::free(text[i].text);
+            }
+
+            fio::close(pngfile, nameo);
+        }
+        array_loop.finish();
+    }
+    catch (std::exception &e)
+    {
+        msg::err_txt("%s", e.what());
+        return 1;
+    }
+
+    return 0;
+}
index cba21b2..f201673 100644 (file)
@@ -81,6 +81,7 @@ std::vector<std::string> find_filters(const std::string& extension, bool import)
     } else if (extension == "ply") {
         filters.push_back("ply");
     } else if (extension == "png") {
+        filters.push_back("png");
         filters.push_back("magick");
     } else if (extension == "pvm") {
         filters.push_back("pvm");
index 500fc94..f22a814 100644 (file)
@@ -707,6 +707,10 @@ GUI::GUI()
     connect(file_import_ply_action, SIGNAL(triggered()), this, SLOT(file_import_ply()));
     file_import_ply_action->setEnabled(cmd_is_available(cmd_find("from-ply")));
     file_import_menu->addAction(file_import_ply_action);
+    QAction *file_import_png_action = new QAction(tr("PNG image data..."), this);
+    connect(file_import_png_action, SIGNAL(triggered()), this, SLOT(file_import_png()));
+    file_import_png_action->setEnabled(cmd_is_available(cmd_find("from-png")));
+    file_import_menu->addAction(file_import_png_action);
     QAction *file_import_pvm_action = new QAction(tr("PVM volume data..."), this);
     connect(file_import_pvm_action, SIGNAL(triggered()), this, SLOT(file_import_pvm()));
     file_import_pvm_action->setEnabled(cmd_is_available(cmd_find("from-pvm")));
@@ -776,6 +780,10 @@ GUI::GUI()
     connect(file_export_ply_action, SIGNAL(triggered()), this, SLOT(file_export_ply()));
     file_export_ply_action->setEnabled(cmd_is_available(cmd_find("to-ply")));
     file_export_menu->addAction(file_export_ply_action);
+    QAction *file_export_png_action = new QAction(tr("PVM volume data..."), this);
+    connect(file_export_png_action, SIGNAL(triggered()), this, SLOT(file_export_png()));
+    file_export_png_action->setEnabled(cmd_is_available(cmd_find("to-png")));
+    file_export_menu->addAction(file_export_png_action);
     QAction *file_export_pvm_action = new QAction(tr("PVM volume data..."), this);
     connect(file_export_pvm_action, SIGNAL(triggered()), this, SLOT(file_export_pvm()));
     file_export_pvm_action->setEnabled(cmd_is_available(cmd_find("to-pvm")));
@@ -1648,6 +1656,11 @@ void GUI::file_import_ply()
     import_from("from-ply", std::vector<std::string>(), QStringList("PLY files (*.ply)"));
 }
 
+void GUI::file_import_png()
+{
+    import_from("from-png", std::vector<std::string>(), QStringList("PNG files (*.png)"));
+}
+
 void GUI::file_import_pvm()
 {
     import_from("from-pvm", std::vector<std::string>(), QStringList("PVM files (*.pvm)"));
@@ -1771,6 +1784,11 @@ void GUI::file_export_ply()
     export_to("to-ply", std::vector<std::string>(), "ply", QStringList("PLY files (*.ply)"));
 }
 
+void GUI::file_export_png()
+{
+    export_to("to-png", std::vector<std::string>(), "png", QStringList("PNG files (*.png)"));
+}
+
 void GUI::file_export_pvm()
 {
     export_to("to-pvm", std::vector<std::string>(), "pvm", QStringList("PVM files (*.pvm)"));
index 89e13fd..f430462 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of gtatool, a tool to manipulate Generic Tagged Arrays
  * (GTAs).
  *
- * Copyright (C) 2010, 2011, 2012, 2013
+ * Copyright (C) 2010, 2011, 2012, 2013, 2014
  * Martin Lambers <marlam@marlam.de>
  *
  * This program is free software; you can redistribute it and/or modify
@@ -256,6 +256,7 @@ private slots:
     void file_import_pcd();
     void file_import_pfs();
     void file_import_ply();
+    void file_import_png();
     void file_import_pvm();
     void file_import_rat();
     void file_import_raw();
@@ -273,6 +274,7 @@ private slots:
     void file_export_pcd();
     void file_export_pfs();
     void file_export_ply();
+    void file_export_png();
     void file_export_pvm();
     void file_export_rat();
     void file_export_raw();
index 9c4426c..fbe2452 100644 (file)
@@ -95,6 +95,9 @@ endif
 if WITH_PMD
 TESTS += conv-pmd.sh
 endif
+if WITH_PNG
+TESTS += conv-png.sh
+endif
 if WITH_PVM
 TESTS += conv-pvm.sh
 endif
diff --git a/gtatool/tests/conv-png.sh b/gtatool/tests/conv-png.sh
new file mode 100755 (executable)
index 0000000..fe687ae
--- /dev/null
@@ -0,0 +1,44 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2014
+# Martin Lambers <marlam@marlam.de>
+#
+# Copying and distribution of this file, with or without modification, are
+# permitted in any medium without royalty provided the copyright notice and this
+# notice are preserved. This file is offered as-is, without any warranty.
+
+set -e
+
+TMPD="`mktemp -d tmp-\`basename $0 .sh\`.XXXXXX`"
+
+$GTA create -d 10,10 -c uint8 -v 42 "$TMPD"/a8.gta
+
+$GTA to-png "$TMPD"/a8.gta "$TMPD"/b8.png
+$GTA to-png "$TMPD"/c8.png < "$TMPD"/a8.gta
+cmp "$TMPD"/b8.png "$TMPD"/c8.png
+
+$GTA from-png "$TMPD"/b8.png "$TMPD"/b8.gta
+$GTA from-png "$TMPD"/c8.png > "$TMPD"/c8.gta
+
+$GTA tag --unset-all < "$TMPD"/b8.gta > "$TMPD"/d8.gta
+$GTA tag --unset-all < "$TMPD"/c8.gta > "$TMPD"/e8.gta
+
+cmp "$TMPD"/d8.gta "$TMPD"/a8.gta
+cmp "$TMPD"/e8.gta "$TMPD"/a8.gta
+
+$GTA create -d 10,10 -c uint8 -v 42 "$TMPD"/a16.gta
+
+$GTA to-png "$TMPD"/a16.gta "$TMPD"/b16.png
+$GTA to-png "$TMPD"/c16.png < "$TMPD"/a16.gta
+cmp "$TMPD"/b16.png "$TMPD"/c16.png
+
+$GTA from-png "$TMPD"/b16.png "$TMPD"/b16.gta
+$GTA from-png "$TMPD"/c16.png > "$TMPD"/c16.gta
+
+$GTA tag --unset-all < "$TMPD"/b16.gta > "$TMPD"/d16.gta
+$GTA tag --unset-all < "$TMPD"/c16.gta > "$TMPD"/e16.gta
+
+cmp "$TMPD"/d16.gta "$TMPD"/a16.gta
+cmp "$TMPD"/e16.gta "$TMPD"/a16.gta
+
+rm -r "$TMPD"