/*
* Copyright (C) 2004 Stefan Kleine Stegemann
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <stdio.h>
#include <stdlib.h>
#include "poppler_cairo_img_renderer.h"
#include "poppler.h"
#include <PDFDoc.h>
#include <Page.h>
#include <goo/GooString.h>
#include <CairoOutputDev.h>
#define PDF_DOC(obj) static_cast<PDFDoc*>(obj)
#define PAGE(obj) static_cast<Page*>(obj)
#define CAIRO_DEV_IMG(obj) static_cast<CairoImageDev*>(obj)
#ifndef MAX
#define MAX(a,b) (((a)>(b))?(a):(b))
#endif
typedef struct CairoImageDev {
CairoOutputDev* device;
cairo_surface_t* surface;
unsigned char* data;
} CairoImageDev;
static void my_poppler_cairo_prepare_dev(CairoImageDev* output_dev, Page* page,
double scale, int rotation, int transparent)
{
int width;
int height;
int rotate = (rotation + page->getRotate()) % 360;
if (rotate == 90 || rotate == 270)
{
#ifdef POPPLER_0_4
width = MAX((int)(page->getHeight() * scale + 0.5), 1);
height = MAX((int)(page->getWidth() * scale + 0.5), 1);
#endif
#ifdef POPPLER_0_5
width = MAX((int)(page->getMediaHeight() * scale + 0.5), 1);
height = MAX((int)(page->getMediaWidth() * scale + 0.5), 1);
#endif
}
else
{
#ifdef POPPLER_0_4
width = MAX((int)(page->getWidth() * scale + 0.5), 1);
height = MAX((int)(page->getHeight() * scale + 0.5), 1);
#endif
#ifdef POPPLER_0_5
width = MAX((int)(page->getMediaWidth() * scale + 0.5), 1);
height = MAX((int)(page->getMediaHeight() * scale + 0.5), 1);
#endif
}
int rowstride = width * 4;
unsigned char* data = (unsigned char*)malloc(height * rowstride);
memset(data, (transparent ? 0x00 : 0xff), height * rowstride);
cairo_surface_t* surface = cairo_image_surface_create_for_data(data, CAIRO_FORMAT_ARGB32, width, height, rowstride);
#ifdef POPPLER_0_5
output_dev->device->setCairo(cairo_create(surface));
#else
output_dev->device->setSurface(surface);
#endif
output_dev->surface = surface;
output_dev->data = data;
}
void* poppler_cairo_img_device_create(void)
{
BEGIN_SYNCHRONIZED;
CairoOutputDev* cairoDevice = new CairoOutputDev();
CairoImageDev* imageDevice = (CairoImageDev*)malloc(sizeof(CairoImageDev));
imageDevice->device = cairoDevice;
imageDevice->surface = NULL;
imageDevice->data = NULL;
END_SYNCHRONIZED;
return imageDevice;
}
void poppler_cairo_img_device_start_doc(void* output_dev, void* poppler_document)
{
if (!output_dev || !poppler_document)
{
return;
}
SYNCHRONIZED(CAIRO_DEV_IMG(output_dev)->device->startDoc(PDF_DOC(poppler_document)->getXRef()));
}
void poppler_cairo_img_device_destroy(void* output_dev)
{
if (!output_dev)
{
return;
}
SYNCHRONIZED(delete CAIRO_DEV_IMG(output_dev)->device);
free(CAIRO_DEV_IMG(output_dev));
}
int poppler_cairo_img_device_display_slice(void* output_dev, void* poppler_page,
void* poppler_document,
float hDPI, float vDPI, float baseDPI,
int rotate,
float sliceX, float sliceY,
float sliceW, float sliceH)
{
if (!output_dev || !poppler_page || !poppler_document)
{
return 0;
}
double scale = MAX(hDPI / baseDPI, vDPI / baseDPI);
my_poppler_cairo_prepare_dev(CAIRO_DEV_IMG(output_dev), PAGE(poppler_page),
scale, rotate, 0);
SYNCHRONIZED(PAGE(poppler_page)->displaySlice(CAIRO_DEV_IMG(output_dev)->device,
(double)hDPI, (double)vDPI,
rotate,
#ifdef POPPLER_0_5
gTrue, // use MediaBox
#endif
gTrue, // Crop
(int)sliceX, (int)sliceY,
(int)sliceW, (int)sliceH,
NULL, // Links
PDF_DOC(poppler_document)->getCatalog()));
return 1;
}
int poppler_cairo_img_device_get_data(void* output_dev, unsigned char** data,
int* width, int* height, int* rowstride)
{
if (!output_dev || !CAIRO_DEV_IMG(output_dev)->surface || !CAIRO_DEV_IMG(output_dev)->data)
{
return 0;
}
*data = CAIRO_DEV_IMG(output_dev)->data;
*width = cairo_image_surface_get_width(CAIRO_DEV_IMG(output_dev)->surface);
*height = cairo_image_surface_get_height(CAIRO_DEV_IMG(output_dev)->surface);
*rowstride = (*width) * 4;
cairo_surface_destroy(CAIRO_DEV_IMG(output_dev)->surface);
CAIRO_DEV_IMG(output_dev)->surface = NULL;
CAIRO_DEV_IMG(output_dev)->data = NULL; // freed after poppler_cairo_img_device_get_rgb
return 1;
}
int poppler_cairo_img_device_get_rgb(unsigned char* cairo_data, unsigned char** rgb_data,
int width, int height, int rowstride)
{
if (!cairo_data)
{
return 0;
}
unsigned char* rgb_data_ptr = *rgb_data;
for (int row = 0; row < height; row++)
{
unsigned int *src;
src = (unsigned int *) (cairo_data + row * rowstride);
for (int col = 0; col < width; col++)
{
*rgb_data_ptr++ = (*src >> 16) & 0xff;
*rgb_data_ptr++ = (*src >> 8) & 0xff;
*rgb_data_ptr++ = (*src >> 0) & 0xff;
src++;
}
}
free(cairo_data);
return 1;
}
syntax highlighted by Code2HTML, v. 0.9.1