diff --git a/.gitignore b/.gitignore index e9f4eb9..0e5ed02 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ .vscode *.o +*.plist tests/test tests/*.o tests/_test_pdf2printable_16x9_* diff --git a/README.md b/README.md index c9a337a..185413f 100644 --- a/README.md +++ b/README.md @@ -8,9 +8,7 @@ Available as rudimentary standalone applications, but mainly made for use in [SeaPrint](https://github.com/attah/harbour-seaprint). ## ppm2pwg -Takes a pbm, pgm or ppm (P4, P5 or P6 "raw") Netpbm bitmap image and converts to PWG or URF printer raster format. - -...or a raw bitmap in the c++ api. +Takes a pbm, pgm or ppm (P4, P5 or P6 "raw") Netpbm bitmap image and converts to PWG or URF printer raster format. Supports 1, 8 and **16** bits per color. ## pwg2ppm For debugging. Similar to [rasterview](https://github.com/michaelrsweet/rasterview), but without a GUI. Takes a PWG or URF printer raster and outputs a series of P4, P5 or P6 pbm/pgm/ppm images. @@ -24,7 +22,7 @@ Takes a PDF document and makes it suitable for printing, by: ## baselinify Takes a JPEG and losslessly repacks it to the baseline ecoding profile, keeping only JFIF and Exif headers. -Sort of like jpegtran without any arguments, but reusable in C++. +Sort of like jpegtran without any arguments. IPP-printers are only required to support baseline-encoded jpeg according to PWG5100.14. diff --git a/lib/pdf2printable.cpp b/lib/pdf2printable.cpp index dd7a9bb..6374cdc 100644 --- a/lib/pdf2printable.cpp +++ b/lib/pdf2printable.cpp @@ -300,6 +300,10 @@ void copy_raster_buffer(Bytestream& bmpBts, uint32_t* data, const PrintParameter } break; } + default: + { + throw std::logic_error("Unhandled color mode"); + } } } diff --git a/lib/ppm2pwg.cpp b/lib/ppm2pwg.cpp index 6435555..0bf9a55 100644 --- a/lib/ppm2pwg.cpp +++ b/lib/ppm2pwg.cpp @@ -10,6 +10,12 @@ #include #include +void make_pwg_hdr(Bytestream& outBts, const PrintParameters& params, bool backside); +void make_urf_hdr(Bytestream& outBts, const PrintParameters& params); + +void compress_lines(Bytestream& bmpBts, Bytestream& outBts, const PrintParameters& params, bool backside); +void compress_line(uint8_t* raw, size_t len, Bytestream& outBts, size_t oneChunk); + Bytestream make_pwg_file_hdr() { Bytestream pwgFileHdr; @@ -42,21 +48,27 @@ void bmp_to_pwg(Bytestream& bmpBts, Bytestream& outBts, size_t page, const Print size_t yRes = params.getPaperSizeHInPixels(); uint8_t* raw = bmpBts.raw(); size_t bytesPerLine = params.getPaperSizeWInBytes(); - int step = backside&¶ms.getBackVFlip() ? -bytesPerLine : bytesPerLine; - uint8_t* row0 = backside&¶ms.getBackVFlip() ? raw+(yRes-1)*bytesPerLine : raw; + int oneLine = backside && params.getBackVFlip() ? -bytesPerLine : bytesPerLine; + uint8_t* row0 = backside && params.getBackVFlip() ? raw + (yRes - 1) * bytesPerLine : raw; Array tmpLine(bytesPerLine); - for(size_t y=0; y urfColorSpaceMappings {{PrintParameters::sRGB24, UrfPgHdr::sRGB}, {PrintParameters::CMYK32, UrfPgHdr::CMYK}, - {PrintParameters::Gray8, UrfPgHdr::sGray}}; + {PrintParameters::Gray8, UrfPgHdr::sGray}, + {PrintParameters::sRGB48, UrfPgHdr::sRGB}, + {PrintParameters::Gray16, UrfPgHdr::sGray}}; static const std::map urfDuplexMappings {{PrintParameters::OneSided, UrfPgHdr::OneSided}, {PrintParameters::TwoSidedLongEdge, UrfPgHdr::TwoSidedLongEdge}, {PrintParameters::TwoSidedShortEdge, UrfPgHdr::TwoSidedShortEdge}}; - outHdr.BitsPerPixel = 8*params.getNumberOfColors(); + outHdr.BitsPerPixel = params.getNumberOfColors() * params.getBitsPerColor(); outHdr.ColorSpace = urfColorSpaceMappings.at(params.colorMode); outHdr.Duplex = urfDuplexMappings.at(params.duplexMode); outHdr.setQuality(params.quality); diff --git a/lib/ppm2pwg.h b/lib/ppm2pwg.h index 7f501e0..bbc3537 100644 --- a/lib/ppm2pwg.h +++ b/lib/ppm2pwg.h @@ -10,17 +10,7 @@ Bytestream make_pwg_file_hdr(); Bytestream make_urf_file_hdr(uint32_t pages); -void make_pwg_hdr(Bytestream& outBts, const PrintParameters& params, bool backside); -void make_urf_hdr(Bytestream& outBts, const PrintParameters& params); - - -void bmp_to_pwg(Bytestream& bmpBts, Bytestream& outBts, size_t page, - const PrintParameters& params); - -void compress_lines(Bytestream& bmpBts, Bytestream& outBts, - const PrintParameters& params, bool backside); - -void compress_line(uint8_t* raw, size_t len, Bytestream& outBts, int Colors); +void bmp_to_pwg(Bytestream& bmpBts, Bytestream& outBts, size_t page, const PrintParameters& params); bool isUrfMediaType(std::string mediaType); diff --git a/lib/printparameters.cpp b/lib/printparameters.cpp index 34bc47b..475ae29 100644 --- a/lib/printparameters.cpp +++ b/lib/printparameters.cpp @@ -110,14 +110,18 @@ double PrintParameters::getPaperSizeHInPoints() const size_t PrintParameters::getPaperSizeWInBytes() const { - if(getBitsPerColor() == 1) + if(getBitsPerColor() == 1 && getNumberOfColors() == 1) { // Round up to whole bytes - return getNumberOfColors() * ((getPaperSizeWInPixels() + 7) / 8); + return (getPaperSizeWInPixels() + 7) / 8; + } + else if(getBitsPerColor() % 8 == 0) + { + return getPaperSizeWInPixels() * getNumberOfColors() * (getBitsPerColor() / 8); } else { - return getNumberOfColors() * (getPaperSizeWInPixels() / (8 / getBitsPerColor())); + throw(std::logic_error("Unhandled color and bit depth combination")); } } @@ -272,6 +276,8 @@ bool PrintParameters::isBlack() const case CMYK32: case Gray8: case Gray1: + case sRGB48: + case Gray16: return false; case Black8: case Black1: @@ -286,6 +292,7 @@ size_t PrintParameters::getNumberOfColors() const switch(colorMode) { case sRGB24: + case sRGB48: return 3; case CMYK32: return 4; @@ -293,6 +300,7 @@ size_t PrintParameters::getNumberOfColors() const case Black8: case Gray1: case Black1: + case Gray16: return 1; default: throw(std::logic_error("Unknown color mode")); @@ -311,6 +319,9 @@ size_t PrintParameters::getBitsPerColor() const case Gray1: case Black1: return 1; + case sRGB48: + case Gray16: + return 16; default: throw(std::logic_error("Unknown color mode")); } diff --git a/lib/printparameters.h b/lib/printparameters.h index 2176559..9e910a8 100644 --- a/lib/printparameters.h +++ b/lib/printparameters.h @@ -32,7 +32,9 @@ class PrintParameters Gray8, Black8, Gray1, - Black1 + Black1, + sRGB48, + Gray16 }; enum Quality diff --git a/tests/Makefile b/tests/Makefile index e518889..b743380 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -1,7 +1,7 @@ LDFLAGS = -ldl -Wl,--export-dynamic -lcurl -ljpeg $(shell pkg-config --libs poppler-glib) -lz CXXFLAGS = -std=c++17 -g -pedantic -Wall -Werror -Wextra -I ../lib -I ../json11 -I ../bytestream \ $(shell pkg-config --cflags poppler-glib) -TEST_INCLUDES = -I ../lib -I ../bytestream/minitest -I ../bytestream/minitest/tests +TEST_INCLUDES = -I ../lib -I ../bytestream/minitest VPATH = ../bytestream ../lib ../json11 diff --git a/tests/test.cpp b/tests/test.cpp index b10f304..c39af5e 100644 --- a/tests/test.cpp +++ b/tests/test.cpp @@ -1,6 +1,5 @@ #include "bytestream.h" #include "test.h" -#include "subprocess.hpp" #include "pwgpghdr.h" #include "pwg2ppm.h" #include "printparameters.h" @@ -11,21 +10,23 @@ #include "ippprintjob.h" #include "json11.hpp" #include +#include using namespace std; using namespace json11; #define REPEAT(N) (uint8_t)(N-1) #define VERBATIM(N) (uint8_t)(257-N) -Bytestream W {(uint8_t)255, (uint8_t)255, (uint8_t)255}; -Bytestream R {(uint8_t)255, (uint8_t)0, (uint8_t)0}; -Bytestream G {(uint8_t)0, (uint8_t)255, (uint8_t)0}; -Bytestream B {(uint8_t)0, (uint8_t)0, (uint8_t)255}; -Bytestream Y {(uint8_t)255, (uint8_t)255, (uint8_t)0}; - +template Bytestream PacmanPpm() { - Bytestream ppm {string("P6\n8 8\n255\n")}; + T max = std::numeric_limits::max(); + Bytestream W {(T)max, (T)max, (T)max}; + Bytestream R {(T)max, (T)0, (T)0}; + Bytestream G {(T)0, (T)max, (T)0}; + Bytestream B {(T)0, (T)0, (T)max}; + Bytestream Y {(T)max, (T)max, (T)0}; + Bytestream ppm {"P6\n8 8\n", to_string(max), "\n"}; ppm << W << Y << Y << Y << W << W << W << W << Y << B << Y << W << W << W << G << W << Y << Y << W << W << W << G << G << G @@ -37,8 +38,15 @@ Bytestream PacmanPpm() return ppm; } +template Bytestream RightSideUp() { + T max = std::numeric_limits::max(); + Bytestream W {(T)max, (T)max, (T)max}; + Bytestream R {(T)max, (T)0, (T)0}; + Bytestream G {(T)0, (T)max, (T)0}; + Bytestream B {(T)0, (T)0, (T)max}; + Bytestream Y {(T)max, (T)max, (T)0}; Bytestream enc; enc << (uint8_t)0 << REPEAT(1) << W << REPEAT(3) << Y << REPEAT(4) << W << (uint8_t)0 << VERBATIM(3) << Y << B << Y << REPEAT(3) << W << VERBATIM(2) << G << W @@ -50,8 +58,15 @@ Bytestream RightSideUp() return enc; } +template Bytestream UpsideDown() { + T max = std::numeric_limits::max(); + Bytestream W {(T)max, (T)max, (T)max}; + Bytestream R {(T)max, (T)0, (T)0}; + Bytestream G {(T)0, (T)max, (T)0}; + Bytestream B {(T)0, (T)0, (T)max}; + Bytestream Y {(T)max, (T)max, (T)0}; Bytestream enc; enc << (uint8_t)1 << REPEAT(8) << R << (uint8_t)0 << REPEAT(8) << W @@ -63,8 +78,15 @@ Bytestream UpsideDown() return enc; } +template Bytestream Flipped() { + T max = std::numeric_limits::max(); + Bytestream W {(T)max, (T)max, (T)max}; + Bytestream R {(T)max, (T)0, (T)0}; + Bytestream G {(T)0, (T)max, (T)0}; + Bytestream B {(T)0, (T)0, (T)max}; + Bytestream Y {(T)max, (T)max, (T)0}; Bytestream enc; enc << (uint8_t)0 << REPEAT(4) << W << REPEAT(3) << Y << REPEAT(1) << W << (uint8_t)0 << VERBATIM(2) << W << G << REPEAT(3) << W << VERBATIM(3) << Y << B << Y @@ -76,8 +98,15 @@ Bytestream Flipped() return enc; } +template Bytestream Rotated() { + T max = std::numeric_limits::max(); + Bytestream W {(T)max, (T)max, (T)max}; + Bytestream R {(T)max, (T)0, (T)0}; + Bytestream G {(T)0, (T)max, (T)0}; + Bytestream B {(T)0, (T)0, (T)max}; + Bytestream Y {(T)max, (T)max, (T)0}; Bytestream enc; enc << (uint8_t)1 << REPEAT(8) << R << (uint8_t)0 << REPEAT(8) << W @@ -147,27 +176,46 @@ Bytestream BilevelPwg0101_Rotated() return enc; } +Bytestream run_ppm2pwg(List args, Bytestream input, std::string tmpfile) +{ + std::filesystem::remove(tmpfile); + args.push_front("../ppm2pwg"); + args += {"-", tmpfile}; + FILE* file = popen(join_string(args, " ").c_str(), "w"); + fwrite(input.raw(), input.size(), 1, file); + pclose(file); + + std::ifstream pwg_ifs(tmpfile); + return Bytestream(pwg_ifs); +} + +Bytestream run_pdf2printable(List args, std::string infile, std::string outfile) +{ + args.push_front("../pdf2printable"); + args += {infile, outfile}; + FILE* file = popen(join_string(args, " ").c_str(), "w"); + pclose(file); + std::ifstream pwg_ifs(outfile); + return Bytestream(pwg_ifs); +} + TEST(ppm2pwg) { - Bytestream ppm = PacmanPpm(); + Bytestream ppm = PacmanPpm(); // For sanity, make sure the one on disk is the same as created above std::ifstream ppm_ifs("pacman.ppm"); Bytestream expected_ppm(ppm_ifs); ASSERT(ppm == expected_ppm); - subprocess::popen ppm2pwg("../ppm2pwg", {"pacman.ppm", "-"}); - ppm2pwg.close(); + Bytestream pwg = run_ppm2pwg({}, ppm, __func__); - ASSERT(ppm2pwg.wait() == 0); - - Bytestream pwg(ppm2pwg.stdout()); PwgPgHdr hdr; ASSERT(pwg >>= "RaS2"); hdr.decodeFrom(pwg); - Bytestream enc = RightSideUp(); + Bytestream enc = RightSideUp(); ASSERT(pwg >>= enc); ASSERT(pwg.atEnd()); @@ -180,134 +228,229 @@ TEST(ppm2pwg) ASSERT(pwg == expected_pwg); } +TEST(ppm2pwg_16bit) +{ + Bytestream ppm = PacmanPpm(); + Bytestream pwg = run_ppm2pwg({}, ppm, __func__); + + PwgPgHdr hdr; + + ASSERT(pwg >>= "RaS2"); + hdr.decodeFrom(pwg); + + Bytestream enc = RightSideUp(); + + ASSERT(pwg >>= enc); + ASSERT(pwg.atEnd()); +} + TEST(duplex_normal) { Bytestream twoSided; - twoSided << PacmanPpm() << PacmanPpm(); + twoSided << PacmanPpm() << PacmanPpm(); - setenv("DUPLEX", "true", true); - subprocess::popen ppm2pwg("../ppm2pwg", {"-", "-"}); - ppm2pwg.stdin() << twoSided; - ppm2pwg.close(); + Bytestream pwg = run_ppm2pwg({"-d"}, twoSided, __func__); - ASSERT(ppm2pwg.wait() == 0); + PwgPgHdr hdr1, hdr2; + + ASSERT(pwg >>= "RaS2"); + hdr1.decodeFrom(pwg); + ASSERT(hdr1.CrossFeedTransform == 1); + ASSERT(hdr1.FeedTransform == 1); + ASSERT(pwg >>= RightSideUp()); + hdr2.decodeFrom(pwg); + ASSERT(hdr2.CrossFeedTransform == 1); + ASSERT(hdr2.FeedTransform == 1); + ASSERT(pwg >>= RightSideUp()); + ASSERT(pwg.atEnd()); +} + +TEST(duplex_normal_16bit) +{ + Bytestream twoSided; + twoSided << PacmanPpm() << PacmanPpm(); + + Bytestream pwg = run_ppm2pwg({"-d"}, twoSided, __func__); - Bytestream pwg(ppm2pwg.stdout()); PwgPgHdr hdr1, hdr2; ASSERT(pwg >>= "RaS2"); hdr1.decodeFrom(pwg); ASSERT(hdr1.CrossFeedTransform == 1); ASSERT(hdr1.FeedTransform == 1); - ASSERT(pwg >>= RightSideUp()); + ASSERT(pwg >>= RightSideUp()); hdr2.decodeFrom(pwg); ASSERT(hdr2.CrossFeedTransform == 1); ASSERT(hdr2.FeedTransform == 1); - ASSERT(pwg >>= RightSideUp()); + ASSERT(pwg >>= RightSideUp()); ASSERT(pwg.atEnd()); } TEST(duplex_vflip) { Bytestream twoSided; - twoSided << PacmanPpm() << PacmanPpm(); + twoSided << PacmanPpm() << PacmanPpm(); + + Bytestream pwg = run_ppm2pwg({"-d", "--back-xform", "flip"}, twoSided, __func__); + + PwgPgHdr hdr1, hdr2; + + ASSERT(pwg >>= "RaS2"); + hdr1.decodeFrom(pwg); + ASSERT(hdr1.CrossFeedTransform == 1); + ASSERT(hdr1.FeedTransform == 1); + ASSERT(pwg >>= RightSideUp()); + hdr2.decodeFrom(pwg); + ASSERT(hdr2.CrossFeedTransform == 1); + ASSERT(hdr2.FeedTransform == -1); + ASSERT(pwg >>= UpsideDown()); + ASSERT(pwg.atEnd()); +} - subprocess::popen ppm2pwg("../ppm2pwg", {"-d", "--back-xform", "flip", "-", "-"}); - ppm2pwg.stdin() << twoSided; - ppm2pwg.close(); +TEST(duplex_vflip_16bit) +{ + Bytestream twoSided; + twoSided << PacmanPpm() << PacmanPpm(); - ASSERT(ppm2pwg.wait() == 0); + Bytestream pwg = run_ppm2pwg({"-d", "--back-xform", "flip"}, twoSided, __func__); - Bytestream pwg(ppm2pwg.stdout()); PwgPgHdr hdr1, hdr2; ASSERT(pwg >>= "RaS2"); hdr1.decodeFrom(pwg); ASSERT(hdr1.CrossFeedTransform == 1); ASSERT(hdr1.FeedTransform == 1); - ASSERT(pwg >>= RightSideUp()); + ASSERT(pwg >>= RightSideUp()); hdr2.decodeFrom(pwg); ASSERT(hdr2.CrossFeedTransform == 1); ASSERT(hdr2.FeedTransform == -1); - ASSERT(pwg >>= UpsideDown()); + ASSERT(pwg >>= UpsideDown()); ASSERT(pwg.atEnd()); } TEST(duplex_hflip) { Bytestream twoSided; - twoSided << PacmanPpm() << PacmanPpm(); + twoSided << PacmanPpm() << PacmanPpm(); - subprocess::popen ppm2pwg("../ppm2pwg", {"-d", "-t", "--back-xform", "flip", "-", "-"}); - ppm2pwg.stdin() << twoSided; - ppm2pwg.close(); + Bytestream pwg = run_ppm2pwg({"-d", "-t", "--back-xform", "flip"}, twoSided, __func__); - ASSERT(ppm2pwg.wait() == 0); + PwgPgHdr hdr1, hdr2; + + ASSERT(pwg >>= "RaS2"); + hdr1.decodeFrom(pwg); + ASSERT(hdr1.CrossFeedTransform == 1); + ASSERT(hdr1.FeedTransform == 1); + ASSERT(pwg >>= RightSideUp()); + hdr2.decodeFrom(pwg); + ASSERT(hdr2.CrossFeedTransform == -1); + ASSERT(hdr2.FeedTransform == 1); + ASSERT(pwg >>= Flipped()); + ASSERT(pwg.atEnd()); +} + +TEST(duplex_hflip_16bit) +{ + Bytestream twoSided; + twoSided << PacmanPpm() << PacmanPpm(); + + Bytestream pwg = run_ppm2pwg({"-d", "-t", "--back-xform", "flip"}, twoSided, __func__); - Bytestream pwg(ppm2pwg.stdout()); PwgPgHdr hdr1, hdr2; ASSERT(pwg >>= "RaS2"); hdr1.decodeFrom(pwg); ASSERT(hdr1.CrossFeedTransform == 1); ASSERT(hdr1.FeedTransform == 1); - ASSERT(pwg >>= RightSideUp()); + ASSERT(pwg >>= RightSideUp()); hdr2.decodeFrom(pwg); ASSERT(hdr2.CrossFeedTransform == -1); ASSERT(hdr2.FeedTransform == 1); - ASSERT(pwg >>= Flipped()); + ASSERT(pwg >>= Flipped()); ASSERT(pwg.atEnd()); } TEST(duplex_rotated) { Bytestream twoSided; - twoSided << PacmanPpm() << PacmanPpm(); + twoSided << PacmanPpm() << PacmanPpm(); + + Bytestream pwg = run_ppm2pwg({"-d", "--back-xform", "rotate"}, twoSided, __func__); - subprocess::popen ppm2pwg("../ppm2pwg", {"-d", "--back-xform", "rotate", "-", "-"}); - ppm2pwg.stdin() << twoSided; - ppm2pwg.close(); + PwgPgHdr hdr1, hdr2; + + ASSERT(pwg >>= "RaS2"); + hdr1.decodeFrom(pwg); + ASSERT(hdr1.CrossFeedTransform == 1); + ASSERT(hdr1.FeedTransform == 1); + ASSERT(pwg >>= RightSideUp()); + hdr2.decodeFrom(pwg); + ASSERT(hdr2.CrossFeedTransform == -1); + ASSERT(hdr2.FeedTransform == -1); + ASSERT(pwg >>= Rotated()); + ASSERT(pwg.atEnd()); +} + +TEST(duplex_rotated_16bit) +{ + Bytestream twoSided; + twoSided << PacmanPpm() << PacmanPpm(); - ASSERT(ppm2pwg.wait() == 0); + Bytestream pwg = run_ppm2pwg({"-d", "--back-xform", "rotate"}, twoSided, __func__); - Bytestream pwg(ppm2pwg.stdout()); PwgPgHdr hdr1, hdr2; ASSERT(pwg >>= "RaS2"); hdr1.decodeFrom(pwg); ASSERT(hdr1.CrossFeedTransform == 1); ASSERT(hdr1.FeedTransform == 1); - ASSERT(pwg >>= RightSideUp()); + ASSERT(pwg >>= RightSideUp()); hdr2.decodeFrom(pwg); ASSERT(hdr2.CrossFeedTransform == -1); ASSERT(hdr2.FeedTransform == -1); - ASSERT(pwg >>= Rotated()); + ASSERT(pwg >>= Rotated()); ASSERT(pwg.atEnd()); } TEST(two_pages_no_duplex) { Bytestream twoSided; - twoSided << PacmanPpm() << PacmanPpm(); + twoSided << PacmanPpm() << PacmanPpm(); + + Bytestream pwg = run_ppm2pwg({"--back-xform", "flip"}, twoSided, __func__); + + PwgPgHdr hdr1, hdr2; + + ASSERT(pwg >>= "RaS2"); + hdr1.decodeFrom(pwg); + ASSERT(hdr1.CrossFeedTransform == 1); + ASSERT(hdr1.FeedTransform == 1); + ASSERT(pwg >>= RightSideUp()); + hdr2.decodeFrom(pwg); + ASSERT(hdr2.CrossFeedTransform == 1); + ASSERT(hdr2.FeedTransform == 1); + ASSERT(pwg >>= RightSideUp()); + ASSERT(pwg.atEnd()); +} - subprocess::popen ppm2pwg("../ppm2pwg", {"--back-xform", "rotate", "-", "-"}); - ppm2pwg.stdin() << twoSided; - ppm2pwg.close(); +TEST(two_pages_no_duplex_16bit) +{ + Bytestream twoSided; + twoSided << PacmanPpm() << PacmanPpm(); - ASSERT(ppm2pwg.wait() == 0); + Bytestream pwg = run_ppm2pwg({"--back-xform", "flip"}, twoSided, __func__); - Bytestream pwg(ppm2pwg.stdout()); PwgPgHdr hdr1, hdr2; ASSERT(pwg >>= "RaS2"); hdr1.decodeFrom(pwg); ASSERT(hdr1.CrossFeedTransform == 1); ASSERT(hdr1.FeedTransform == 1); - ASSERT(pwg >>= RightSideUp()); + ASSERT(pwg >>= RightSideUp()); hdr2.decodeFrom(pwg); ASSERT(hdr2.CrossFeedTransform == 1); ASSERT(hdr2.FeedTransform == 1); - ASSERT(pwg >>= RightSideUp()); + ASSERT(pwg >>= RightSideUp()); ASSERT(pwg.atEnd()); } @@ -315,13 +458,7 @@ TEST(bilevel) { Bytestream P4 = P4_0101(); - subprocess::popen ppm2pwg("../ppm2pwg", {"-", "-"}); - ppm2pwg.stdin() << P4; - ppm2pwg.close(); - - ASSERT(ppm2pwg.wait() == 0); - - Bytestream pwg(ppm2pwg.stdout()); + Bytestream pwg = run_ppm2pwg({}, P4, __func__); PwgPgHdr hdr1; ASSERT(pwg >>= "RaS2"); @@ -336,13 +473,8 @@ TEST(bilevel_vflip) Bytestream twoSided; twoSided << P4_0101() << P4_0101(); - subprocess::popen ppm2pwg("../ppm2pwg", {"-d", "--back-xform", "flip", "-", "-"}); - ppm2pwg.stdin() << twoSided; - ppm2pwg.close(); - - ASSERT(ppm2pwg.wait() == 0); + Bytestream pwg = run_ppm2pwg({"-d", "--back-xform", "flip"}, twoSided, __func__); - Bytestream pwg(ppm2pwg.stdout()); PwgPgHdr hdr1, hdr2; ASSERT(pwg >>= "RaS2"); @@ -362,13 +494,8 @@ TEST(bilevel_hflip) Bytestream twoSided; twoSided << P4_0101() << P4_0101(); - subprocess::popen ppm2pwg("../ppm2pwg", {"-d", "-t", "--back-xform", "flip", "-", "-"}); - ppm2pwg.stdin() << twoSided; - ppm2pwg.close(); - - ASSERT(ppm2pwg.wait() == 0); + Bytestream pwg = run_ppm2pwg({"-d", "-t", "--back-xform", "flip"}, twoSided, __func__); - Bytestream pwg(ppm2pwg.stdout()); PwgPgHdr hdr1, hdr2; ASSERT(pwg >>= "RaS2"); @@ -389,13 +516,8 @@ TEST(bilevel_rotated) Bytestream twoSided; twoSided << P4_0101() << P4_0101(); - subprocess::popen ppm2pwg("../ppm2pwg", {"-d", "--back-xform", "rotate", "-", "-"}); - ppm2pwg.stdin() << twoSided; - ppm2pwg.close(); + Bytestream pwg = run_ppm2pwg({"-d", "--back-xform", "rotate"}, twoSided, __func__); - ASSERT(ppm2pwg.wait() == 0); - - Bytestream pwg(ppm2pwg.stdout()); PwgPgHdr hdr1, hdr2; ASSERT(pwg >>= "RaS2"); @@ -420,17 +542,9 @@ bool close_enough(int a, int b, unsigned int precision) void do_test_centering(const char* test_name, std::string filename, bool asymmetric) { - subprocess::popen pdf2printable("../pdf2printable", - {"--format", "pwg", - "-rx", "300", - "-ry", asymmetric ? "600" : "300", - filename, test_name}); - pdf2printable.close(); - ASSERT(pdf2printable.wait() == 0); - - std::ifstream ifs(test_name, std::ios::in | std::ios::binary); - Bytestream pwg(ifs); + Bytestream pwg = run_pdf2printable({"--format", "pwg", "-rx", "300", "-ry", asymmetric ? "600" : "300"}, + filename, test_name); ASSERT(pwg.size() != 0); ASSERT(pwg >>= "RaS2"); @@ -1015,31 +1129,34 @@ TEST(color_mode) ASSERT(params.getNumberOfColors() == 3); ASSERT(params.getBitsPerColor() == 8); ASSERT(params.isBlack() == false); - params = PrintParameters(); params.colorMode = PrintParameters::CMYK32; ASSERT(params.getNumberOfColors() == 4); ASSERT(params.getBitsPerColor() == 8); ASSERT(params.isBlack() == false); - params = PrintParameters(); params.colorMode = PrintParameters::Gray8; ASSERT(params.getNumberOfColors() == 1); ASSERT(params.getBitsPerColor() == 8); ASSERT(params.isBlack() == false); - params = PrintParameters(); params.colorMode = PrintParameters::Black8; ASSERT(params.getNumberOfColors() == 1); ASSERT(params.getBitsPerColor() == 8); ASSERT(params.isBlack() == true); - params = PrintParameters(); params.colorMode = PrintParameters::Gray1; ASSERT(params.getNumberOfColors() == 1); ASSERT(params.getBitsPerColor() == 1); ASSERT(params.isBlack() == false); - params = PrintParameters(); params.colorMode = PrintParameters::Black1; ASSERT(params.getNumberOfColors() == 1); ASSERT(params.getBitsPerColor() == 1); ASSERT(params.isBlack() == true); + params.colorMode = PrintParameters::sRGB48; + ASSERT(params.getNumberOfColors() == 3); + ASSERT(params.getBitsPerColor() == 16); + ASSERT(params.isBlack() == false); + params.colorMode = PrintParameters::Gray16; + ASSERT(params.getNumberOfColors() == 1); + ASSERT(params.getBitsPerColor() == 16); + ASSERT(params.isBlack() == false); } TEST(argget) diff --git a/utils/ppm2pwg_main.cpp b/utils/ppm2pwg_main.cpp index 325b907..747fcd4 100644 --- a/utils/ppm2pwg_main.cpp +++ b/utils/ppm2pwg_main.cpp @@ -181,23 +181,52 @@ int main(int argc, char** argv) if(p == "P6") { inFile >> r; - params.colorMode = PrintParameters::sRGB24; + if(r == "255") + { + params.colorMode = PrintParameters::sRGB24; + } + else if(r == "65535") + { + params.colorMode = PrintParameters::sRGB48; + } + else + { + std::cerr << "Only 255 and 65535 bit-depths supported, got " << r << std::endl; + return 1; + } } else if(p == "P5") { inFile >> r; - params.colorMode = PrintParameters::Gray8; + if(r == "255") + { + params.colorMode = PrintParameters::Gray8; + } + else if(r == "65535") + { + params.colorMode = PrintParameters::Gray16; + } + else + { + std::cerr << "Only 255 and 65535 bit-depths supported, got " << r << std::endl; + return 1; + } } else if(p == "P4") { r = "1"; params.colorMode = PrintParameters::Black1; - size_t x = stoi(xs); + size_t x = stoul(xs); if(x % 8 != 0) { std::cerr << "Only whole-byte width P4 PBMs supported, got " << x << std::endl; return 1; } + if(params.format == PrintParameters::URF) + { + std::cerr << "URF does not support 1-bit (P4/pbm) color." << std::endl; + return 1; + } } else { @@ -210,8 +239,8 @@ int main(int argc, char** argv) DBG(<< "Found: " << p << " " << xs << "x" << ys << " " << r); - params.paperSizeW = stoi(xs); - params.paperSizeH = stoi(ys); + params.paperSizeW = stoul(xs); + params.paperSizeH = stoul(ys); size_t size = params.paperSizeH*params.getPaperSizeWInBytes(); bmpBts = Bytestream(inFile, size);