| /* |
| * 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. |
| */ |
| package org.apache.commons.imaging.formats.dcx; |
| |
| import java.awt.Dimension; |
| import java.awt.image.BufferedImage; |
| import java.io.File; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.io.OutputStream; |
| import java.io.PrintWriter; |
| import java.util.ArrayList; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Map; |
| |
| import org.apache.commons.imaging.ImageFormat; |
| import org.apache.commons.imaging.ImageFormats; |
| import org.apache.commons.imaging.ImageInfo; |
| import org.apache.commons.imaging.ImageParser; |
| import org.apache.commons.imaging.ImageReadException; |
| import org.apache.commons.imaging.ImageWriteException; |
| import org.apache.commons.imaging.PixelDensity; |
| import org.apache.commons.imaging.common.BinaryOutputStream; |
| import org.apache.commons.imaging.common.ByteOrder; |
| import org.apache.commons.imaging.common.IImageMetadata; |
| import org.apache.commons.imaging.common.bytesource.ByteSource; |
| import org.apache.commons.imaging.common.bytesource.ByteSourceInputStream; |
| import org.apache.commons.imaging.formats.pcx.PcxConstants; |
| import org.apache.commons.imaging.formats.pcx.PcxImageParser; |
| import org.apache.commons.imaging.util.IoUtils; |
| |
| public class DcxImageParser extends ImageParser { |
| // See http://www.fileformat.info/format/pcx/egff.htm for documentation |
| |
| public DcxImageParser() { |
| super.setByteOrder(ByteOrder.INTEL); |
| } |
| |
| @Override |
| public String getName() { |
| return "Dcx-Custom"; |
| } |
| |
| @Override |
| public String getDefaultExtension() { |
| return DEFAULT_EXTENSION; |
| } |
| |
| private static final String DEFAULT_EXTENSION = ".dcx"; |
| private static final String ACCEPTED_EXTENSIONS[] = { ".dcx", }; |
| |
| @Override |
| protected String[] getAcceptedExtensions() { |
| return ACCEPTED_EXTENSIONS; |
| } |
| |
| @Override |
| protected ImageFormat[] getAcceptedTypes() { |
| return new ImageFormat[] { |
| ImageFormats.DCX, // |
| }; |
| } |
| |
| @Override |
| public boolean embedICCProfile(final File src, final File dst, final byte profile[]) { |
| return false; |
| } |
| |
| @Override |
| public IImageMetadata getMetadata(final ByteSource byteSource, final Map<String,Object> params) |
| throws ImageReadException, IOException { |
| return null; |
| } |
| |
| @Override |
| public ImageInfo getImageInfo(final ByteSource byteSource, final Map<String,Object> params) |
| throws ImageReadException, IOException { |
| return null; |
| } |
| |
| @Override |
| public Dimension getImageSize(final ByteSource byteSource, final Map<String,Object> params) |
| throws ImageReadException, IOException { |
| return null; |
| } |
| |
| @Override |
| public byte[] getICCProfileBytes(final ByteSource byteSource, final Map<String,Object> params) |
| throws ImageReadException, IOException { |
| return null; |
| } |
| |
| private static class DcxHeader { |
| |
| public static final int DCX_ID = 0x3ADE68B1; |
| public final int id; |
| public final long[] pageTable; |
| |
| public DcxHeader(final int id, final long[] pageTable) { |
| this.id = id; |
| this.pageTable = pageTable; |
| } |
| |
| public void dump(final PrintWriter pw) { |
| pw.println("DcxHeader"); |
| pw.println("Id: 0x" + Integer.toHexString(id)); |
| pw.println("Pages: " + pageTable.length); |
| pw.println(); |
| } |
| } |
| |
| private DcxHeader readDcxHeader(final ByteSource byteSource) |
| throws ImageReadException, IOException { |
| InputStream is = null; |
| boolean canThrow = false; |
| try { |
| is = byteSource.getInputStream(); |
| final int id = read4Bytes("Id", is, "Not a Valid DCX File"); |
| final List<Long> pageTable = new ArrayList<Long>(1024); |
| for (int i = 0; i < 1024; i++) { |
| final long pageOffset = 0xFFFFffffL & read4Bytes("PageTable", is, |
| "Not a Valid DCX File"); |
| if (pageOffset == 0) { |
| break; |
| } |
| pageTable.add(pageOffset); |
| } |
| |
| if (id != DcxHeader.DCX_ID) { |
| throw new ImageReadException( |
| "Not a Valid DCX File: file id incorrect"); |
| } |
| if (pageTable.size() == 1024) { |
| throw new ImageReadException( |
| "DCX page table not terminated by zero entry"); |
| } |
| |
| final Object[] objects = pageTable.toArray(); |
| final long[] pages = new long[objects.length]; |
| for (int i = 0; i < objects.length; i++) { |
| pages[i] = ((Long) objects[i]); |
| } |
| |
| final DcxHeader ret = new DcxHeader(id, pages); |
| canThrow = true; |
| return ret; |
| } finally { |
| IoUtils.closeQuietly(canThrow, is); |
| } |
| } |
| |
| @Override |
| public boolean dumpImageFile(final PrintWriter pw, final ByteSource byteSource) |
| throws ImageReadException, IOException { |
| readDcxHeader(byteSource).dump(pw); |
| return true; |
| } |
| |
| @Override |
| public final BufferedImage getBufferedImage(final ByteSource byteSource, |
| final Map<String,Object> params) throws ImageReadException, IOException { |
| final List<BufferedImage> list = getAllBufferedImages(byteSource); |
| if (list.isEmpty()) { |
| return null; |
| } |
| return list.get(0); |
| } |
| |
| @Override |
| public List<BufferedImage> getAllBufferedImages(final ByteSource byteSource) |
| throws ImageReadException, IOException { |
| final DcxHeader dcxHeader = readDcxHeader(byteSource); |
| final List<BufferedImage> images = new ArrayList<BufferedImage>(); |
| final PcxImageParser pcxImageParser = new PcxImageParser(); |
| for (final long element : dcxHeader.pageTable) { |
| InputStream stream = null; |
| boolean canThrow = false; |
| try { |
| stream = byteSource.getInputStream(element); |
| final ByteSourceInputStream pcxSource = new ByteSourceInputStream( |
| stream, null); |
| final BufferedImage image = pcxImageParser.getBufferedImage( |
| pcxSource, new HashMap<String,Object>()); |
| images.add(image); |
| canThrow = true; |
| } finally { |
| IoUtils.closeQuietly(canThrow, stream); |
| } |
| } |
| return images; |
| } |
| |
| @Override |
| public void writeImage(final BufferedImage src, final OutputStream os, Map<String,Object> params) |
| throws ImageWriteException, IOException { |
| // make copy of params; we'll clear keys as we consume them. |
| params = (params == null) ? new HashMap<String,Object>() : new HashMap<String,Object>(params); |
| |
| final HashMap<String,Object> pcxParams = new HashMap<String,Object>(); |
| |
| // clear format key. |
| if (params.containsKey(PARAM_KEY_FORMAT)) { |
| params.remove(PARAM_KEY_FORMAT); |
| } |
| |
| if (params.containsKey(PcxConstants.PARAM_KEY_PCX_COMPRESSION)) { |
| final Object value = params |
| .remove(PcxConstants.PARAM_KEY_PCX_COMPRESSION); |
| pcxParams.put(PcxConstants.PARAM_KEY_PCX_COMPRESSION, value); |
| } |
| |
| if (params.containsKey(PARAM_KEY_PIXEL_DENSITY)) { |
| final Object value = params.remove(PARAM_KEY_PIXEL_DENSITY); |
| if (value != null) { |
| if (!(value instanceof PixelDensity)) { |
| throw new ImageWriteException( |
| "Invalid pixel density parameter"); |
| } |
| pcxParams.put(PARAM_KEY_PIXEL_DENSITY, value); |
| } |
| } |
| |
| |
| if (params.size() > 0) { |
| final Object firstKey = params.keySet().iterator().next(); |
| throw new ImageWriteException("Unknown parameter: " + firstKey); |
| } |
| |
| final int headerSize = 4 + 1024 * 4; |
| |
| final BinaryOutputStream bos = new BinaryOutputStream(os, |
| ByteOrder.INTEL); |
| bos.write4Bytes(DcxHeader.DCX_ID); |
| // Some apps may need a full 1024 entry table |
| bos.write4Bytes(headerSize); |
| for (int i = 0; i < 1023; i++) { |
| bos.write4Bytes(0); |
| } |
| final PcxImageParser pcxImageParser = new PcxImageParser(); |
| pcxImageParser.writeImage(src, bos, pcxParams); |
| } |
| |
| /** |
| * Extracts embedded XML metadata as XML string. |
| * <p> |
| * |
| * @param byteSource |
| * File containing image data. |
| * @param params |
| * Map of optional parameters, defined in ImagingConstants. |
| * @return Xmp Xml as String, if present. Otherwise, returns null. |
| */ |
| @Override |
| public String getXmpXml(final ByteSource byteSource, final Map<String,Object> params) |
| throws ImageReadException, IOException { |
| return null; |
| } |
| } |