1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.imaging.formats.dcx;
18
19 import static org.apache.commons.imaging.common.BinaryFunctions.read4Bytes;
20
21 import java.awt.Dimension;
22 import java.awt.image.BufferedImage;
23 import java.io.IOException;
24 import java.io.InputStream;
25 import java.io.OutputStream;
26 import java.io.PrintWriter;
27 import java.nio.ByteOrder;
28 import java.util.ArrayList;
29 import java.util.List;
30
31 import org.apache.commons.imaging.AbstractImageParser;
32 import org.apache.commons.imaging.ImageFormat;
33 import org.apache.commons.imaging.ImageFormats;
34 import org.apache.commons.imaging.ImageInfo;
35 import org.apache.commons.imaging.ImagingException;
36 import org.apache.commons.imaging.bytesource.ByteSource;
37 import org.apache.commons.imaging.common.AbstractBinaryOutputStream;
38 import org.apache.commons.imaging.common.Allocator;
39 import org.apache.commons.imaging.common.ImageMetadata;
40 import org.apache.commons.imaging.formats.pcx.PcxImageParser;
41 import org.apache.commons.imaging.formats.pcx.PcxImagingParameters;
42
43 public class DcxImageParser extends AbstractImageParser<PcxImagingParameters> {
44 private static final class DcxHeader {
45
46 public static final int DCX_ID = 0x3ADE68B1;
47 public final int id;
48 public final long[] pageTable;
49
50 DcxHeader(final int id, final long[] pageTable) {
51 this.id = id;
52 this.pageTable = pageTable;
53 }
54
55 public void dump(final PrintWriter pw) {
56 pw.println("DcxHeader");
57 pw.println("Id: 0x" + Integer.toHexString(id));
58 pw.println("Pages: " + pageTable.length);
59 pw.println();
60 }
61 }
62
63
64 private static final String DEFAULT_EXTENSION = ImageFormats.DCX.getDefaultExtension();
65
66 private static final String[] ACCEPTED_EXTENSIONS = ImageFormats.DCX.getExtensions();
67
68
69
70
71 public DcxImageParser() {
72 super(ByteOrder.LITTLE_ENDIAN);
73 }
74
75 @Override
76 public boolean dumpImageFile(final PrintWriter pw, final ByteSource byteSource) throws ImagingException, IOException {
77 readDcxHeader(byteSource).dump(pw);
78 return true;
79 }
80
81 @Override
82 protected String[] getAcceptedExtensions() {
83 return ACCEPTED_EXTENSIONS;
84 }
85
86 @Override
87 protected ImageFormat[] getAcceptedTypes() {
88 return new ImageFormat[] { ImageFormats.DCX };
89 }
90
91 @Override
92 public List<BufferedImage> getAllBufferedImages(final ByteSource byteSource) throws ImagingException, IOException {
93 final DcxHeader dcxHeader = readDcxHeader(byteSource);
94 final List<BufferedImage> images = new ArrayList<>();
95 final PcxImageParser pcxImageParser = new PcxImageParser();
96 for (final long element : dcxHeader.pageTable) {
97 try (InputStream stream = ByteSource.getInputStream(byteSource, element)) {
98 images.add(pcxImageParser.getBufferedImage(ByteSource.inputStream(stream, null), new PcxImagingParameters()));
99 }
100 }
101 return images;
102 }
103
104 @Override
105 public final BufferedImage getBufferedImage(final ByteSource byteSource, final PcxImagingParameters params) throws ImagingException, IOException {
106 final List<BufferedImage> list = getAllBufferedImages(byteSource);
107 return list.isEmpty() ? null : list.get(0);
108 }
109
110 @Override
111 public String getDefaultExtension() {
112 return DEFAULT_EXTENSION;
113 }
114
115 @Override
116 public PcxImagingParameters getDefaultParameters() {
117 return new PcxImagingParameters();
118 }
119
120
121 @Override
122 public byte[] getIccProfileBytes(final ByteSource byteSource, final PcxImagingParameters params) throws ImagingException, IOException {
123 return null;
124 }
125
126
127 @Override
128 public ImageInfo getImageInfo(final ByteSource byteSource, final PcxImagingParameters params) throws ImagingException, IOException {
129 return null;
130 }
131
132
133 @Override
134 public Dimension getImageSize(final ByteSource byteSource, final PcxImagingParameters params) throws ImagingException, IOException {
135 return null;
136 }
137
138
139 @Override
140 public ImageMetadata getMetadata(final ByteSource byteSource, final PcxImagingParameters params) throws ImagingException, IOException {
141 return null;
142 }
143
144 @Override
145 public String getName() {
146 return "Dcx-Custom";
147 }
148
149 private DcxHeader readDcxHeader(final ByteSource byteSource) throws ImagingException, IOException {
150 try (InputStream is = byteSource.getInputStream()) {
151 final int id = read4Bytes("Id", is, "Not a Valid DCX File", getByteOrder());
152 final int size = 1024;
153 final List<Long> pageTable = Allocator.arrayList(size);
154 for (int i = 0; i < size; i++) {
155 final long pageOffset = 0xFFFFffffL & read4Bytes("PageTable", is, "Not a Valid DCX File", getByteOrder());
156 if (pageOffset == 0) {
157 break;
158 }
159 pageTable.add(pageOffset);
160 }
161
162 if (id != DcxHeader.DCX_ID) {
163 throw new ImagingException("Not a Valid DCX File: file id incorrect");
164 }
165 if (pageTable.size() == size) {
166 throw new ImagingException("DCX page table not terminated by zero entry");
167 }
168
169 final long[] pages = pageTable.stream().mapToLong(Long::longValue).toArray();
170 return new DcxHeader(id, pages);
171 }
172 }
173
174 @Override
175 public void writeImage(final BufferedImage src, final OutputStream os, final PcxImagingParameters params) throws ImagingException, IOException {
176 final int headerSize = 4 + 1024 * 4;
177
178 @SuppressWarnings("resource")
179 final AbstractBinaryOutputStream bos = AbstractBinaryOutputStream.littleEndian(os);
180 bos.write4Bytes(DcxHeader.DCX_ID);
181
182 bos.write4Bytes(headerSize);
183 for (int i = 0; i < 1023; i++) {
184 bos.write4Bytes(0);
185 }
186 new PcxImageParser().writeImage(src, bos, params);
187 }
188 }