You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@pdfbox.apache.org by Gert van Spijker <ge...@ab-graph.com> on 2012/02/22 22:34:50 UTC

Re: Offer to try to fix the broken "PDPixelMap from BufferedImage" and some Eclipse questions

Thanks for the hints Andreas,

I actually made already some progress and have a constructor that works,
at least for plain vanilla RGB which is with which I tested.

What I did was use the 1.6 stable jar and created a new implementation
of PDPixelMap within my own package.
I then copied the PDPixelMap source code from the development trunk and
uncommented the broken constructor.
I then modified my calling code, that was up to then was creating a
PDJpeg, to create a PDPixelmap instance and tested.
It actually did produce visible output in the Linux Evince reader that I
use, but it was immediately evident that there was an issue with the
colour space.

It turned out that there are 2 things wrong:

setBitsPerComponent is called erroneously with ColorModel.getPixelSize()
instead of ColorModel.getComponentSize()
so it sets an illegal BitsPerComponent whem an image has more than 1
component.

In case of RGB images the colour channel order is inverse, so the R and
B components have to be swapped.

I have fixed these 2 issues in my version of the constructor and I get
correct RGB images. I did not yet test other image formats and I expect
to find more problems.

It is to early to submit a patch, but here is my version of the
constructor, in case others want to continue with that:

	/*
	 * This fix has only been tested with RGB input so far.
	 */
	public PDPixelMap(PDDocument doc, BufferedImage awtImage) throws
IOException {
		super(doc, "png");
		image = awtImage;
		setWidth(image.getWidth());
		setHeight(image.getHeight());

		ColorModel cm = image.getColorModel();
		// Use the size of the first channel, which should be the same for all
		setBitsPerComponent(cm.getComponentSize(0));
		ColorSpace cs = cm.getColorSpace();
		PDColorSpace pdColorSpace = PDColorSpaceFactory.createColorSpace(doc, cs);
		setColorSpace(pdColorSpace);

		PDStream stream = getPDStream();
		List<COSName> filters = new ArrayList<COSName>();
		filters.add(COSName.FLATE_DECODE);
		stream.setFilters(filters);

		OutputStream output = null;
		try {
			output = stream.createOutputStream();

			// In case of RGB images we must swap R and B.
			if (cm.getNumColorComponents() == 3) {
				// Check if we have an alpha channel, which determines whether we have
				// to output the fourth byte or not.
				boolean hasAlpha = cm.hasAlpha();
				int width = getWidth();
				int height = getHeight();
				int size = width * height;
				int[] rgbArray = new int[size];

				image.getRGB(0, 0, width, height, rgbArray, 0, width);

				for (int n = 0; n < size; n++) {
					output.write((byte) (rgbArray[n] >> 16));
					output.write((byte) (rgbArray[n] >> 8));
					output.write((byte) (rgbArray[n] >> 0));
					if(hasAlpha)
						output.write((byte) (rgbArray[n] >> 24));
				}
			} else {
				// Not an RGB image so just copy the data buffer for now.
				DataBuffer buffer = awtImage.getRaster().getDataBuffer();
				if (buffer instanceof DataBufferByte) {
					DataBufferByte byteBuffer = (DataBufferByte) buffer;
					byte[] data = byteBuffer.getData();
					output.write(data);
				}
			}

		} finally {
			if (output != null) {
				output.close();
			}
		}
	}

Of course I am open to debug and test more and will do anyway, but I
just thought I'd post the intermediate results of my efforts.

Gert

On 22/02/12 18:28, Andreas Lehmkuehler wrote:
> Hi,
> 
> sorry for the late answer...
> 
> Am 18.02.2012 11:55, schrieb Gert van Spijker:
>> I just signed up for this list, because I would like to start
>> contributing to PDFBox. Actually, I'd like to attack the problem with
>> the broken constructor:
>>
>> PDPixelMap(PDDocument doc, BufferedImage awtImage)
>>
>> In the comment I read: "This method is broken and needs to be
>> implemented, any takers?"
>>
>> My answer to this question is: Yes why not, I'll give it a try..
>>
>> We are using PDFBox in our prepress product, and I'd like to be able to
>> create a lossless image directly from a PDF without having to go through
>> JAI.
> Welcome to our community
> 
>> But before I start I have 2 questions:
>>
>> 1: Who is the current developer with the most knowledge about this bug?
>> I'd like to get as much information about the problem as possible.
> We prefer to discuss everything on the dev mailing list, as all
> developers are subscribed to it.
> I guess the problem with the mentioned constructor was, that it simply
> didn't work. If you like to (re)implement it you may consider the following
> 
> - read the pdf specs to find out how pixelmaps in pdfs are working
> - have a look at PDPixelMap#getRGBImage, it does the decoding
> - have a look at the implementation of PDJpeg#createImageStream, yours
> maybe similar to it
> 
>> 2: I am using Eclipse for development, and checked out trunk through
>> SVN, but when letting it build through Eclipse auto build I stumble
>> across all the missing outside dependencies. I understand that using
>> Maven makes feature selection very simple, but can this be controlled
>> from inside Eclipse? for example by installing the Maven plugin?
>> Does anybody have any experience with building/debugging the PDF core
>> with Eclipse?
> Just install the m2e plugin [1], that should do the trick.
> 
> BR
> Andreas Lehmkühler
> 
> [1] http://www.eclipse.org/m2e
> 
>