mirror of
https://github.com/pdewacht/brlaser
synced 2025-07-19 07:19:45 +02:00
brlaser version 1
This commit is contained in:
106
src/debug.cc
Normal file
106
src/debug.cc
Normal file
@ -0,0 +1,106 @@
|
||||
// This file is part of the brlaser printer driver.
|
||||
//
|
||||
// Copyright 2013 Peter De Wachter
|
||||
//
|
||||
// brlaser is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// brlaser is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with brlaser. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include "debug.h"
|
||||
#include <iostream>
|
||||
#include <typeinfo>
|
||||
|
||||
namespace {
|
||||
|
||||
template <typename T>
|
||||
void dump(const char *name, const T &value) {
|
||||
std::cerr << "DEBUG: page header: " << name << " = " << value << '\n';
|
||||
}
|
||||
|
||||
template <typename T, int N>
|
||||
void dump(const char *name, const T (&value)[N]) {
|
||||
std::cerr << "DEBUG: page header: " << name << " =";
|
||||
for (int i = 0; i < N; ++i) {
|
||||
std::cerr << ' ' << value[i];
|
||||
}
|
||||
std::cerr << '\n';
|
||||
}
|
||||
|
||||
void dump(const char *name, const char *value) {
|
||||
std::cerr << "DEBUG: page header: " << name << " = \"" << value << "\"\n";
|
||||
}
|
||||
|
||||
template <int N, int M>
|
||||
void dump(const char *name, const char (&value)[N][M]) {
|
||||
std::cerr << "DEBUG: page header: " << name << " =";
|
||||
for (int i = 0; i < N; ++i) {
|
||||
std::cerr << " \"" << value[i] << '"';
|
||||
}
|
||||
std::cerr << '\n';
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
|
||||
void dump_page_header(const cups_page_header2_t &h) {
|
||||
#define d(f) dump(#f, h.f)
|
||||
d(MediaClass);
|
||||
d(MediaColor);
|
||||
d(MediaType);
|
||||
d(OutputType);
|
||||
d(AdvanceDistance);
|
||||
d(AdvanceMedia);
|
||||
d(Collate);
|
||||
d(CutMedia);
|
||||
d(Duplex);
|
||||
d(HWResolution);
|
||||
d(ImagingBoundingBox);
|
||||
d(InsertSheet);
|
||||
d(Jog);
|
||||
d(LeadingEdge);
|
||||
d(Margins);
|
||||
d(ManualFeed);
|
||||
d(MediaPosition);
|
||||
d(MediaWeight);
|
||||
d(MirrorPrint);
|
||||
d(NegativePrint);
|
||||
d(NumCopies);
|
||||
d(Orientation);
|
||||
d(OutputFaceUp);
|
||||
d(PageSize);
|
||||
d(Separations);
|
||||
d(TraySwitch);
|
||||
d(Tumble);
|
||||
d(cupsWidth);
|
||||
d(cupsHeight);
|
||||
d(cupsMediaType);
|
||||
d(cupsBitsPerColor);
|
||||
d(cupsBitsPerPixel);
|
||||
d(cupsBytesPerLine);
|
||||
d(cupsColorOrder);
|
||||
d(cupsColorSpace);
|
||||
d(cupsCompression);
|
||||
d(cupsRowCount);
|
||||
d(cupsRowFeed);
|
||||
d(cupsRowStep);
|
||||
d(cupsNumColors);
|
||||
d(cupsBorderlessScalingFactor);
|
||||
d(cupsPageSize);
|
||||
d(cupsImagingBBox);
|
||||
d(cupsInteger);
|
||||
d(cupsReal);
|
||||
d(cupsString);
|
||||
d(cupsMarkerType);
|
||||
d(cupsRenderingIntent);
|
||||
d(cupsPageSizeName);
|
||||
#undef d
|
||||
}
|
25
src/debug.h
Normal file
25
src/debug.h
Normal file
@ -0,0 +1,25 @@
|
||||
// This file is part of the brlaser printer driver.
|
||||
//
|
||||
// Copyright 2013 Peter De Wachter
|
||||
//
|
||||
// brlaser is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// brlaser is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with brlaser. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#ifndef DEBUG_H
|
||||
#define DEBUG_H
|
||||
|
||||
#include <cups/raster.h>
|
||||
|
||||
void dump_page_header(const cups_page_header2_t &h);
|
||||
|
||||
#endif
|
152
src/job.cc
Normal file
152
src/job.cc
Normal file
@ -0,0 +1,152 @@
|
||||
// This file is part of the brlaser printer driver.
|
||||
//
|
||||
// Copyright 2013 Peter De Wachter
|
||||
//
|
||||
// brlaser is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// brlaser is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with brlaser. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include "job.h"
|
||||
#include <assert.h>
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
#include "line.h"
|
||||
|
||||
using std::vector;
|
||||
|
||||
namespace {
|
||||
|
||||
class block {
|
||||
public:
|
||||
void add_line(vector<uint8_t> &&line) {
|
||||
assert(!line.empty());
|
||||
line_bytes_ += line.size();
|
||||
lines_.push_back(line);
|
||||
}
|
||||
|
||||
bool line_fits(unsigned size) {
|
||||
return lines_.size() != max_lines_per_block_
|
||||
&& line_bytes_ + size < max_block_size_;
|
||||
}
|
||||
|
||||
void flush(FILE *f) {
|
||||
if (line_bytes_) {
|
||||
fprintf(f, "%dw%c%c",
|
||||
line_bytes_ + 2, 0,
|
||||
static_cast<int>(lines_.size()));
|
||||
for (auto &line : lines_) {
|
||||
fwrite(line.data(), 1, line.size(), f);
|
||||
}
|
||||
line_bytes_ = 0;
|
||||
lines_.clear();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
const unsigned max_block_size_ = 16350;
|
||||
const unsigned max_lines_per_block_ = 128;
|
||||
|
||||
vector<vector<uint8_t>> lines_;
|
||||
int line_bytes_ = 0;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
job::job(FILE *out, const std::string &job_name)
|
||||
: out_(out),
|
||||
job_name_(job_name),
|
||||
page_params_() {
|
||||
// Delete dubious characters from job name
|
||||
std::replace_if(job_name_.begin(), job_name_.end(), [](char c) {
|
||||
return c < 32 || c >= 127 || c == '"' || c == '\\';
|
||||
}, ' ');
|
||||
|
||||
begin_job();
|
||||
}
|
||||
|
||||
job::~job() {
|
||||
end_job();
|
||||
}
|
||||
|
||||
void job::begin_job() {
|
||||
for (int i = 0; i < 128; ++i) {
|
||||
putc(0, out_);
|
||||
}
|
||||
fprintf(out_, "\033%%-12345X@PJL\n");
|
||||
fprintf(out_, "@PJL JOB NAME=\"%s\"\n", job_name_.c_str());
|
||||
}
|
||||
|
||||
void job::end_job() {
|
||||
fprintf(out_, "\033%%-12345X@PJL\n");
|
||||
fprintf(out_, "@PJL EOJ NAME=\"%s\"\n", job_name_.c_str());
|
||||
fprintf(out_, "\033%%-12345X\n");
|
||||
}
|
||||
|
||||
void job::write_page_header() {
|
||||
fprintf(out_, "\033%%-12345X@PJL\n");
|
||||
if (page_params_.resolution != 1200) {
|
||||
fprintf(out_, "@PJL SET RAS1200MODE = FALSE\n");
|
||||
fprintf(out_, "@PJL SET RESOLUTION = %d\n", page_params_.resolution);
|
||||
} else {
|
||||
fprintf(out_, "@PJL SET RAS1200MODE = TRUE\n");
|
||||
fprintf(out_, "@PJL SET RESOLUTION = 600\n");
|
||||
}
|
||||
fprintf(out_, "@PJL SET ECONOMODE = %s\n",
|
||||
page_params_.economode ? "ON" : "OFF");
|
||||
fprintf(out_, "@PJL SET SOURCETRAY = %s\n",
|
||||
page_params_.sourcetray.c_str());
|
||||
fprintf(out_, "@PJL SET MEDIATYPE = %s\n",
|
||||
page_params_.mediatype.c_str());
|
||||
fprintf(out_, "@PJL SET PAPER = %s\n",
|
||||
page_params_.papersize.c_str());
|
||||
fprintf(out_, "@PJL SET PAGEPROTECT = AUTO\n");
|
||||
fprintf(out_, "@PJL SET ORIENTATION = PORTRAIT\n");
|
||||
fprintf(out_, "@PJL ENTER LANGUAGE = PCL\n");
|
||||
}
|
||||
|
||||
void job::encode_page(const page_params &page_params,
|
||||
int num_copies,
|
||||
int lines,
|
||||
int linesize,
|
||||
nextline_fn nextline) {
|
||||
if (!(page_params_ == page_params)) {
|
||||
page_params_ = page_params;
|
||||
write_page_header();
|
||||
}
|
||||
|
||||
vector<uint8_t> line(linesize);
|
||||
vector<uint8_t> reference(linesize);
|
||||
block block;
|
||||
|
||||
if (!nextline(line.data())) {
|
||||
return;
|
||||
}
|
||||
block.add_line(encode_line(line));
|
||||
std::swap(line, reference);
|
||||
|
||||
fputs("\033E", out_);
|
||||
fprintf(out_, "\033&l%dX", std::max(1, num_copies));
|
||||
fputs("\033*b1030m", out_);
|
||||
|
||||
for (int i = 1; i < lines && nextline(line.data()); ++i) {
|
||||
vector<uint8_t> encoded = encode_line(line, reference);
|
||||
if (!block.line_fits(encoded.size())) {
|
||||
block.flush(out_);
|
||||
}
|
||||
block.add_line(std::move(encoded));
|
||||
std::swap(line, reference);
|
||||
}
|
||||
|
||||
block.flush(out_);
|
||||
fputs("1030M\f", out_);
|
||||
fflush(out_);
|
||||
}
|
64
src/job.h
Normal file
64
src/job.h
Normal file
@ -0,0 +1,64 @@
|
||||
// This file is part of the brlaser printer driver.
|
||||
//
|
||||
// Copyright 2013 Peter De Wachter
|
||||
//
|
||||
// brlaser is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// brlaser is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with brlaser. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#ifndef JOB_H
|
||||
#define JOB_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string>
|
||||
|
||||
struct page_params {
|
||||
int resolution;
|
||||
bool economode;
|
||||
std::string sourcetray;
|
||||
std::string mediatype;
|
||||
std::string papersize;
|
||||
|
||||
bool operator==(const page_params &o) const {
|
||||
return resolution == o.resolution
|
||||
&& economode == o.economode
|
||||
&& sourcetray == o.sourcetray
|
||||
&& mediatype == o.mediatype
|
||||
&& papersize == o.papersize;
|
||||
}
|
||||
};
|
||||
|
||||
class job {
|
||||
public:
|
||||
typedef bool (*nextline_fn)(uint8_t *buf);
|
||||
|
||||
explicit job(FILE *out, const std::string &job_name);
|
||||
~job();
|
||||
|
||||
void encode_page(const page_params ¶ms,
|
||||
int num_copies,
|
||||
int lines,
|
||||
int linesize,
|
||||
nextline_fn nextline);
|
||||
|
||||
private:
|
||||
void begin_job();
|
||||
void end_job();
|
||||
void write_page_header();
|
||||
|
||||
FILE *out_;
|
||||
std::string job_name_;
|
||||
page_params page_params_;
|
||||
};
|
||||
|
||||
#endif // JOB_H
|
191
src/line.cc
Normal file
191
src/line.cc
Normal file
@ -0,0 +1,191 @@
|
||||
// This file is part of the brlaser printer driver.
|
||||
//
|
||||
// Copyright 2013 Peter De Wachter
|
||||
//
|
||||
// brlaser is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// brlaser is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with brlaser. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include "line.h"
|
||||
#include <assert.h>
|
||||
#include <algorithm>
|
||||
using std::vector;
|
||||
|
||||
namespace {
|
||||
|
||||
void write_overflow(int value, vector<uint8_t> *out) {
|
||||
if (value >= 0) {
|
||||
if (value < 255) {
|
||||
out->push_back(value);
|
||||
} else {
|
||||
out->insert(out->end(), value / 255, 255);
|
||||
out->push_back(value % 255);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Iterator>
|
||||
void write_substitute(int offset,
|
||||
Iterator first,
|
||||
Iterator last,
|
||||
vector<uint8_t> *out) {
|
||||
assert(offset >= 0);
|
||||
assert(offset < 10000);
|
||||
assert(first != last);
|
||||
|
||||
const int offset_max = 15;
|
||||
const int count_max = 7;
|
||||
int count = std::distance(first, last) - 1;
|
||||
|
||||
int offset_low = std::min(offset, offset_max);
|
||||
int count_low = std::min(count, count_max);
|
||||
out->push_back((offset_low << 3) | count_low);
|
||||
write_overflow(offset - offset_max, out);
|
||||
write_overflow(count - count_max, out);
|
||||
out->insert(out->end(), first, last);
|
||||
}
|
||||
|
||||
void write_repeat(int offset, int count, int value, vector<uint8_t> *out) {
|
||||
assert(offset >= 0);
|
||||
assert(offset < 10000);
|
||||
assert(count >= 2);
|
||||
assert(count < 10000);
|
||||
|
||||
const int offset_max = 3;
|
||||
const int count_max = 31;
|
||||
count -= 2;
|
||||
|
||||
int offset_low = std::min(offset, offset_max);
|
||||
int count_low = std::min(count, count_max);
|
||||
out->push_back(128 | (offset_low << 5) | count_low);
|
||||
write_overflow(offset - offset_max, out);
|
||||
write_overflow(count - count_max, out);
|
||||
out->push_back(value);
|
||||
}
|
||||
|
||||
|
||||
bool all_zeros(const vector<uint8_t> &buf) {
|
||||
return std::none_of(buf.begin(), buf.end(), [](uint8_t b) { return b; });
|
||||
}
|
||||
|
||||
template <typename Iterator1, typename Iterator2>
|
||||
int skip_to_next_mismatch(Iterator1 *first1,
|
||||
Iterator1 last1,
|
||||
Iterator2 *first2) {
|
||||
auto mismatch_it = std::mismatch(*first1, last1, *first2);
|
||||
int skipped = std::distance(*first1, mismatch_it.first);
|
||||
*first1 = mismatch_it.first;
|
||||
*first2 = mismatch_it.second;
|
||||
return skipped;
|
||||
}
|
||||
|
||||
template <typename Iterator>
|
||||
int repeat_length(Iterator first, Iterator last) {
|
||||
if (first != last) {
|
||||
auto k = *first;
|
||||
auto mismatch = std::find_if(std::next(first), last,
|
||||
[=](decltype(k) x) { return x != k; });
|
||||
return std::distance(first, mismatch);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <typename Iterator1, typename Iterator2>
|
||||
int substitute_length(Iterator1 first1, Iterator1 last1, Iterator2 first2) {
|
||||
if (first1 != last1) {
|
||||
Iterator1 it1 = first1;
|
||||
Iterator2 it2 = first2;
|
||||
Iterator1 next1 = std::next(first1);
|
||||
Iterator2 next2 = std::next(first2);
|
||||
Iterator1 prev1 = first1;
|
||||
while (next1 != last1) {
|
||||
if ((*it1 == *it2 && *next1 == *next2)) {
|
||||
return std::distance(first1, it1);
|
||||
}
|
||||
if (*it1 == *next1 && *it1 == *prev1) {
|
||||
return std::distance(first1, prev1);
|
||||
}
|
||||
prev1 = it1;
|
||||
it1 = next1; it2 = next2;
|
||||
++next1; ++next2;
|
||||
}
|
||||
}
|
||||
return std::distance(first1, last1);
|
||||
}
|
||||
|
||||
size_t reserve_size(const vector<uint8_t> &line) {
|
||||
// Big enough to store the line uncompressed together with an Substitute
|
||||
// command with many overflow bytes.
|
||||
return line.size() + 16;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
vector<uint8_t> encode_line(const vector<uint8_t> &line,
|
||||
const vector<uint8_t> &reference) {
|
||||
assert(line.size() == reference.size());
|
||||
if (all_zeros(line)) {
|
||||
return vector<uint8_t>(1, 0xFF);
|
||||
}
|
||||
|
||||
vector<uint8_t> output;
|
||||
output.reserve(reserve_size(line));
|
||||
output.push_back(0); // first byte is the edit count
|
||||
|
||||
const uint8_t max_edits = 254;
|
||||
int num_edits = 0;
|
||||
|
||||
auto line_it = line.begin();
|
||||
auto ref_it = reference.begin();
|
||||
while (1) {
|
||||
int offset = skip_to_next_mismatch(&line_it, line.end(), &ref_it);
|
||||
if (line_it == line.end()) {
|
||||
// No more differences, we're done.
|
||||
break;
|
||||
}
|
||||
|
||||
if (++num_edits == max_edits) {
|
||||
// We've run out of edits. Just output the rest of the line in a big
|
||||
// substitute command.
|
||||
write_substitute(offset, line_it, line.end(), &output);
|
||||
break;
|
||||
}
|
||||
|
||||
int s = substitute_length(line_it, line.end(), ref_it);
|
||||
if (s > 0) {
|
||||
write_substitute(offset, line_it, std::next(line_it, s), &output);
|
||||
line_it += s;
|
||||
ref_it += s;
|
||||
} else {
|
||||
int r = repeat_length(line_it, line.end());
|
||||
assert(r >= 2);
|
||||
write_repeat(offset, r, *line_it, &output);
|
||||
line_it += r;
|
||||
ref_it += r;
|
||||
}
|
||||
}
|
||||
|
||||
assert(num_edits <= max_edits);
|
||||
output[0] = num_edits;
|
||||
return output;
|
||||
}
|
||||
|
||||
vector<uint8_t> encode_line(const vector<uint8_t> &line) {
|
||||
if (all_zeros(line)) {
|
||||
return vector<uint8_t>(1, 0xFF);
|
||||
}
|
||||
vector<uint8_t> buf;
|
||||
buf.reserve(reserve_size(line));
|
||||
buf.push_back(1);
|
||||
write_substitute(0, line.begin(), line.end(), &buf);
|
||||
return buf;
|
||||
}
|
31
src/line.h
Normal file
31
src/line.h
Normal file
@ -0,0 +1,31 @@
|
||||
// This file is part of the brlaser printer driver.
|
||||
//
|
||||
// Copyright 2013 Peter De Wachter
|
||||
//
|
||||
// brlaser is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// brlaser is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with brlaser. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#ifndef LINE_H
|
||||
#define LINE_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <vector>
|
||||
|
||||
std::vector<uint8_t> encode_line(
|
||||
const std::vector<uint8_t> &line,
|
||||
const std::vector<uint8_t> &reference);
|
||||
|
||||
std::vector<uint8_t> encode_line(
|
||||
const std::vector<uint8_t> &line);
|
||||
|
||||
#endif // LINE_H
|
194
src/main.cc
Normal file
194
src/main.cc
Normal file
@ -0,0 +1,194 @@
|
||||
// This file is part of the brlaser printer driver.
|
||||
//
|
||||
// Copyright 2013 Peter De Wachter
|
||||
//
|
||||
// brlaser is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// brlaser is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with brlaser. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include <stdio.h>
|
||||
#include <signal.h>
|
||||
#include <locale.h>
|
||||
#include <iconv.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <cups/raster.h>
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <array>
|
||||
#include <map>
|
||||
#include "config.h"
|
||||
#include "job.h"
|
||||
#include "debug.h"
|
||||
|
||||
namespace {
|
||||
|
||||
volatile sig_atomic_t interrupted = 0;
|
||||
|
||||
void sigterm_handler(int sig) {
|
||||
interrupted = 1;
|
||||
}
|
||||
|
||||
|
||||
cups_raster_t *ras;
|
||||
cups_page_header2_t header;
|
||||
|
||||
bool next_line(uint8_t *buf) {
|
||||
if (interrupted) {
|
||||
return false;
|
||||
}
|
||||
unsigned bytes = header.cupsBytesPerLine;
|
||||
return cupsRasterReadPixels(ras, buf, bytes) == bytes;
|
||||
}
|
||||
|
||||
// POSIX says the second argument of iconv has type 'char **', but
|
||||
// some systems have 'const char **'. This class is used to work
|
||||
// around this incompatibility.
|
||||
class sloppy_ptr {
|
||||
public:
|
||||
explicit sloppy_ptr(const char **ptr): ptr_(ptr) { }
|
||||
operator const char **() { return ptr_; }
|
||||
operator char **() { return const_cast<char **>(ptr_); }
|
||||
private:
|
||||
const char **ptr_;
|
||||
};
|
||||
|
||||
std::string ascii_job_name(const char *job_name, const char *charset) {
|
||||
if (job_name && charset) {
|
||||
iconv_t cd = iconv_open("ASCII//TRANSLIT//IGNORE", charset);
|
||||
if (cd != (iconv_t) -1) {
|
||||
char ascii[80];
|
||||
const char *in_ptr = job_name;
|
||||
size_t in_left = strlen(job_name);
|
||||
char *out_ptr = ascii;
|
||||
size_t out_left = sizeof(ascii) - 1;
|
||||
while (in_left > 0) {
|
||||
size_t err = iconv(cd,
|
||||
sloppy_ptr(&in_ptr), &in_left,
|
||||
&out_ptr, &out_left);
|
||||
if (err == (size_t) -1) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
*out_ptr = 0;
|
||||
iconv_close(cd);
|
||||
return ascii;
|
||||
}
|
||||
}
|
||||
return "CUPS";
|
||||
}
|
||||
|
||||
page_params build_page_params() {
|
||||
static const std::array<std::string, 6> sources = {
|
||||
"AUTO", "T1", "T2", "T3", "MP", "MANUAL"
|
||||
};
|
||||
static const std::map<std::string, std::string> sizes = {
|
||||
{ "A4", "A4" },
|
||||
{ "A5", "A5" },
|
||||
{ "A6", "A6" },
|
||||
{ "B5", "B5" },
|
||||
{ "B6", "B6" },
|
||||
{ "EnvC5", "C5" },
|
||||
{ "EnvMonarch", "MONARCH" },
|
||||
{ "EnvPRC5", "DL" },
|
||||
{ "Executive", "EXECUTIVE" },
|
||||
{ "Legal", "LEGAL" },
|
||||
{ "Letter", "LETTER" }
|
||||
};
|
||||
|
||||
page_params p = { };
|
||||
p.resolution = header.HWResolution[0];
|
||||
p.economode = header.cupsInteger[10];
|
||||
p.mediatype = header.MediaType;
|
||||
|
||||
if (header.MediaPosition < sources.size())
|
||||
p.sourcetray = sources[header.MediaPosition];
|
||||
else
|
||||
p.sourcetray = sources[0];
|
||||
|
||||
auto size_it = sizes.find(header.cupsPageSizeName);
|
||||
if (size_it != sizes.end())
|
||||
p.papersize = size_it->second;
|
||||
else
|
||||
p.papersize = "A4";
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
fprintf(stderr, "INFO: %s version %s\n", PACKAGE, VERSION);
|
||||
|
||||
if (argc != 6 && argc != 7) {
|
||||
fprintf(stderr, "ERROR: %s job-id user title copies options [file]\n", argv[0]);
|
||||
fprintf(stderr, "INFO: This program is a CUPS filter. It is not intended to be run manually.\n");
|
||||
return 1;
|
||||
}
|
||||
// const char *job_id = argv[1];
|
||||
// const char *job_user = argv[2];
|
||||
const char *job_name = argv[3];
|
||||
// const int job_copies = atoi(argv[4]);
|
||||
// const char *job_options = argv[5];
|
||||
const char *job_filename = argv[6];
|
||||
const char *job_charset = getenv("CHARSET");
|
||||
|
||||
setlocale(LC_ALL, "");
|
||||
|
||||
signal(SIGTERM, sigterm_handler);
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
|
||||
int fd = 0;
|
||||
if (job_filename) {
|
||||
fd = open(job_filename, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
fprintf(stderr, "ERROR: Unable to open raster file\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
ras = cupsRasterOpen(fd, CUPS_RASTER_READ);
|
||||
if (!ras) {
|
||||
fprintf(stderr, "ERROR: Can't read raster data\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
int pages = 0;
|
||||
{
|
||||
job job(stdout, ascii_job_name(job_name, job_charset));
|
||||
while (!interrupted && cupsRasterReadHeader2(ras, &header)) {
|
||||
if (pages == 0) {
|
||||
dump_page_header(header);
|
||||
}
|
||||
job.encode_page(build_page_params(),
|
||||
header.NumCopies,
|
||||
header.cupsHeight,
|
||||
header.cupsBytesPerLine,
|
||||
next_line);
|
||||
fprintf(stderr, "PAGE: %d %d\n", ++pages, header.NumCopies);
|
||||
}
|
||||
}
|
||||
if (pages == 0) {
|
||||
fprintf(stderr, "ERROR: No pages were found.");
|
||||
return 1;
|
||||
}
|
||||
|
||||
fflush(stdout);
|
||||
if (ferror(stdout)) {
|
||||
fprintf(stderr, "ERROR: Could not write print data\n");
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
Reference in New Issue
Block a user