We often construct a foxit::common::Renderer object based on a foxit::common::Bitmap to do the page rendering. But if we try to create a bitmap with a large size for rendering, we may get OOM exception when creating the foxit::common::Bitmap object. This is because the expected bitmap size is too large to create. One solution for this is to reduce the size for creating foxit::common::Bitmap in order to avoid the OOM exception.
However, if we still wish to proceed in this manner, is it possible?
The answer is Yes. We can adopt tiled-based rendering method.
How to do tiled-based rendering?
Instead of rendering the whole page with large size in one time, just divide the rendering area of PDF page into multiple blocks in vertical direction and render each block one by one. Please note that we just divide the rendering area, but not split the PDF page.
Then splice all the bitmaps (which are the rendering results for the blocks) together to form a complete image as the final result.
Below is the C++ sample code. In the sample code, we divide 10 blocks in vertical direction for rendering and splice the rendering result of 10 blocks together to form a BMP file as final result.
Main code flow:
// Load PDF document.
PDFDoc doc = PDFDoc(input_pdf_path);
ErrorCode error_code = doc.Load();
if (error_code != foxit::e_ErrSuccess) {
printf("Fail to load PDF file. Error code: %d\n", error_code);
return ;
}
// Get first PDF page and parse it.
int page_index = 0;
PDFPage page = doc.GetPage(page_index);
page.StartParse(0, NULL, false);
// Now, we're going to divide 10 blocks in vertical direction for rendering.
int int_page_width = page.GetWidth();
int int_page_height = page.GetHeight();
int y_block_count = 10;
int single_block_width = int_page_width;
int single_block_height = (int)(int_page_height / y_block_count);
string saved_final_image_file = "saved.bmp";
for (int y_block_index = 0; y_slice_index < y_block_count; y_slice_index++) {
// Render each block.
Matrix matrix = page.GetDisplayMatrix(0, -1 * y_slice_index *single_block_height,
int_page_width, int_page_height, e_Rotation0);
Bitmap bitmap(single_block_width, single_block_height, Bitmap::e_DIBArgb, NULL, 0);
bitmap.FillRect(0xFFFFFFFF, NULL);
Renderer render(bitmap, false);
render.StartRender(page, matrix, NULL);
// Write the data of rendering result bitmap to a BMP file which is the final result.
// Please refer to below for implementation of this function.
WriteToBmp_Append(bitmap, saved_final_image_file.c_str(), y_block_count, y_slice_index);
}
Implemenation of function WriteToBmp_Appedn():
bool WriteToBmp_Append(const Bitmap& bitmap, const char* filePath, int y_block_count, int y_block_index)
{
FILE* pFile = NULL;
if (y_block_index == 0)
pFile = fopen(filePath, "wb");
else
pFile = fopen(filePath, "ab");
if (pFile == NULL) return false;
Bitmap temp_bitmap = (Bitmap)bitmap;
if (temp_bitmap.GetFormat() == Bitmap::e_DIBArgb || temp_bitmap.GetBpp() <= 8) {
temp_bitmap.ConvertFormat(Bitmap::e_DIBRgb, NULL);
}
uint32 dpitch = temp_bitmap.GetPitch();
int bitmap_height = temp_bitmap.GetHeight();
// For first block, we need to write the head for BMP file.
if (y_block_index == 0)
{
uint32 imageSize = dpitch * bitmap_height*y_block_count;
int size = 14 + 40 + imageSize;
unsigned char fileHeadBuf[14];
memset(fileHeadBuf, 0, 14);
// write file header
fileHeadBuf[0] = 'B';
fileHeadBuf[1] = 'M';
fileHeadBuf[2] = (unsigned char)size;
fileHeadBuf[3] = (unsigned char)(size >> 8);
fileHeadBuf[4] = (unsigned char)(size >> 16);
fileHeadBuf[5] = (unsigned char)(size >> 24);
fileHeadBuf[6] = fileHeadBuf[7] = fileHeadBuf[8] = fileHeadBuf[9] = 0;
fileHeadBuf[10] = 54;
fileHeadBuf[11] = fileHeadBuf[12] = fileHeadBuf[13] = 0;
fwrite(fileHeadBuf, 14, 1, pFile);
unsigned char bmpHeadBuf[40];
memset(bmpHeadBuf, 0, 40);
// write bitmap header
int bitmapwidth = temp_bitmap.GetWidth();
int bitmapheight = bitmap_height * y_block_count;
memset(bmpHeadBuf, 0, 40);
bmpHeadBuf[0] = 40;
bmpHeadBuf[4] = (unsigned char)bitmapwidth;
bmpHeadBuf[5] = (unsigned char)(bitmapwidth >> 8);
bmpHeadBuf[6] = (unsigned char)(bitmapwidth >> 16);
bmpHeadBuf[7] = (unsigned char)(bitmapwidth >> 24);
bmpHeadBuf[8] = (unsigned char)(-1 * bitmapheight);
bmpHeadBuf[9] = (unsigned char)((-1 * bitmapheight) >> 8);
bmpHeadBuf[10] = (unsigned char)((-1 * bitmapheight) >> 16);
bmpHeadBuf[11] = (unsigned char)((-1 * bitmapheight) >> 24);
bmpHeadBuf[12] = 1; //plane always 1
bmpHeadBuf[14] = (char)temp_bitmap.GetBpp();
fwrite(bmpHeadBuf, 40, 1, pFile);
}
uint32 single_datasize = dpitch * bitmap_height;
const uint8* single_databuf = temp_bitmap.GetBuffer();
fwrite(single_databuf, 1, single_datasize, pFile);
fclose(pFile);
return true;
}