[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