[poppler] [patch] a sketch of yflip for PNGWriter for pdftohtml
Albert Astals Cid
aacid at kde.org
Sun Mar 11 14:47:43 PDT 2012
El Diumenge, 11 de març de 2012, a les 17:44:02, Ihar `Philips` Filipau va
escriure:
> Hi All!
Hi
> I had some spare time and source code at hand and tried to solve
> another of my problems with the pdftohtml: vertically flipped images.
> (Also a long standing bug:
> https://bugs.freedesktop.org/show_bug.cgi?id=32340 )
>
> An hour (w)hacking at the code produced that piece of frankenstein
> code you might see below.
>
> Short summary: implement very crude yflip in PNGWriter by buffering
> rows and transpose/write them before closing the PNG image; disable
> JPEGs and write always PNGs. (The piece of code detecting flip was
> lifted from pdf2xml project.)
>
>
> Is there any official ideas on how to implement the image flip in the
> pdftohtml?
>
> Are other flip possible too? rotations? To date I have seen only PDFs
> with upside down images.
>
> Have Fun.
Please either use bugzilla or the list to post patches, not both, otherwise
following the conversation gets difficult.
Albert
>
>
> goo/PNGWriter.cc | 89
> ++++++++++++++++++++++++++++++++++++++++++++++++ goo/PNGWriter.h |
> 12 ++++++-
> utils/HtmlOutputDev.cc | 47 ++++++++++++++++++++++++-
> 3 files changed, 145 insertions(+), 3 deletions(-)
>
> diff --git a/goo/PNGWriter.cc b/goo/PNGWriter.cc
> index fe8b79e..b60a540 100644
> --- a/goo/PNGWriter.cc
> +++ b/goo/PNGWriter.cc
> @@ -30,6 +30,11 @@ PNGWriter::PNGWriter(Format formatA) : format(formatA)
> icc_data_size = 0;
> icc_name = NULL;
> sRGB_profile = false;
> +
> + y_flip = false;
> + row_buf = NULL;
> + row_buf_num = 0;
> + row_buf_cap = 0;
> }
>
> PNGWriter::~PNGWriter()
> @@ -64,6 +69,9 @@ bool PNGWriter::init(FILE *f, int width, int height,
> int hDPI, int vDPI)
> png_const_bytep icc_data_ptr = (png_const_bytep)icc_data;
> #endif
>
> + image_width = width;
> + image_height = height;
> +
> /* initialize stuff */
> png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL,
> NULL); if (!png_ptr) {
> @@ -99,18 +107,22 @@ bool PNGWriter::init(FILE *f, int width, int
> height, int hDPI, int vDPI)
> case RGB:
> bit_depth = 8;
> color_type = PNG_COLOR_TYPE_RGB;
> + bytes_per_row = 3 * image_width;
> break;
> case RGBA:
> bit_depth = 8;
> color_type = PNG_COLOR_TYPE_RGB_ALPHA;
> + bytes_per_row = 4 * image_width;
> break;
> case GRAY:
> bit_depth = 8;
> color_type = PNG_COLOR_TYPE_GRAY;
> + bytes_per_row = 1 * image_width;
> break;
> case MONOCHROME:
> bit_depth = 1;
> color_type = PNG_COLOR_TYPE_GRAY;
> + bytes_per_row = 1 * image_width;
> break;
> }
> png_byte interlace_type = PNG_INTERLACE_NONE;
> @@ -139,6 +151,17 @@ bool PNGWriter::init(FILE *f, int width, int
> height, int hDPI, int vDPI)
>
> bool PNGWriter::writePointers(unsigned char **rowPointers, int rowCount)
> {
> + /* writes the image at once */
> + if (y_flip) {
> + if (rowCount == image_height) {
> + for (int i = 0; i<rowCount/2; i++) {
> + unsigned char *tmp = rowPointers[i];
> + int ri = rowCount-i-1;
> + rowPointers[i] = rowPointers[ri];
> + rowPointers[ri] = tmp;
> + }
> + }
> + }
> png_write_image(png_ptr, rowPointers);
> /* write bytes */
> if (setjmp(png_jmpbuf(png_ptr))) {
> @@ -152,6 +175,10 @@ bool PNGWriter::writePointers(unsigned char
> **rowPointers, int rowCount)
> bool PNGWriter::writeRow(unsigned char **row)
> {
> // Write the row to the file
> + // or just buffer if y_flip
> + if (y_flip) {
> + return bufRows( row, 1 );
> + }
> png_write_rows(png_ptr, row, 1);
> if (setjmp(png_jmpbuf(png_ptr))) {
> error(errInternal, -1, "error during png row write");
> @@ -163,6 +190,37 @@ bool PNGWriter::writeRow(unsigned char **row)
>
> bool PNGWriter::close()
> {
> + /* y_flip is implemented by buffering the rows - flush the rows here. */
> + if (y_flip && row_buf_num) {
> + /* transpose the row_buf to accomodate the y_flip */
> + for (int i = 0; i<row_buf_num/2; i++) {
> + unsigned char *tmp = row_buf[i];
> + int ri = row_buf_num-i-1;
> + row_buf[i] = row_buf[ri];
> + row_buf[ri] = tmp;
> + }
> + /* write it */
> + if (row_buf_num == image_height)
> + {
> + png_write_image(png_ptr, row_buf);
> + /* write bytes */
> + if (setjmp(png_jmpbuf(png_ptr))) {
> + error(errInternal, -1, "Error during writing bytes");
> + return false;
> + }
> + }
> + else
> + {
> + for (int i = 0; i<row_buf_num; i++) {
> + png_write_rows(png_ptr, &row_buf[i], 1);
> + if (setjmp(png_jmpbuf(png_ptr))) {
> + error(errInternal, -1, "error during png row write");
> + return false;
> + }
> + }
> + }
> + }
> +
> /* end write */
> png_write_end(png_ptr, info_ptr);
> if (setjmp(png_jmpbuf(png_ptr))) {
> @@ -173,4 +231,35 @@ bool PNGWriter::close()
> return true;
> }
>
> +void PNGWriter::setFlipY(bool flip)
> +{
> + y_flip = flip;
> +}
> +
> +bool PNGWriter::bufRows( unsigned char **rows, int row_count )
> +{
> + if (!row_count)
> + return true;
> +
> + if (row_buf_num + row_count > row_buf_cap) {
> +
> + if (row_buf_cap == 0)
> + row_buf_cap = 32;
> +
> + while ( row_buf_num + row_count > row_buf_cap )
> + row_buf_cap = (row_buf_cap/4)*5; /* increase capacity by 25% */
> +
> + row_buf = (unsigned char **)grealloc( row_buf,
> row_buf_cap*sizeof(unsigned char *) );
> + }
> +
> + while (row_count > 0) {
> + row_buf[ row_buf_num ] = (unsigned char *)gmalloc( bytes_per_row );
> + memcpy( row_buf[ row_buf_num ], *rows, bytes_per_row );
> + row_buf_num++;
> + rows++;
> + row_count--;
> + }
> + return true;
> +}
> +
> #endif
> diff --git a/goo/PNGWriter.h b/goo/PNGWriter.h
> index f22495d..efc8f58 100644
> --- a/goo/PNGWriter.h
> +++ b/goo/PNGWriter.h
> @@ -47,7 +47,8 @@ class PNGWriter : public ImgWriter
> bool writeRow(unsigned char **row);
>
> bool close();
> -
> +
> + void setFlipY(bool = true);
> private:
> Format format;
> png_structp png_ptr;
> @@ -56,6 +57,15 @@ class PNGWriter : public ImgWriter
> int icc_data_size;
> char *icc_name;
> bool sRGB_profile;
> +
> + int image_width, image_height;
> + int bytes_per_row;
> +
> + bool y_flip;
> + unsigned char **row_buf;
> + int row_buf_num, row_buf_cap;
> +
> + bool bufRows( unsigned char **rowPointers, int rowCount );
> };
>
> #endif
> diff --git a/utils/HtmlOutputDev.cc b/utils/HtmlOutputDev.cc
> index b38af4d..cd80f6d 100644
> --- a/utils/HtmlOutputDev.cc
> +++ b/utils/HtmlOutputDev.cc
> @@ -1295,7 +1295,9 @@ void HtmlOutputDev::drawJpegImage(GfxState
> *state, Stream *str)
> }
>
> // initialize stream
> + fprintf( stderr, "jpeg stream kind before: %d\n",
> int(str->getKind()) ); // StreamKind
> str = str->getNextStream();
> + fprintf( stderr, "jpeg stream kind after: %d\n",
> int(str->getKind()) ); // StreamKind
> str->reset();
>
> // copy the stream
> @@ -1345,6 +1347,47 @@ void HtmlOutputDev::drawPngImage(GfxState
> *state, Stream *str, int width, int he
> return;
> }
>
> + if (1) {
> + double x0, y0; // top left corner of image
> + double w0, h0, w1, h1; // size of image
> + double xt, yt, wt, ht;
> + GBool rotate, xFlip, yFlip;
> +
> + // get image position and size
> + state->transform(0, 0, &xt, &yt);
> + state->transformDelta(1, 1, &wt, &ht);
> + if (wt > 0) {
> + x0 = (xt);
> + w0 = (wt);
> + } else {
> + x0 = (xt + wt);
> + w0 = (-wt);
> + }
> + if (ht > 0) {
> + y0 = (yt);
> + h0 = (ht);
> + } else {
> + y0 = (yt + ht);
> + h0 = (-ht);
> + }
> + state->transformDelta(1, 0, &xt, &yt);
> + rotate = fabs(xt) < fabs(yt);
> + if (rotate) {
> + w1 = h0;
> + h1 = w0;
> + xFlip = ht < 0;
> + yFlip = wt > 0;
> + } else {
> + w1 = w0;
> + h1 = h0;
> + xFlip = wt < 0;
> + yFlip = ht > 0;
> + }
> + //fprintf( stderr, "image xFlip:%d yFlip:%d\n", int(xFlip),
> int(yFlip) ); // StreamKind
> +
> + if (yFlip) writer->setFlipY();
> + }
> +
> if (!isMask) {
> Guchar *p;
> GfxRGB rgb;
> @@ -1441,7 +1484,7 @@ void HtmlOutputDev::drawImageMask(GfxState
> *state, Object *ref, Stream *str,
> }
>
> // dump JPEG file
> - if (dumpJPEG && str->getKind() == strDCT) {
> + if (0 && dumpJPEG && str->getKind() == strDCT) {
> drawJpegImage(state, str);
> }
> else {
> @@ -1466,7 +1509,7 @@ void HtmlOutputDev::drawImage(GfxState *state,
> Object *ref, Stream *str,
> /*if( !globalParams->getErrQuiet() )
> printf("image stream of kind %d\n", str->getKind());*/
> // dump JPEG file
> - if (dumpJPEG && str->getKind() == strDCT) {
> + if (0 && dumpJPEG && str->getKind() == strDCT) {
> drawJpegImage(state, str);
> }
> else {
> _______________________________________________
> poppler mailing list
> poppler at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/poppler
More information about the poppler
mailing list