[poppler] Toward to JBIG2 support in CairoOutputDev
Adrian Johnson
ajohnson at redneon.com
Tue Jan 6 22:14:57 PST 2015
On 07/01/15 02:58, suzuki toshiya wrote:
> Hi all,
>
> Here I submit a preliminary patch for git head,
> which enables JBIG2 embedding to PDF surface via Cairo.
+static cairo_status_t setJBIG2GlobalsIdByRefNums(int refNum, int refGen,
+ cairo_surface_t *image)
+{
+ GooString *globalsStrId;
+ char *idBuffer;
+ cairo_status_t st;
+
+
+ globalsStrId = new GooString;
+ globalsStrId->appendf("{0:d}-{1:d}", refNum, refGen);
+ idBuffer = copyString(globalsStrId->getCString());
+ st = cairo_surface_set_mime_data (image, CAIRO_MIME_TYPE_JBIG2_GLOBAL_ID,
The cairo JBIG2 mime types are new to 1.14.0 so will need to be inside a
#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 14, 0).
You could also factor out the CAIRO_MIME_TYPE_UNIQUE_ID code into this
function to avoid the duplication of code. eg name it
setMimeIdFromRef(cairo_surface_t *surface,
const char *mime_type,
Ref ref);
and use it for setting UNIQUE_ID and JBIG2_GLOBAL_ID mime data.
+GBool CairoOutputDev::setMimeDataForJBIG2Globals(Stream *str,
+ cairo_surface_t *image)
+{
+ JBIG2Stream *jbig2Str = static_cast<JBIG2Stream *>(str);
+ Object* globalsStr = jbig2Str->getGlobalsStream();
+ char *globalsBuffer;
+ int globalsLength;
+
+ // According to PDF spec, Globals should be stream (or nothing)
+
+ if (globalsStr->isNull())
+ return gTrue;
+
+ if (!globalsStr->isStream())
+ return gFalse;
+
+ // See JBIG2Stream constructor for valid reference number
+ if (!jbig2Str->getGlobalsStreamRefNum())
+ return gFalse;
The globalsStr->isStream() check should be sufficient. The reference
number should always be valid of the global stream is valid.
+#define getMimeTypeFromStreamKind( k ) \
+ ( k == strDCT ? CAIRO_MIME_TYPE_JPEG : \
+ ( k == strJPX ? CAIRO_MIME_TYPE_JP2 : \
+ ( k == strJBIG2 ? CAIRO_MIME_TYPE_JBIG2 : \
+ "" \
+ ) \
+ ) \
+ )
+
st = cairo_surface_set_mime_data (image,
- str->getKind() == strDCT ?
- CAIRO_MIME_TYPE_JPEG : CAIRO_MIME_TYPE_JP2,
+ getMimeTypeFromStreamKind(strKind),
(const unsigned char *)strBuffer,
I don't like the macro for converting stream type to mime type. I
suggest using a switch statement or lookup table instead.
-JBIG2Stream::JBIG2Stream(Stream *strA, Object *globalsStreamA):
+JBIG2Stream::JBIG2Stream(Stream *strA, Object *globalsStreamA, Object
*globalsStreamRefA):
FilterStream(strA)
{
pageBitmap = NULL;
@@ -1194,6 +1194,18 @@ JBIG2Stream::JBIG2Stream(Stream *strA, Object
*globalsStreamA):
mmrDecoder = new JBIG2MMRDecoder();
globalsStreamA->copy(&globalsStream);
+ if (globalsStreamRefA) {
+ globalsStreamRefNum = globalsStreamRefA->getRefNum();
+ globalsStreamRefGen = globalsStreamRefA->getRefGen();
+ } else {
+ // According to PDF spec, object reference number 0 is reserved
+ // to indicate the head & tail of xref, it should not be used
+ // for the valid reference. We use it to indicate the case that
+ // JBIG2Stream should be decoded without Globals stream.
+ globalsStreamRefNum = 0;
+ globalsStreamRefGen = 0;
+ }
+
globalStreamA is never null. I suggest storing the ref in a variable of
type Ref. Then the code can be:
if (globalsStreamA->isRef())
globalsStreamRef = globalsStreamA->getRef();
Instead of using num,gen = 0 to indicate no global, I suggest checking
getGlobalsStream()->isStream().
+ virtual int getGlobalsStreamRefNum() { return globalsStreamRefNum; }
+ virtual int getGlobalsStreamRefGen() { return globalsStreamRefGen; }
You can use the Ref type to avoid having two functions to get the ref.
eg virtual Ref getGlobalsStreamRef() { return globalsStreamRef; }
Object globalsStream;
+ int globalsStreamRefNum; // to make unique ID for JBIG2 Globals in
CairoOutputDev
+ int globalsStreamRefGen; // to make unique ID for JBIG2 Globals in
CairoOutputDev
No need to mention what the variables are used for outside of this class.
@@ -336,11 +337,23 @@ Stream *Stream::makeFilter(char *name, Stream
*str, Object *params, int recursio
}
str = new FlateStream(str, pred, columns, colors, bits);
} else if (!strcmp(name, "JBIG2Decode")) {
+ obj.free();
If obj is not null at this point it is a bug and the free belongs
somewhere else. If you just want to ensure obj is null, use obj.initNull().
if (params->isDict()) {
params->dictLookup("JBIG2Globals", &globals, recursion);
+ if (globals.isStream()) {
+ params->dictLookupNF("JBIG2Globals", &obj);
+ XRef *xref = params->getDict()->getXRef();
+ Object rObj;
+ while (xref->fetch(obj.getRefNum(), obj.getRefGen(),
&rObj)->isRef()) {
+ obj.free();
+ rObj.copy(&obj);
+ }
+ rObj.free();
+ }
}
This would be simpler and easier to understand when written as:
if (params->isDict()) {
params->dictLookup("JBIG2Globals", &globals, recursion);
while (globals.isRef()) {
obj.free();
globals.copy(&obj);
globals.free();
obj.fetch(xref, &globals);
}
}
str = new JBIG2Stream(str, &globals, &refObj);
More information about the poppler
mailing list