From c82f3aad2ea6933f37b469688a4eb9405850e5ba Mon Sep 17 00:00:00 2001 From: Danny Robson Date: Wed, 3 Jun 2015 23:24:26 +1000 Subject: [PATCH] netpbm: extract ppm/pgm into distinct unit --- Makefile.am | 2 + image.cpp | 113 +------------------------------------------ image.hpp | 25 ---------- netpbm.cpp | 126 ++++++++++++++++++++++++++++++++++++++++++++++++ netpbm.hpp | 51 ++++++++++++++++++++ tools/noise.cpp | 3 +- 6 files changed, 182 insertions(+), 138 deletions(-) create mode 100644 netpbm.cpp create mode 100644 netpbm.hpp diff --git a/Makefile.am b/Makefile.am index af5f0870..81b6efc7 100644 --- a/Makefile.am +++ b/Makefile.am @@ -136,6 +136,8 @@ UTIL_FILES = \ net/socket.hpp \ net/types.cpp \ net/types.hpp \ + netpbm.cpp \ + netpbm.hpp \ nocopy.hpp \ noise.hpp \ noise/basis.hpp \ diff --git a/image.cpp b/image.cpp index 964bd11a..83303e13 100644 --- a/image.cpp +++ b/image.cpp @@ -14,16 +14,10 @@ * Copyright 2011-2015 Danny Robson */ - #include "image.hpp" + #include "debug.hpp" -#include "except.hpp" -#include "io.hpp" - -#include - - using util::image::buffer; @@ -358,111 +352,6 @@ buffer::end (void) const } -/////////////////////////////////////////////////////////////////////////////// -// HACK: This does not support the full header structure with any robustness. -// In particular it will abort when it sees a comment. If you want better -// support use waif, or port its implementation. -util::image::buffer -util::pgm::read (const boost::filesystem::path &path) -{ - util::mapped_file raw (path); - - std::ifstream cooked (path.string (), std::ios::binary); - char magic[2]; - size_t width, height, scale; - char space; - - cooked >> magic[0] >> magic[1] >> width >> height >> scale >> space; - - if (magic[0] != 'P' && magic[1] != '5') - throw std::runtime_error ("invalid header magic"); - - if (width == 0 || height == 0 || scale == 0) - throw std::runtime_error ("zero width, height, or scale"); - - size_t expected = width * height; - size_t remain = raw.size () - cooked.tellg (); - if (expected != remain) - throw std::runtime_error ("expected data size mismatch"); - - util::image::buffer out (width, height); - - CHECK_EQ (out.w, out.s); - std::copy (raw.begin () + cooked.tellg () - 1, raw.end (), out.begin ()); - - return out; -} - -//----------------------------------------------------------------------------- -static void -write_netpbm (const uint8_t *restrict pixels, - size_t components, - size_t width, - size_t height, - size_t stride, - const boost::filesystem::path &path, - const char* MAGIC) { - CHECK (pixels); - CHECK_GT (components, 0); - CHECK_GT (width, 0); - CHECK_GE (stride, width); - CHECK_GT (height, 0); - - // Establish an output stream - std::ofstream output (path.string ()); - if (!output.good ()) - throw util::output_error ("Unable to open output file"); - - // Write the PPM header. - output << MAGIC << "\n" - << width << "\n" - << height << "\n" - << (size_t)std::numeric_limits::max () << "\n"; - - // Write the data rows - for (size_t y = 0; y < height; ++y) { - for (size_t x = 0; x < width; ++x) - for (size_t c = 0; c < components; ++c) - output << pixels[y * stride + x * components + c]; - } -} - - -//----------------------------------------------------------------------------- -void -util::pgm::write (const util::image::buffer &src, - const boost::filesystem::path &path) -{ - write (src.begin (), src.w, src.h, src.s, path); -} - - -//----------------------------------------------------------------------------- -void -util::pgm::write (const uint8_t *restrict pixels, - size_t width, - size_t height, - size_t stride, - const boost::filesystem::path &path) { - // TODO: We should switch between P2 (ascii) and P5 (binary) - static const char MAGIC[] = "P5"; - write_netpbm (pixels, 1, width, height, stride, path, MAGIC); -} - - -//----------------------------------------------------------------------------- -void -util::ppm::write (const uint8_t *restrict pixels, - size_t width, - size_t height, - size_t stride, - const boost::filesystem::path &path) { - // TODO: We should switch between P3 (ascii) and P6 (binary) - static const char MAGIC[] = "P6"; - write_netpbm (pixels, 3, width, height, stride, path, MAGIC); -} - - //----------------------------------------------------------------------------- template struct util::image::buffer; template struct util::image::buffer; diff --git a/image.hpp b/image.hpp index d09ac4d4..fa3d76c0 100644 --- a/image.hpp +++ b/image.hpp @@ -23,7 +23,6 @@ #include #include #include -#include namespace util { @@ -72,30 +71,6 @@ namespace util { std::unique_ptr m_data; }; } - - - // Portable GrayMap: single component greyscale. - struct pgm { - static image::buffer read (const boost::filesystem::path&); - - static void write (const image::buffer &src, - const boost::filesystem::path &); - - static void write (const uint8_t *restrict pixels, - size_t width, - size_t height, - size_t stride, - const boost::filesystem::path &path); - }; - - /// Portable PixMap: 3-component colour images. - struct ppm { - static void write (const uint8_t *restrict pixels, - size_t width, - size_t height, - size_t stride, - const boost::filesystem::path &path); - }; } #endif diff --git a/netpbm.cpp b/netpbm.cpp new file mode 100644 index 00000000..6756a5c2 --- /dev/null +++ b/netpbm.cpp @@ -0,0 +1,126 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright 2011-2015 Danny Robson + */ + +#include "netpbm.hpp" + +#include "io.hpp" +#include "except.hpp" +#include + + +/////////////////////////////////////////////////////////////////////////////// +// HACK: This does not support the full header structure with any robustness. +// In particular it will abort when it sees a comment. If you want better +// support use waif, or port its implementation. +util::image::buffer +util::pgm::read (const boost::filesystem::path &path) +{ + util::mapped_file raw (path); + + std::ifstream cooked (path.string (), std::ios::binary); + char magic[2]; + size_t width, height, scale; + char space; + + cooked >> magic[0] >> magic[1] >> width >> height >> scale >> space; + + if (magic[0] != 'P' && magic[1] != '5') + throw std::runtime_error ("invalid header magic"); + + if (width == 0 || height == 0 || scale == 0) + throw std::runtime_error ("zero width, height, or scale"); + + size_t expected = width * height; + size_t remain = raw.size () - cooked.tellg (); + if (expected != remain) + throw std::runtime_error ("expected data size mismatch"); + + util::image::buffer out (width, height); + + CHECK_EQ (out.w, out.s); + std::copy (raw.begin () + cooked.tellg () - 1, raw.end (), out.begin ()); + + return out; +} + +//----------------------------------------------------------------------------- +static void +write_netpbm (const uint8_t *restrict pixels, + size_t components, + size_t width, + size_t height, + size_t stride, + const boost::filesystem::path &path, + const char* MAGIC) { + CHECK (pixels); + CHECK_GT (components, 0); + CHECK_GT (width, 0); + CHECK_GE (stride, width); + CHECK_GT (height, 0); + + // Establish an output stream + std::ofstream output (path.string ()); + if (!output.good ()) + throw util::output_error ("Unable to open output file"); + + // Write the PPM header. + output << MAGIC << "\n" + << width << "\n" + << height << "\n" + << (size_t)std::numeric_limits::max () << "\n"; + + // Write the data rows + for (size_t y = 0; y < height; ++y) { + for (size_t x = 0; x < width; ++x) + for (size_t c = 0; c < components; ++c) + output << pixels[y * stride + x * components + c]; + } +} + + +//----------------------------------------------------------------------------- +void +util::pgm::write (const util::image::buffer &src, + const boost::filesystem::path &path) +{ + write (src.begin (), src.w, src.h, src.s, path); +} + + +//----------------------------------------------------------------------------- +void +util::pgm::write (const uint8_t *restrict pixels, + size_t width, + size_t height, + size_t stride, + const boost::filesystem::path &path) { + // TODO: We should switch between P2 (ascii) and P5 (binary) + static const char MAGIC[] = "P5"; + write_netpbm (pixels, 1, width, height, stride, path, MAGIC); +} + + +//----------------------------------------------------------------------------- +void +util::ppm::write (const uint8_t *restrict pixels, + size_t width, + size_t height, + size_t stride, + const boost::filesystem::path &path) { + // TODO: We should switch between P3 (ascii) and P6 (binary) + static const char MAGIC[] = "P6"; + write_netpbm (pixels, 3, width, height, stride, path, MAGIC); +} diff --git a/netpbm.hpp b/netpbm.hpp new file mode 100644 index 00000000..69b9d6f8 --- /dev/null +++ b/netpbm.hpp @@ -0,0 +1,51 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright 2011-2015 Danny Robson + */ + +#ifndef __UTIL_NETPBM_HPP +#define __UTIL_NETPBM_HPP + +#include "image.hpp" + +#include +#include +#include + +namespace util { + // Portable GrayMap: single component greyscale. + struct pgm { + static image::buffer read (const boost::filesystem::path&); + + static void write (const image::buffer &src, + const boost::filesystem::path &); + + static void write (const uint8_t *restrict pixels, + size_t width, + size_t height, + size_t stride, + const boost::filesystem::path &path); + }; + + /// Portable PixMap: 3-component colour images. + struct ppm { + static void write (const uint8_t *restrict pixels, + size_t width, + size_t height, + size_t stride, + const boost::filesystem::path &path); + }; +} + +#endif diff --git a/tools/noise.cpp b/tools/noise.cpp index 621af9d4..4292fdfa 100644 --- a/tools/noise.cpp +++ b/tools/noise.cpp @@ -13,6 +13,7 @@ #include "noise/turbulence.hpp" #include "extent.hpp" #include "colour.hpp" +#include "netpbm.hpp" template struct util::noise::fractal::fbm>; template struct util::noise::fractal::hmf>; @@ -23,7 +24,7 @@ int main (void) { // setup the output buffer -#if ENABLE_DEBUGGING +#ifdef ENABLE_DEBUGGING util::extent2u size {320, 240}; #else util::extent2u size {1920, 1080};