diff --git a/src/conversion.cpp b/src/conversion.cpp new file mode 100644 index 0000000..8ccca41 --- /dev/null +++ b/src/conversion.cpp @@ -0,0 +1,50 @@ +#include +#include +#include +#include +#include +#include +#include "pixels.hpp" + +static std::string resize_str() { + sc::term t {STDERR_FILENO}; + int cols = t.cols() - 1; + int rows = t.rows() * 2 - 4; + std::ostringstream oss; + oss << cols << "x" << rows; + return oss.str(); +} + +void convert(const std::string& path) { // try to convert to ppm using ImageMagick + int pfd[2]; + throw_if_min1_msg(pipe(pfd), "could not create pipe"); + + switch (fork()) { + case -1: + throw std::runtime_error {"could not fork"}; + + case 0: { // child + throw_if_min1(dup2(pfd[1], STDOUT_FILENO)); + throw_if_min1(close(pfd[0])); + throw_if_min1(close(pfd[1])); + + std::string resize {resize_str()}; + int res = execlp("magick", "magick", path.c_str(), "-resize", resize.c_str(), "ppm:-", nullptr); + if (res == -1) { // probably "magick" not found, try "convert" + res = execlp("convert", "convert", path.c_str(), "-resize", resize.c_str(), "ppm:-", nullptr); + if (res == -1) { // no ImageMagick, abort + throw std::runtime_error {"no ImageMagick installed, abort"}; + } + } + break; + } + + default: // parent + throw_if_min1(dup2(pfd[0], STDIN_FILENO)); + throw_if_min1(close(pfd[0])); + throw_if_min1(close(pfd[1])); + + write_image(std::cout, stdin); + break; + } +} diff --git a/src/conversion.hpp b/src/conversion.hpp new file mode 100644 index 0000000..0bb805c --- /dev/null +++ b/src/conversion.hpp @@ -0,0 +1,8 @@ +#ifndef CONVERSION_H_ +#define CONVERSION_H_ + +#include + +void convert(const std::string& path); + +#endif // CONVERSION_H_ diff --git a/src/main.cpp b/src/main.cpp index d7acf3f..102cfe8 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4,8 +4,10 @@ #include #include #include +#include #include "commit.inc" #include "pixels.hpp" +#include "conversion.hpp" void print_help() { std::cout << "usage: termage [-h|--version] \n"; @@ -55,7 +57,13 @@ int main(int argc, char* argv[]) { } for (int i = optind; i < argc; ++i) { try { - write_image(std::cout, argv[i]); + std::string path {argv[i]}; + std::string ext {sc::filename_extension(path)}; + if (ext != "ppm") { + convert(path); + } else { + write_image(std::cout, path); + } } catch (const std::runtime_error& ex) { std::cerr << "termage: " << ex.what() << '\n'; } diff --git a/src/pixels.cpp b/src/pixels.cpp index a7b20e4..2a89548 100644 --- a/src/pixels.cpp +++ b/src/pixels.cpp @@ -3,7 +3,7 @@ #include #include "pixels.hpp" -static void write(std::ostream& os, FILE* in) { +void write_image(std::ostream& os, FILE* in) { struct pam info; pnm_readpaminit(in, &info, PAM_STRUCT_SIZE(tuple_type)); std::unique_ptr row1 {pnm_allocpamrow(&info), pm_freerow}; @@ -32,10 +32,10 @@ static void write(std::ostream& os, FILE* in) { } void write_image(std::ostream& os) { - write(os, stdin); + write_image(os, stdin); } void write_image(std::ostream& os, const std::string& path) { std::unique_ptr infile {pm_openr(path.c_str()), pm_close}; - write(os, infile.get()); + write_image(os, infile.get()); } diff --git a/src/pixels.hpp b/src/pixels.hpp index c16bec7..5874d16 100644 --- a/src/pixels.hpp +++ b/src/pixels.hpp @@ -4,6 +4,7 @@ #include void write_image(std::ostream& os); +void write_image(std::ostream& os, FILE*); void write_image(std::ostream& os, const std::string& path); #endif // PIXELS_H_