Skip to content

Commit cb7de07

Browse files
committed
Add 16-bit support, and related clean-ups
1 parent 23b3f05 commit cb7de07

10 files changed

+320
-150
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
.vscode
22
*.o
3+
*.plist
34
tests/test
45
tests/*.o
56
tests/_test_pdf2printable_16x9_*

README.md

+2-4
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,7 @@
88
Available as rudimentary standalone applications, but mainly made for use in [SeaPrint](https://github.com/attah/harbour-seaprint).
99

1010
## ppm2pwg
11-
Takes a pbm, pgm or ppm (P4, P5 or P6 "raw") Netpbm bitmap image and converts to PWG or URF printer raster format.
12-
13-
...or a raw bitmap in the c++ api.
11+
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.
1412

1513
## pwg2ppm
1614
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:
2422

2523
## baselinify
2624
Takes a JPEG and losslessly repacks it to the baseline ecoding profile, keeping only JFIF and Exif headers.
27-
Sort of like jpegtran without any arguments, but reusable in C++.
25+
Sort of like jpegtran without any arguments.
2826

2927
IPP-printers are only required to support baseline-encoded jpeg according to PWG5100.14.
3028

lib/pdf2printable.cpp

+4
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,10 @@ void copy_raster_buffer(Bytestream& bmpBts, uint32_t* data, const PrintParameter
300300
}
301301
break;
302302
}
303+
default:
304+
{
305+
throw std::logic_error("Unhandled color mode");
306+
}
303307
}
304308
}
305309

lib/ppm2pwg.cpp

+47-29
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,12 @@
1010
#include <map>
1111
#include <string.h>
1212

13+
void make_pwg_hdr(Bytestream& outBts, const PrintParameters& params, bool backside);
14+
void make_urf_hdr(Bytestream& outBts, const PrintParameters& params);
15+
16+
void compress_lines(Bytestream& bmpBts, Bytestream& outBts, const PrintParameters& params, bool backside);
17+
void compress_line(uint8_t* raw, size_t len, Bytestream& outBts, size_t oneChunk);
18+
1319
Bytestream make_pwg_file_hdr()
1420
{
1521
Bytestream pwgFileHdr;
@@ -42,21 +48,27 @@ void bmp_to_pwg(Bytestream& bmpBts, Bytestream& outBts, size_t page, const Print
4248
size_t yRes = params.getPaperSizeHInPixels();
4349
uint8_t* raw = bmpBts.raw();
4450
size_t bytesPerLine = params.getPaperSizeWInBytes();
45-
int step = backside&&params.getBackVFlip() ? -bytesPerLine : bytesPerLine;
46-
uint8_t* row0 = backside&&params.getBackVFlip() ? raw+(yRes-1)*bytesPerLine : raw;
51+
int oneLine = backside && params.getBackVFlip() ? -bytesPerLine : bytesPerLine;
52+
uint8_t* row0 = backside && params.getBackVFlip() ? raw + (yRes - 1) * bytesPerLine : raw;
4753
Array<uint8_t> tmpLine(bytesPerLine);
4854

49-
for(size_t y=0; y<yRes; y++)
55+
size_t colors = params.getNumberOfColors();
56+
size_t bpc = params.getBitsPerColor();
57+
// A chunk is the unit used for compression.
58+
// Usually this is the number of bytes per color times the number of colors,
59+
// but for 1-bit, compression is applied in whole bytes.
60+
size_t oneChunk = bpc == 1 ? colors : colors * bpc / 8;
61+
62+
for(size_t y = 0; y < yRes; y++)
5063
{
51-
uint8_t* thisLine = row0+y*step;
64+
uint8_t* thisLine = row0 + y * oneLine;
5265
uint8_t lineRepeat = 0;
53-
size_t colors = params.getNumberOfColors();
5466

55-
uint8_t* next_line = thisLine + step;
67+
uint8_t* next_line = thisLine + oneLine;
5668
while((y+1)<yRes && memcmp(thisLine, next_line, bytesPerLine) == 0)
5769
{
5870
y++;
59-
next_line += step;
71+
next_line += oneLine;
6072
lineRepeat++;
6173
if(lineRepeat == 255)
6274
{
@@ -68,7 +80,7 @@ void bmp_to_pwg(Bytestream& bmpBts, Bytestream& outBts, size_t page, const Print
6880
if(backside && params.getBackHFlip())
6981
{
7082
// Flip line into tmp buffer
71-
if(params.getBitsPerColor() == 1)
83+
if(bpc == 1)
7284
{
7385
for(size_t i = 0; i < bytesPerLine; i++)
7486
{
@@ -78,46 +90,48 @@ void bmp_to_pwg(Bytestream& bmpBts, Bytestream& outBts, size_t page, const Print
7890
}
7991
else
8092
{
81-
for(size_t i = 0; i < bytesPerLine; i += colors)
93+
uint8_t* lastChunk = thisLine + bytesPerLine - oneChunk;
94+
for(size_t i = 0; i < bytesPerLine; i += oneChunk)
8295
{
83-
memcpy(tmpLine+i, thisLine+bytesPerLine-colors-i, colors);
96+
memcpy(tmpLine+i, lastChunk-i, oneChunk);
8497
}
8598
}
86-
compress_line(tmpLine, bytesPerLine, outBts, colors);
99+
compress_line(tmpLine, bytesPerLine, outBts, oneChunk);
87100
}
88101
else
89102
{
90-
compress_line(thisLine, bytesPerLine, outBts, colors);
103+
compress_line(thisLine, bytesPerLine, outBts, oneChunk);
91104
}
92105
}
93106
}
94107

95-
void compress_line(uint8_t* raw, size_t len, Bytestream& outBts, int colors)
108+
void compress_line(uint8_t* raw, size_t len, Bytestream& outBts, size_t oneChunk)
96109
{
97110
uint8_t* current;
98111
uint8_t* pos = raw;
99-
uint8_t* epos = raw+len;
112+
uint8_t* epos = raw + len;
113+
100114
while(pos != epos)
101115
{
102116
uint8_t* currentStart = pos;
103117
current = pos;
104-
pos += colors;
118+
pos += oneChunk;
105119

106-
if(pos == epos || memcmp(pos, current, colors) == 0)
120+
if(pos == epos || memcmp(pos, current, oneChunk) == 0)
107121
{
108122
int8_t repeat = 0;
109123
// Find number of repititions
110-
while(pos != epos && memcmp(pos, current, colors) == 0)
124+
while(pos != epos && memcmp(pos, current, oneChunk) == 0)
111125
{
112-
pos += colors;
126+
pos += oneChunk;
113127
repeat++;
114128
if(repeat == 127)
115129
{
116130
break;
117131
}
118132
}
119133
outBts << repeat;
120-
outBts.putBytes(current, colors);
134+
outBts.putBytes(current, oneChunk);
121135
}
122136
else
123137
{
@@ -127,14 +141,14 @@ void compress_line(uint8_t* raw, size_t len, Bytestream& outBts, int colors)
127141
do
128142
{
129143
current = pos;
130-
pos += colors;
144+
pos += oneChunk;
131145
verbatim++;
132146
if(verbatim == 127)
133147
{
134148
break;
135149
}
136150
}
137-
while(pos != epos && memcmp(pos, current, colors) != 0);
151+
while(pos != epos && memcmp(pos, current, oneChunk) != 0);
138152

139153
// This and the next sequence are equal,
140154
// assume it starts a repeating sequence.
@@ -148,15 +162,15 @@ void compress_line(uint8_t* raw, size_t len, Bytestream& outBts, int colors)
148162
// But in order to not lean on that (uint8_t)(256)==0, we have this.
149163
if(verbatim == 1)
150164
{ // We ended up with one sequence, encode it as such
151-
pos = currentStart + colors;
165+
pos = currentStart + oneChunk;
152166
outBts << (uint8_t)0;
153-
outBts.putBytes(currentStart, colors);
167+
outBts.putBytes(currentStart, oneChunk);
154168
}
155169
else
156170
{ // 2 or more non-repeating sequnces
157-
pos = currentStart + verbatim*colors;
158-
outBts << (uint8_t)(257-verbatim);
159-
outBts.putBytes(currentStart, verbatim*colors);
171+
pos = currentStart + verbatim * oneChunk;
172+
outBts << (uint8_t)(257 - verbatim);
173+
outBts.putBytes(currentStart, verbatim * oneChunk);
160174
}
161175
}
162176
}
@@ -193,7 +207,9 @@ void make_pwg_hdr(Bytestream& outBts, const PrintParameters& params, bool backsi
193207
{PrintParameters::Gray8, PwgPgHdr::sGray},
194208
{PrintParameters::Black8, PwgPgHdr::Black},
195209
{PrintParameters::Gray1, PwgPgHdr::sGray},
196-
{PrintParameters::Black1, PwgPgHdr::Black}};
210+
{PrintParameters::Black1, PwgPgHdr::Black},
211+
{PrintParameters::sRGB48, PwgPgHdr::sRGB},
212+
{PrintParameters::Gray16, PwgPgHdr::sGray}};
197213

198214
outHdr.MediaType = params.mediaType;
199215
outHdr.Duplex = params.isTwoSided();
@@ -235,14 +251,16 @@ void make_urf_hdr(Bytestream& outBts, const PrintParameters& params)
235251
static const std::map<PrintParameters::ColorMode, UrfPgHdr::ColorSpace_enum>
236252
urfColorSpaceMappings {{PrintParameters::sRGB24, UrfPgHdr::sRGB},
237253
{PrintParameters::CMYK32, UrfPgHdr::CMYK},
238-
{PrintParameters::Gray8, UrfPgHdr::sGray}};
254+
{PrintParameters::Gray8, UrfPgHdr::sGray},
255+
{PrintParameters::sRGB48, UrfPgHdr::sRGB},
256+
{PrintParameters::Gray16, UrfPgHdr::sGray}};
239257

240258
static const std::map<PrintParameters::DuplexMode, UrfPgHdr::Duplex_enum>
241259
urfDuplexMappings {{PrintParameters::OneSided, UrfPgHdr::OneSided},
242260
{PrintParameters::TwoSidedLongEdge, UrfPgHdr::TwoSidedLongEdge},
243261
{PrintParameters::TwoSidedShortEdge, UrfPgHdr::TwoSidedShortEdge}};
244262

245-
outHdr.BitsPerPixel = 8*params.getNumberOfColors();
263+
outHdr.BitsPerPixel = params.getNumberOfColors() * params.getBitsPerColor();
246264
outHdr.ColorSpace = urfColorSpaceMappings.at(params.colorMode);
247265
outHdr.Duplex = urfDuplexMappings.at(params.duplexMode);
248266
outHdr.setQuality(params.quality);

lib/ppm2pwg.h

+1-11
Original file line numberDiff line numberDiff line change
@@ -10,17 +10,7 @@ Bytestream make_pwg_file_hdr();
1010

1111
Bytestream make_urf_file_hdr(uint32_t pages);
1212

13-
void make_pwg_hdr(Bytestream& outBts, const PrintParameters& params, bool backside);
14-
void make_urf_hdr(Bytestream& outBts, const PrintParameters& params);
15-
16-
17-
void bmp_to_pwg(Bytestream& bmpBts, Bytestream& outBts, size_t page,
18-
const PrintParameters& params);
19-
20-
void compress_lines(Bytestream& bmpBts, Bytestream& outBts,
21-
const PrintParameters& params, bool backside);
22-
23-
void compress_line(uint8_t* raw, size_t len, Bytestream& outBts, int Colors);
13+
void bmp_to_pwg(Bytestream& bmpBts, Bytestream& outBts, size_t page, const PrintParameters& params);
2414

2515
bool isUrfMediaType(std::string mediaType);
2616

lib/printparameters.cpp

+14-3
Original file line numberDiff line numberDiff line change
@@ -110,14 +110,18 @@ double PrintParameters::getPaperSizeHInPoints() const
110110

111111
size_t PrintParameters::getPaperSizeWInBytes() const
112112
{
113-
if(getBitsPerColor() == 1)
113+
if(getBitsPerColor() == 1 && getNumberOfColors() == 1)
114114
{
115115
// Round up to whole bytes
116-
return getNumberOfColors() * ((getPaperSizeWInPixels() + 7) / 8);
116+
return (getPaperSizeWInPixels() + 7) / 8;
117+
}
118+
else if(getBitsPerColor() % 8 == 0)
119+
{
120+
return getPaperSizeWInPixels() * getNumberOfColors() * (getBitsPerColor() / 8);
117121
}
118122
else
119123
{
120-
return getNumberOfColors() * (getPaperSizeWInPixels() / (8 / getBitsPerColor()));
124+
throw(std::logic_error("Unhandled color and bit depth combination"));
121125
}
122126
}
123127

@@ -272,6 +276,8 @@ bool PrintParameters::isBlack() const
272276
case CMYK32:
273277
case Gray8:
274278
case Gray1:
279+
case sRGB48:
280+
case Gray16:
275281
return false;
276282
case Black8:
277283
case Black1:
@@ -286,13 +292,15 @@ size_t PrintParameters::getNumberOfColors() const
286292
switch(colorMode)
287293
{
288294
case sRGB24:
295+
case sRGB48:
289296
return 3;
290297
case CMYK32:
291298
return 4;
292299
case Gray8:
293300
case Black8:
294301
case Gray1:
295302
case Black1:
303+
case Gray16:
296304
return 1;
297305
default:
298306
throw(std::logic_error("Unknown color mode"));
@@ -311,6 +319,9 @@ size_t PrintParameters::getBitsPerColor() const
311319
case Gray1:
312320
case Black1:
313321
return 1;
322+
case sRGB48:
323+
case Gray16:
324+
return 16;
314325
default:
315326
throw(std::logic_error("Unknown color mode"));
316327
}

lib/printparameters.h

+3-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,9 @@ class PrintParameters
3232
Gray8,
3333
Black8,
3434
Gray1,
35-
Black1
35+
Black1,
36+
sRGB48,
37+
Gray16
3638
};
3739

3840
enum Quality

tests/Makefile

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
LDFLAGS = -ldl -Wl,--export-dynamic -lcurl -ljpeg $(shell pkg-config --libs poppler-glib) -lz
22
CXXFLAGS = -std=c++17 -g -pedantic -Wall -Werror -Wextra -I ../lib -I ../json11 -I ../bytestream \
33
$(shell pkg-config --cflags poppler-glib)
4-
TEST_INCLUDES = -I ../lib -I ../bytestream/minitest -I ../bytestream/minitest/tests
4+
TEST_INCLUDES = -I ../lib -I ../bytestream/minitest
55

66
VPATH = ../bytestream ../lib ../json11
77

0 commit comments

Comments
 (0)