/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/* $Id$ */

package org.apache.fop.render.ps;

import java.awt.image.ColorModel;
import java.awt.image.IndexColorModel;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.zip.Deflater;
import java.util.zip.DeflaterOutputStream;
import java.util.zip.Inflater;
import java.util.zip.InflaterInputStream;

import org.apache.commons.io.IOUtils;

import org.apache.xmlgraphics.image.loader.impl.ImageRawPNG;
import org.apache.xmlgraphics.image.loader.impl.ImageRawStream;
import org.apache.xmlgraphics.ps.ImageEncoder;

ImageEncoder implementation for PNG images.
/** * ImageEncoder implementation for PNG images. */
public class ImageEncoderPNG implements ImageEncoder { private final ImageRawPNG image; private int numberOfInterleavedComponents;
Main constructor
Params:
  • image – the PNG image
/** * Main constructor * @param image the PNG image */
public ImageEncoderPNG(ImageRawPNG image) { this.image = image; ColorModel cm = this.image.getColorModel(); if (cm instanceof IndexColorModel) { numberOfInterleavedComponents = 1; } else { // this can be 1 (gray), 2 (gray + alpha), 3 (rgb) or 4 (rgb + alpha) // numberOfInterleavedComponents = (cm.hasAlpha() ? 1 : 0) + cm.getNumColorComponents(); numberOfInterleavedComponents = cm.getNumComponents(); } }
{@inheritDoc}
/** {@inheritDoc} */
public void writeTo(OutputStream out) throws IOException { // TODO: refactor this code with equivalent PDF code InputStream in = ((ImageRawStream) image).createInputStream(); InflaterInputStream infStream = null; DataInputStream dataStream = null; ByteArrayOutputStream baos = null; DeflaterOutputStream dos = null; try { if (numberOfInterleavedComponents == 1 || numberOfInterleavedComponents == 3) { // means we have Gray, RGB, or Palette IOUtils.copy(in, out); } else { // means we have Gray + alpha or RGB + alpha int numBytes = numberOfInterleavedComponents - 1; // 1 for Gray, 3 for RGB int numColumns = image.getSize().getWidthPx(); infStream = new InflaterInputStream(in, new Inflater()); dataStream = new DataInputStream(infStream); int offset = 0; int bytesPerRow = numberOfInterleavedComponents * numColumns; int filter; // here we need to inflate the PNG pixel data, which includes alpha, separate the alpha // channel and then deflate the RGB channels back again // TODO: not using the baos below and using the original out instead (as happens in PDF) // would be preferable but that does not work with the rest of the postscript code; this // needs to be revisited baos = new ByteArrayOutputStream(); dos = new DeflaterOutputStream(/* out */baos, new Deflater()); while ((filter = dataStream.read()) != -1) { byte[] bytes = new byte[bytesPerRow]; dataStream.readFully(bytes, 0, bytesPerRow); dos.write((byte) filter); for (int j = 0; j < numColumns; j++) { dos.write(bytes, offset, numBytes); offset += numberOfInterleavedComponents; } offset = 0; } dos.close(); IOUtils.copy(new ByteArrayInputStream(baos.toByteArray()), out); } } finally { IOUtils.closeQuietly(dos); IOUtils.closeQuietly(baos); IOUtils.closeQuietly(dataStream); IOUtils.closeQuietly(infStream); IOUtils.closeQuietly(in); } }
{@inheritDoc}
/** {@inheritDoc} */
public String getImplicitFilter() { String filter = "<< /Predictor 15 /Columns " + image.getSize().getWidthPx(); filter += " /Colors " + (numberOfInterleavedComponents > 2 ? 3 : 1); filter += " /BitsPerComponent " + image.getBitDepth() + " >> /FlateDecode"; return filter; } }