diff --git a/pom.xml b/pom.xml index d1e4815..1f5d5e1 100644 --- a/pom.xml +++ b/pom.xml @@ -1,18 +1,19 @@ - + 4.0.0 a2geek.apple2 apple2-image-encoder - 4.4.0-FINAL + 5.0.0-SNAPSHOT Apple II Image Encoder A utility that got out of hand and became an application to move modern images to the Apple II platform. - + 1.8 1.8 - 2.4.3 + 3.0.0 4.12 + 1.14 @@ -22,6 +23,23 @@ ${junit.version} test + + org.apache.commons + commons-compress + ${commons-compress.version} + + + org.brotli + dec + 0.1.2 + true + + + org.tukaani + xz + 1.6 + true + @@ -52,4 +70,5 @@ - \ No newline at end of file + + \ No newline at end of file diff --git a/src/main/java/a2geek/apple2/image/encoder/encode/A2EncoderFactory.java b/src/main/java/a2geek/apple2/image/encoder/encode/A2EncoderFactory.java new file mode 100644 index 0000000..24ec285 --- /dev/null +++ b/src/main/java/a2geek/apple2/image/encoder/encode/A2EncoderFactory.java @@ -0,0 +1,27 @@ +package a2geek.apple2.image.encoder.encode; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.commons.compress.compressors.CompressorStreamFactory; + +public abstract class A2EncoderFactory { + public static List getEncoders() { + List list = new ArrayList<>(); + list.add(new RleEncoder()); + list.add(new VariableRleEncoder()); + list.add(new PackBitsEncoder()); + list.add(new BitPack1()); + list.add(new BitPack2()); + list.add(new BitPack3()); + list.add(new GZipEncoder()); + list.add(new ZipEncoder()); + // From Apache Commons + for (String outputProvider : CompressorStreamFactory.findAvailableCompressorOutputStreamProviders().keySet()) { + // PACK200 does nothing for some reason, so just ignoring it + if (CompressorStreamFactory.PACK200.equals(outputProvider)) continue; + list.add(new CommonsCodecEncoder(outputProvider)); + } + return list; + } +} diff --git a/src/main/java/a2geek/apple2/image/encoder/encode/CommonsCodecEncoder.java b/src/main/java/a2geek/apple2/image/encoder/encode/CommonsCodecEncoder.java new file mode 100644 index 0000000..f8e97f8 --- /dev/null +++ b/src/main/java/a2geek/apple2/image/encoder/encode/CommonsCodecEncoder.java @@ -0,0 +1,48 @@ +package a2geek.apple2.image.encoder.encode; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; + +import org.apache.commons.compress.compressors.CompressorException; +import org.apache.commons.compress.compressors.CompressorOutputStream; +import org.apache.commons.compress.compressors.CompressorStreamFactory; +import org.apache.commons.compress.compressors.CompressorStreamProvider; + +import a2geek.apple2.image.encoder.A2Image; +import a2geek.apple2.image.encoder.ui.ImageEncoderApp; + +public class CommonsCodecEncoder extends A2Encoder { + private CompressorStreamProvider provider = new CompressorStreamFactory(); + private String name; + private String title; + + public CommonsCodecEncoder(String name) { + this(name, name.toUpperCase()); + } + public CommonsCodecEncoder(String name, String title) { + this.name = name; + this.title = title; + } + + @Override + public void encode(A2Image a2image, int maxSize) { + try { + reset(maxSize); + ByteArrayOutputStream ba = new ByteArrayOutputStream(); + CompressorOutputStream out = provider.createCompressorOutputStream(name, ba); + out.write(a2image.getBytes()); + out.close(); + for (byte b : ba.toByteArray()) { + addByte(b); + } + } catch (CompressorException | IOException ex) { + ImageEncoderApp.showErrorDialog("Apache Commons '" + name + "' compress", ex); + } + } + + @Override + public String getTitle() { + return title; + } + +} diff --git a/src/main/java/a2geek/apple2/image/encoder/ui/EncoderTableModel.java b/src/main/java/a2geek/apple2/image/encoder/ui/EncoderTableModel.java index b630807..9cb1ee5 100644 --- a/src/main/java/a2geek/apple2/image/encoder/ui/EncoderTableModel.java +++ b/src/main/java/a2geek/apple2/image/encoder/ui/EncoderTableModel.java @@ -7,14 +7,7 @@ import javax.swing.table.AbstractTableModel; import a2geek.apple2.image.encoder.A2Image; import a2geek.apple2.image.encoder.encode.A2Encoder; -import a2geek.apple2.image.encoder.encode.BitPack1; -import a2geek.apple2.image.encoder.encode.BitPack2; -import a2geek.apple2.image.encoder.encode.BitPack3; -import a2geek.apple2.image.encoder.encode.GZipEncoder; -import a2geek.apple2.image.encoder.encode.PackBitsEncoder; -import a2geek.apple2.image.encoder.encode.RleEncoder; -import a2geek.apple2.image.encoder.encode.VariableRleEncoder; -import a2geek.apple2.image.encoder.encode.ZipEncoder; +import a2geek.apple2.image.encoder.encode.A2EncoderFactory; import a2geek.apple2.image.encoder.util.ProgressListener; /** @@ -25,7 +18,7 @@ import a2geek.apple2.image.encoder.util.ProgressListener; */ @SuppressWarnings("serial") public class EncoderTableModel extends AbstractTableModel { - private List encoders = new ArrayList(); + private final List results = new ArrayList<>(); private byte[] data = null; private String[] headers = new String[] { "Type", "Original", "Compressed", "%" }; /** @@ -33,30 +26,18 @@ public class EncoderTableModel extends AbstractTableModel { */ public EncoderTableModel(A2Image image, int maxSize, ProgressListener listener) { this.data = image.getBytes(); - - Class[] encoderClasses = new Class[] { - RleEncoder.class, - VariableRleEncoder.class, - PackBitsEncoder.class, - BitPack1.class, - BitPack2.class, - BitPack3.class, - GZipEncoder.class, - ZipEncoder.class - }; + int count = 0; - for (Class encoderClass : encoderClasses) { - if (listener != null && listener.isCancelled()) return; - A2Encoder a2encoder = null; + int size = A2EncoderFactory.getEncoders().size(); + for (A2Encoder encoder : A2EncoderFactory.getEncoders()) { try { - a2encoder = (A2Encoder)encoderClass.newInstance(); + if (listener != null && listener.isCancelled()) return; count++; - if (listener != null) listener.update(count, encoderClasses.length, a2encoder.getTitle()); - a2encoder.encode(image, maxSize); - encoders.add(a2encoder); + if (listener != null) listener.update(count, size, encoder.getTitle()); + encoder.encode(image, maxSize); + results.add(encoder); } catch (Throwable t) { - // FIXME ignore errors... - //ImageEncoderApp.showErrorDialog(a2encoder.getTitle(), t); + // Ignoring these as some are expected to throw errors if boundaries are missed } } } @@ -70,7 +51,7 @@ public class EncoderTableModel extends AbstractTableModel { * Answer with the number of rows. */ public int getRowCount() { - return encoders.size(); + return results.size(); } /** * Answer with the number of columns. @@ -84,13 +65,13 @@ public class EncoderTableModel extends AbstractTableModel { public Object getValueAt(int rowIndex, int columnIndex) { switch (columnIndex) { case 0: - return encoders.get(rowIndex).getTitle(); + return results.get(rowIndex).getTitle(); case 1: return data.length; case 2: - return encoders.get(rowIndex).getSize(); + return results.get(rowIndex).getSize(); case 3: - return (encoders.get(rowIndex).getSize() * 100) / data.length; + return (results.get(rowIndex).getSize() * 100) / data.length; default: return "Unknown"; } @@ -116,6 +97,6 @@ public class EncoderTableModel extends AbstractTableModel { * Answer with the specific A2Encoder. */ public A2Encoder getSelectedEncoder(int rowIndex) { - return encoders.get(rowIndex); + return results.get(rowIndex); } }