Skip to content

Commit

Permalink
Add an IPP client
Browse files Browse the repository at this point in the history
  • Loading branch information
attah committed Oct 2, 2023
1 parent d939fa4 commit 39158f8
Show file tree
Hide file tree
Showing 23 changed files with 2,736 additions and 59 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ pdf2printable_mad
hexdump
baselinify
baselinify_mad
ippposter
6 changes: 3 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ $(shell pkg-config --cflags poppler-glib)

VPATH = bytestream lib utils

all: ppm2pwg pwg2ppm pdf2printable hexdump baselinify
all: ppm2pwg pwg2ppm pdf2printable hexdump baselinify ippposter


pdf2printable_mad.o: pdf2printable.cpp
Expand Down Expand Up @@ -36,8 +36,8 @@ baselinify: bytestream.o baselinify.o baselinify_main.o
baselinify_mad: bytestream.o baselinify_mad.o baselinify_main.o
$(CXX) $^ -ldl -o $@

ippposter: ippposter.o curlrequester.o bytestream.o
$(CXX) $^ -lcurl -o $@
ippposter: ippmsg.o ippattr.o ippprintjob.o printparameters.o ippposter.o curlrequester.o pdf2printable.o ppm2pwg.o baselinify.o bytestream.o
$(CXX) $^ $(shell pkg-config --libs poppler-glib) -ljpeg -lcurl -o $@

clean:
rm -f *.o ppm2pwg pwg2ppm pdf2printable pdf2printable_mad hexdump baselinify baselinify_mad
Expand Down
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,14 @@ IPP-printers are only required to support baseline-encoded jpeg according to PWG

Despite working with in-memory data, it only requires the libjpeg 62.2.0 and not 62.3.0/7.3+ API, so it works on conservative distros.

## ippposter (WIP)
An IPP client that harnesses the above tools for converting files to be printed.

## Building

Install dependencies:

`sudo apt install libpoppler-dev libpoppler-glib-dev libcairo2-dev libglib2.0-dev libjpeg-dev`
`sudo apt install libpoppler-dev libpoppler-glib-dev libcairo2-dev libglib2.0-dev libjpeg-dev libcurl4-openssl-dev`

Build:

Expand Down
5 changes: 1 addition & 4 deletions lib/curlrequester.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
#include "curlrequester.h"
#include <cstring>
#include <iostream>
#include <chrono>
#include <thread>

Expand Down Expand Up @@ -43,8 +42,6 @@ void CurlRequester::doRun()
curl_easy_setopt(_curl, CURLOPT_WRITEFUNCTION, write_callback);

CURLcode res = curl_easy_perform(_curl);
if(res != CURLE_OK)
std::cerr << "curl_easy_perform() failed: " << curl_easy_strerror(res);

_result = res;
_resultMsg = buf;
Expand Down Expand Up @@ -126,7 +123,7 @@ size_t CurlIppPosterBase::requestWrite(char* dest, size_t size)
}

CurlIppPosterBase::CurlIppPosterBase(std::string addr, bool ignoreSslErrors, bool verbose)
: CurlRequester(addr, ignoreSslErrors, verbose)
: CurlRequester("http"+addr.erase(0,3), ignoreSslErrors, verbose)
{
_canWrite.unlock();
_canRead.lock();
Expand Down
8 changes: 8 additions & 0 deletions lib/error.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#ifndef ERROR_H
#define ERROR_H

#include <optional>

typedef std::optional<std::string> Error;

#endif // ERROR_H
9 changes: 9 additions & 0 deletions lib/functions.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#ifndef FUNCTIONS_H
#define FUNCTIONS_H

#include <functional>

typedef std::function<bool(unsigned char const*, unsigned int)> WriteFun;
typedef std::function<void(size_t page, size_t total)> ProgressFun;

#endif // FUNCTIONS_H
132 changes: 132 additions & 0 deletions lib/ippattr.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
#include "ippattr.h"
#include <iomanip>

bool IppAttr::isList() const
{
return is<IppOneSetOf>();
}
IppOneSetOf IppAttr::asList() const
{
if(isList())
{
return get<IppOneSetOf>();
}
else
{
return IppOneSetOf {{value()}};
}
}

std::ostream& operator<<(std::ostream& os, const IppIntRange& ir)
{
os << "{\"min\": " << ir.low << ", \"max\": " << ir.high << "}";
return os;
}
std::ostream& operator<<(std::ostream& os, const IppResolution& res)
{
os << "{\"x\": " << res.x
<< ", \"y\": " << res.y
<< ", \"units\": " << +res.units << "}";
return os;
}
std::ostream& operator<<(std::ostream& os, const IppDateTime& dt)
{
// 2000-01-02T00:00:57 GMT+0200
os << "\"" << std::setfill('0') << std::setw(4) << dt.year << "-"
<< std::setw(2) << +dt.month << "-" << std::setw(2) << +dt.day
<< "T" << std::setw(2) << +dt.hour << ":"
<< std::setw(2) << +dt.minutes << ":" << std::setw(2) << +dt.seconds
<< "." << std::setw(3) << dt.deciSeconds*100 << " GMT" << dt.plusMinus
<< std::setw(2) << +dt.utcHOffset << std::setw(2) << +dt.utcMOffset << "\"";
return os;
}

std::ostream& operator<<(std::ostream& os, const IppValue& iv)
{
if(iv.is<std::string>())
{
os << "\"" << iv.get<std::string>() << "\"";
}
else if(iv.is<int>())
{
os << iv.get<int>();
}
else if(iv.is<bool>())
{
os << iv.get<bool>();
}
else if(iv.is<IppIntRange>())
{
os << iv.get<IppIntRange>();
}
else if(iv.is<IppResolution>())
{
os << iv.get<IppResolution>();
}
else if(iv.is<IppDateTime>())
{
os << iv.get<IppDateTime>();
}
else if(iv.is<IppOneSetOf>())
{
IppOneSetOf oneSet = iv.get<IppOneSetOf>();
os << "[" << oneSet.takeFront();
for(IppValue iv2 : oneSet)
{
os << ", " << iv2;
}
os << "]";
}
else if(iv.is<IppCollection>())
{
os << "{";
IppCollection ippCollection = iv.get<IppCollection>();
IppCollection::const_iterator it = ippCollection.cbegin();
os << "\"" << it->first << "\": " << it->second;
it++;
for(; it != ippCollection.cend(); it++)
{
os << ", \"" << it->first << "\": " << it->second;
}
os << "}";
}
else
{
os << "unhandled value";
}

return os;
}

std::ostream& operator<<(std::ostream& os, const IppAttrs& as)
{
if(as.empty())
{
os << "{}" << std::endl;
return os;
}

IppAttrs::const_iterator it = as.cbegin();
os << "{"
<< "\"" << it->first << "\": {\"tag\": " << +it->second.tag()
<< ", \"value\": " << it->second.value() << "}";
it++;
for(; it != as.cend(); it++)
{
os << "," << std::endl
<< "\"" << it->first << "\": {\"tag\": " << +it->second.tag()
<< ", \"value\": " << it->second.value() << "}";
}
os << "}" << std::endl;
return os;
}

bool IppCollection::has(std::string key) const
{
return find(key) != end();
}

void IppCollection::set(std::string key, IppAttr value)
{
insert_or_assign(key, value);
}
153 changes: 153 additions & 0 deletions lib/ippattr.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
#ifndef IPPATTR_H
#define IPPATTR_H

#include "list.h"
#include <cstdint>
#include <string>
#include <vector>
#include <map>
#include <iostream>
#include "polymorph.h"

struct IppOneSetOf;
struct IppCollection;
class IppAttr;

struct IppIntRange
{
int32_t low = 0;
int32_t high = 0;

bool operator==(const IppIntRange& other) const
{
return other.low == low && other.high == high;
}
};

struct IppResolution
{
enum Units : uint8_t
{
Invalid=0,
DPI=3,
DPCM=4
};

uint32_t x = 0;
uint32_t y = 0;
uint8_t units = Invalid;

bool operator==(const IppResolution& other) const
{
return other.units == units && other.x == x && other.y == y;
}
};

struct IppDateTime
{
uint16_t year = 0;
uint8_t month = 0;
uint8_t day = 0;
uint8_t hour = 0;
uint8_t minutes = 0;
uint8_t seconds = 0;
uint8_t deciSeconds = 0;
uint8_t plusMinus = '+';
uint8_t utcHOffset = 0;
uint8_t utcMOffset = 0;

bool operator==(const IppDateTime& other) const
{
return other.year == year &&
other.month == month &&
other.day == day &&
other.hour == hour &&
other.minutes == minutes &&
other.seconds == seconds &&
other.deciSeconds == deciSeconds &&
other.plusMinus == plusMinus &&
other.utcHOffset == utcHOffset &&
other.utcMOffset == utcMOffset;
}
};

using IppValue = Polymorph<std::string, int, bool,
IppIntRange, IppResolution, IppDateTime,
IppOneSetOf, IppCollection>;

struct IppOneSetOf: public List<IppValue>
{
using List<IppValue>::List;
};

struct IppCollection: public std::map<std::string, IppAttr>
{
using std::map<std::string, IppAttr>::map;
bool has(std::string key) const;
void set(std::string key, IppAttr value);
};

class IppAttr : public IppValue
{
public:
bool isList() const ;
IppOneSetOf asList() const;

template <typename T>
IppAttr(uint8_t tag, T value) : IppValue(value), _tag(tag) {}

uint8_t tag() const {return _tag;}
IppValue value() const {return *this;}

private:
uint8_t _tag;

};

struct IppAttrs: public std::map<std::string, IppAttr>
{
using std::map<std::string, IppAttr>::map;

bool has(std::string key) const
{
return find(key) != end();
}

template <typename T>
T get(std::string name, T res=T()) const
{
if(find(name) != end())
{
res = at(name).get<T>();
}
return res;
}

void set(std::string key, IppAttr value)
{
insert_or_assign(key, value);
}

template <typename T>
List<T> getList(std::string name) const
{
List<T> res;
if(has(name))
{
for(const IppValue& v : at(name).asList())
{
res.push_back(v.get<T>());
}
}
return res;
}
};

std::ostream& operator<<(std::ostream& os, const IppIntRange& iv);
std::ostream& operator<<(std::ostream& os, const IppResolution& iv);
std::ostream& operator<<(std::ostream& os, const IppDateTime& iv);
std::ostream& operator<<(std::ostream& os, const IppValue& iv);

std::ostream& operator<<(std::ostream& os, const IppAttrs& as);

#endif // IPPATTR_H
Loading

0 comments on commit 39158f8

Please sign in to comment.