I believe I have finally figured out the ipdf sharpness and image quality issue, without needing to modify Poppler!
Originally iRex was taking 24 bit bitmaps from Poppler and doing something interesting with them. I never realized how interesting until this past weekend. They were doing a color space cube reduction and letting the cube reduction kinda sorta correct them into 4 bit per pixel gray.
I say interesting because conversion from RGB to 8 bit grey scale is essentially error free to the human eye, there is no need to use a color cube reduction. In addition their color cube reduction wasn't doing anything intelligent vis-a-vis the human eye. The human eye is far more sensitive to green than either or red or blue. iRex though did a simple linear color cube reduction.
So why did iRex say the ipdf converted to have Poppler serve up Mono 8 was inferior in image quality for pictures?
While Mono 8 is good enough, the iLiad is a Mono 4 device. The iLiad's frame buffer (and my code as well) was not doing anything smart in converting Mono 8 to Mono 4, so in some cases you'd get some rather nasty posterization in images.
The code below takes Poppler's Mono 8 and crunches it to Mono 4 with FS dithering for the error distribution. This more directly addresses what the cube reduction was doing by reducing the number of colors in the Poppler image to indirectly reduce the number of grays in the image.
But what about the glyphs? We still want our razor sharp glyphs right? Didn't the FS error distribution do bad things to the glyphs?
Technically, white on the iLiad is actually 239, but iRex tells Poppler to draw text on 255 paper. This use of 255 rather than 239 causes their cube routine to distribute an error because there is no 255 on the iLiad. This distributed white error would in essence chew the edges of glyphs and make them appear "moth eaten" as little white errors were distributed into them.
The code below understands 255 is "white" and exempts it from error distribution. I tried just telling Poppler to draw on 239 paper but Paul's scanned books (and others) are drawn on 255 paper as well...
This code drops into PDFCore.cpp. Don't forget to also tweak that same file to use Mono 8 mode with Poppler.
Code:
// check result
if (ret == Render_Error || ret == Render_Invalid)
{
PV_ERRORPRINTF("Render page error!");
return ret;
}
// bitmap has been allocated
info.bitmap = outputDev->takeBitmap();
// Convert Mono 8 to Mono 4
int srcWidth = info.bitmap->getWidth();
int srcHeight = info.bitmap->getHeight();
char *src = (char *)info.bitmap->getDataPtr();
int origGrey = 0;
int grey = 0;
int error = 0;
int *errors = (int *)alloca((srcWidth + 2) * 4);
memset(errors, 0, (srcWidth + 2) * 4);
int errorRight = 0;
int errDownRight = 0;
for (int y = 0; y < srcHeight; y++) {
for (int x = 0; x < srcWidth; x++) {
// Get Mono 8 pixel and add error distribution
origGrey = *src + errorRight + errors[x+1];
// Convert pixel to Mono 4, clip < 0 and > Mono 4
if (origGrey <= 0) {
grey = 0;
} else if (origGrey >= 0x00ff) {
grey = 0x00ff; // No error for white of 255
} else {
grey = origGrey & 0x00f0;
}
// Put Mono 4 pixel with distributed error back
*src++ = grey;
// Calculate error
error = origGrey - grey;
// Distribute error
errorRight = (error * 7) >> 4;
errors[x] += (error * 3) >> 4;
errors[x+1] = ((error * 5) >> 4) + errDownRight;
errDownRight = error >> 4;
}
}
if (ret == Render_Done)
{
#if (PV_PROFILE_ON)