Add conversion from any input file via ImageMagick

This commit is contained in:
Bob Polis 2024-01-29 15:54:09 +01:00
parent ef4f87295e
commit 02a5601466
5 changed files with 71 additions and 4 deletions

50
src/conversion.cpp Normal file
View File

@ -0,0 +1,50 @@
#include <stdexcept>
#include <string>
#include <sstream>
#include <unistd.h>
#include <libscerror.hpp>
#include <libscterm.hpp>
#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;
}
}

8
src/conversion.hpp Normal file
View File

@ -0,0 +1,8 @@
#ifndef CONVERSION_H_
#define CONVERSION_H_
#include <string>
void convert(const std::string& path);
#endif // CONVERSION_H_

View File

@ -4,8 +4,10 @@
#include <stdexcept> #include <stdexcept>
#include <getopt.h> #include <getopt.h>
#include <netpbm/pam.h> #include <netpbm/pam.h>
#include <libscstring.hpp>
#include "commit.inc" #include "commit.inc"
#include "pixels.hpp" #include "pixels.hpp"
#include "conversion.hpp"
void print_help() { void print_help() {
std::cout << "usage: termage [-h|--version] <imagefile>\n"; std::cout << "usage: termage [-h|--version] <imagefile>\n";
@ -55,7 +57,13 @@ int main(int argc, char* argv[]) {
} }
for (int i = optind; i < argc; ++i) { for (int i = optind; i < argc; ++i) {
try { 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) { } catch (const std::runtime_error& ex) {
std::cerr << "termage: " << ex.what() << '\n'; std::cerr << "termage: " << ex.what() << '\n';
} }

View File

@ -3,7 +3,7 @@
#include <netpbm/pam.h> #include <netpbm/pam.h>
#include "pixels.hpp" #include "pixels.hpp"
static void write(std::ostream& os, FILE* in) { void write_image(std::ostream& os, FILE* in) {
struct pam info; struct pam info;
pnm_readpaminit(in, &info, PAM_STRUCT_SIZE(tuple_type)); pnm_readpaminit(in, &info, PAM_STRUCT_SIZE(tuple_type));
std::unique_ptr<tuple, void(*)(void*)> row1 {pnm_allocpamrow(&info), pm_freerow}; std::unique_ptr<tuple, void(*)(void*)> row1 {pnm_allocpamrow(&info), pm_freerow};
@ -32,10 +32,10 @@ static void write(std::ostream& os, FILE* in) {
} }
void write_image(std::ostream& os) { void write_image(std::ostream& os) {
write(os, stdin); write_image(os, stdin);
} }
void write_image(std::ostream& os, const std::string& path) { void write_image(std::ostream& os, const std::string& path) {
std::unique_ptr<FILE, void(*)(FILE*)> infile {pm_openr(path.c_str()), pm_close}; std::unique_ptr<FILE, void(*)(FILE*)> infile {pm_openr(path.c_str()), pm_close};
write(os, infile.get()); write_image(os, infile.get());
} }

View File

@ -4,6 +4,7 @@
#include <iostream> #include <iostream>
void write_image(std::ostream& os); void write_image(std::ostream& os);
void write_image(std::ostream& os, FILE*);
void write_image(std::ostream& os, const std::string& path); void write_image(std::ostream& os, const std::string& path);
#endif // PIXELS_H_ #endif // PIXELS_H_