presentation
parent
a5134535f4
commit
0b36d583ee
8 changed files with 438 additions and 346 deletions
@ -0,0 +1,226 @@ |
||||
#include "PdfObjectWriter.h" |
||||
#include "UpdateRef.h" |
||||
#include "UpdateRefKey.h" |
||||
|
||||
PdfObjectWriter::PdfObjectWriter(PdfWriter * writer, PdfXRef * xref) { |
||||
this->writer = writer; |
||||
this->xref = xref; |
||||
|
||||
this->updatedReferenced = g_hash_table_new_full((GHashFunc) UpdateRefKey::hashFunction, (GEqualFunc) UpdateRefKey::equalFunction, |
||||
(GDestroyNotify) UpdateRefKey::destroyDelete, (GDestroyNotify) UpdateRef::destroyDelete); |
||||
|
||||
} |
||||
|
||||
PdfObjectWriter::~PdfObjectWriter() { |
||||
this->writer = NULL; |
||||
this->xref = NULL; |
||||
|
||||
// TODO: free!?
|
||||
g_hash_table_destroy(this->updatedReferenced); |
||||
this->updatedReferenced = NULL; |
||||
} |
||||
|
||||
void PdfObjectWriter::writeCopiedObjects() { |
||||
bool allWritten = false; |
||||
while (!allWritten) { |
||||
allWritten = true; |
||||
for (GList * l = g_hash_table_get_values(this->updatedReferenced); l != NULL; l = l->next) { |
||||
UpdateRef * uref = (UpdateRef *) l->data; |
||||
if (!uref->wroteOut) { |
||||
this->xref->setXref(uref->objectId, this->writer->getDataCount()); |
||||
this->writer->writef("%i 0 obj\n", uref->objectId); |
||||
|
||||
writeObject(&uref->object, uref->doc); |
||||
this->writer->write("endobj\n"); |
||||
uref->wroteOut = true; |
||||
break; |
||||
} |
||||
} |
||||
for (GList * l = g_hash_table_get_values(this->updatedReferenced); l != NULL; l = l->next) { |
||||
UpdateRef * uref = (UpdateRef *) l->data; |
||||
if (!uref->wroteOut) { |
||||
allWritten = false; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
void PdfObjectWriter::writeObject(Object * obj, XojPopplerDocument doc) { |
||||
Array * array; |
||||
Object obj1; |
||||
|
||||
switch (obj->getType()) { |
||||
case objBool: |
||||
this->writer->writef("%s ", obj->getBool() ? "true" : "false"); |
||||
break; |
||||
case objInt: |
||||
this->writer->writef("%i ", obj->getInt()); |
||||
break; |
||||
case objReal: |
||||
this->writer->writef("%g ", obj->getReal()); |
||||
break; |
||||
case objString: |
||||
this->writeString(obj->getString()); |
||||
break; |
||||
case objName: { |
||||
GooString name(obj->getName()); |
||||
GooString * nameToPrint = name.sanitizedName(gFalse /* non ps mode */); |
||||
this->writer->writef("/%s ", nameToPrint->getCString()); |
||||
delete nameToPrint; |
||||
break; |
||||
} |
||||
case objNull: |
||||
this->writer->write("null"); |
||||
break; |
||||
case objArray: |
||||
array = obj->getArray(); |
||||
this->writer->write("["); |
||||
for (int i = 0; i < array->getLength(); i++) { |
||||
writeObject(array->getNF(i, &obj1), doc); |
||||
obj1.free(); |
||||
} |
||||
this->writer->write("] "); |
||||
break; |
||||
case objDict: |
||||
writeDictionnary(obj->getDict(), doc); |
||||
break; |
||||
case objStream: { |
||||
// Poppler: We can't modify stream with the current implementation (no write functions in Stream API)
|
||||
// Poppler: => the only type of streams which that have been modified are internal streams (=strWeird)
|
||||
Stream *stream = obj->getStream(); |
||||
if (stream->getKind() == strWeird) { |
||||
//we write the stream unencoded
|
||||
stream->reset(); |
||||
//recalculate stream length
|
||||
int tmp = 0; |
||||
for (int c = stream->getChar(); c != EOF; c = stream->getChar()) { |
||||
tmp++; |
||||
} |
||||
obj1.initInt(tmp); |
||||
stream->getDict()->set("Length", &obj1); |
||||
|
||||
//Remove Stream encoding
|
||||
stream->getDict()->remove("Filter"); |
||||
stream->getDict()->remove("DecodeParms"); |
||||
|
||||
writeDictionnary(stream->getDict(), doc); |
||||
writeStream(stream); |
||||
obj1.free(); |
||||
} else { |
||||
//raw stream copy
|
||||
writeDictionnary(stream->getDict(), doc); |
||||
writeRawStream(stream, doc); |
||||
} |
||||
break; |
||||
} |
||||
case objRef: { |
||||
UpdateRefKey key(obj->getRef(), doc); |
||||
UpdateRef * uref = (UpdateRef *) g_hash_table_lookup(this->updatedReferenced, &key); |
||||
if (uref) { |
||||
this->writer->writef("%i %i R ", uref->objectId, 0); |
||||
} else { |
||||
UpdateRef * uref = new UpdateRef(this->writer->getNextObjectId(), doc); |
||||
this->xref->addXref(0); |
||||
this->writer->writef("%i %i R ", uref->objectId, 0); |
||||
|
||||
obj->fetch(doc.getDoc()->getXRef(), &uref->object); |
||||
|
||||
g_hash_table_insert(this->updatedReferenced, new UpdateRefKey(obj->getRef(), doc), uref); |
||||
} |
||||
} |
||||
break; |
||||
case objCmd: |
||||
this->writer->write("cmd\r\n"); |
||||
break; |
||||
case objError: |
||||
this->writer->write("error\r\n"); |
||||
break; |
||||
case objEOF: |
||||
this->writer->write("eof\r\n"); |
||||
break; |
||||
case objNone: |
||||
this->writer->write("none\r\n"); |
||||
break; |
||||
default: |
||||
g_error("Unhandled objType : %i, please report a bug with a testcase\r\n", obj->getType()); |
||||
break; |
||||
} |
||||
} |
||||
|
||||
void PdfObjectWriter::writeRawStream(Stream * str, XojPopplerDocument doc) { |
||||
Object obj1; |
||||
str->getDict()->lookup("Length", &obj1); |
||||
if (!obj1.isInt()) { |
||||
error(-1, "PDFDoc::writeRawStream, no Length in stream dict"); |
||||
return; |
||||
} |
||||
|
||||
const int length = obj1.getInt(); |
||||
obj1.free(); |
||||
|
||||
this->writer->write("stream\r\n"); |
||||
str->unfilteredReset(); |
||||
|
||||
char buffer[1]; |
||||
|
||||
for (int i = 0; i < length; i++) { |
||||
int c = str->getUnfilteredChar(); |
||||
buffer[0] = c; |
||||
this->writer->writeLen(buffer, 1); |
||||
} |
||||
str->reset(); |
||||
this->writer->write("\nendstream\n"); |
||||
} |
||||
|
||||
void PdfObjectWriter::writeStream(Stream * str) { |
||||
this->writer->write("stream\r\n"); |
||||
str->reset(); |
||||
for (int c = str->getChar(); c != EOF; c = str->getChar()) { |
||||
this->writer->writef("%c", c); |
||||
} |
||||
this->writer->write("\r\nendstream\r\n"); |
||||
} |
||||
|
||||
void PdfObjectWriter::writeDictionnary(Dict * dict, XojPopplerDocument doc) { |
||||
Object obj1; |
||||
this->writer->write("<<"); |
||||
for (int i = 0; i < dict->getLength(); i++) { |
||||
GooString keyName(dict->getKey(i)); |
||||
GooString *keyNameToPrint = keyName.sanitizedName(gFalse /* non ps mode */); |
||||
this->writer->writef("/%s ", keyNameToPrint->getCString()); |
||||
delete keyNameToPrint; |
||||
writeObject(dict->getValNF(i, &obj1), doc); |
||||
obj1.free(); |
||||
} |
||||
this->writer->write(">> "); |
||||
} |
||||
|
||||
void PdfObjectWriter::writeString(GooString * s) { |
||||
if (s->hasUnicodeMarker()) { |
||||
//unicode string don't necessary end with \0
|
||||
const char* c = s->getCString(); |
||||
this->writer->write("("); |
||||
for (int i = 0; i < s->getLength(); i++) { |
||||
char unescaped = *(c + i) & 0x000000ff; |
||||
//escape if needed
|
||||
if (unescaped == '(' || unescaped == ')' || unescaped == '\\') { |
||||
this->writer->writef("%c", '\\'); |
||||
} |
||||
this->writer->writef("%c", unescaped); |
||||
} |
||||
this->writer->write(") "); |
||||
} else { |
||||
const char* c = s->getCString(); |
||||
this->writer->write("("); |
||||
while (*c != '\0') { |
||||
char unescaped = (*c) & 0x000000ff; |
||||
//escape if needed
|
||||
if (unescaped == '(' || unescaped == ')' || unescaped == '\\') { |
||||
this->writer->writef("%c", '\\'); |
||||
} |
||||
this->writer->writef("%c", unescaped); |
||||
c++; |
||||
} |
||||
this->writer->write(") "); |
||||
} |
||||
} |
||||
@ -0,0 +1,41 @@ |
||||
/*
|
||||
* Xournal++ |
||||
* |
||||
* Handles PDF Export |
||||
* |
||||
* @author Xournal Team |
||||
* http://xournal.sf.net
|
||||
* |
||||
* @license GPL |
||||
*/ |
||||
|
||||
#ifndef __PDFOBJECTWRITER_H__ |
||||
#define __PDFOBJECTWRITER_H__ |
||||
|
||||
#include "poppler/XojPopplerDocument.h" |
||||
#include <poppler/Object.h> |
||||
|
||||
#include "PdfWriter.h" |
||||
#include "PdfXRef.h" |
||||
|
||||
class PdfObjectWriter { |
||||
public: |
||||
PdfObjectWriter(PdfWriter * writer, PdfXRef * xref); |
||||
virtual ~PdfObjectWriter(); |
||||
|
||||
public: |
||||
void writeObject(Object * obj, XojPopplerDocument doc); |
||||
void writeString(GooString * s); |
||||
void writeDictionnary(Dict * dict, XojPopplerDocument doc); |
||||
void writeRawStream(Stream * str, XojPopplerDocument doc); |
||||
void writeStream(Stream * str); |
||||
void writeCopiedObjects(); |
||||
|
||||
private: |
||||
PdfWriter * writer; |
||||
PdfXRef * xref; |
||||
|
||||
GHashTable * updatedReferenced; |
||||
}; |
||||
|
||||
#endif /* __PDFOBJECTWRITER_H__ */ |
||||
@ -0,0 +1,61 @@ |
||||
#include "PdfRefList.h" |
||||
#include "PdfRefEntry.h" |
||||
#include "PdfXRef.h" |
||||
|
||||
PdfRefList::PdfRefList(PdfXRef * xref, PdfObjectWriter * objectWriter, PdfWriter * writer, const char * type) { |
||||
this->id = 1; |
||||
this->data = NULL; |
||||
this->xref = xref; |
||||
this->objectWriter = objectWriter; |
||||
this->writer = writer; |
||||
this->type = type; |
||||
} |
||||
|
||||
PdfRefList::~PdfRefList() { |
||||
for (GList * l = this->data; l != NULL; l = l->next) { |
||||
PdfRefEntry * pattern = (PdfRefEntry *) l->data; |
||||
delete pattern; |
||||
} |
||||
g_list_free(this->data); |
||||
} |
||||
|
||||
void PdfRefList::writeObjects() { |
||||
for (GList * l = this->data; l != NULL; l = l->next) { |
||||
PdfRefEntry * ref = (PdfRefEntry *) l->data; |
||||
|
||||
this->xref->setXref(ref->objectId, this->writer->getDataCount()); |
||||
bool res = this->writer->writef("%i 0 obj\n", ref->objectId); |
||||
|
||||
this->objectWriter->writeObject(ref->object, ref->doc); |
||||
this->writer->write("\nendobj\n"); |
||||
} |
||||
} |
||||
|
||||
int PdfRefList::lookup(String name, Ref ref, Object * object, XojPopplerDocument doc) { |
||||
for (GList * l = this->data; l != NULL; l = l->next) { |
||||
PdfRefEntry * p = (PdfRefEntry *) l->data; |
||||
|
||||
if (p->equalsRef(ref)) { |
||||
object->free(); |
||||
delete object; |
||||
return p->objectId; |
||||
} |
||||
} |
||||
|
||||
int id = this->id++; |
||||
|
||||
PdfRefEntry * pattern = new PdfRefEntry(this->writer->getNextObjectId(), ref, object, id, doc); |
||||
this->xref->addXref(0); |
||||
this->data = g_list_append(this->data, pattern); |
||||
|
||||
return id; |
||||
} |
||||
|
||||
bool PdfRefList::writeRefList() { |
||||
for (GList * l = this->data; l != NULL; l = l->next) { |
||||
PdfRefEntry * img = (PdfRefEntry *) l->data; |
||||
this->writer->writef("/%s%i %i 0 R\n", this->type, img->imageId, img->objectId); |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
@ -0,0 +1,46 @@ |
||||
/*
|
||||
* Xournal++ |
||||
* |
||||
* Handles PDF Export |
||||
* |
||||
* @author Xournal Team |
||||
* http://xournal.sf.net
|
||||
* |
||||
* @license GPL |
||||
*/ |
||||
|
||||
#ifndef __PDFREFLIST_H__ |
||||
#define __PDFREFLIST_H__ |
||||
|
||||
#include <glib.h> |
||||
#include "../util/String.h" |
||||
#include <poppler/Object.h> |
||||
|
||||
#include "PdfObjectWriter.h" |
||||
#include "poppler/XojPopplerDocument.h" |
||||
|
||||
class PdfXRef; |
||||
class PdfExport; |
||||
class PdfWriter; |
||||
|
||||
class PdfRefList { |
||||
public: |
||||
PdfRefList(PdfXRef * xref, PdfObjectWriter * objectWriter, PdfWriter * writer, const char * type); |
||||
virtual ~PdfRefList(); |
||||
|
||||
public: |
||||
void writeObjects(); |
||||
bool writeRefList(); |
||||
int lookup(String name, Ref ref, Object * object, XojPopplerDocument doc); |
||||
|
||||
private: |
||||
int id; |
||||
GList * data; |
||||
|
||||
PdfXRef * xref; |
||||
PdfObjectWriter * objectWriter; |
||||
PdfWriter * writer; |
||||
const char * type; |
||||
}; |
||||
|
||||
#endif /* PDFREFLIST_H_ */ |
||||
Loading…
Reference in new issue