1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.imaging.common;
18
19 import java.io.ByteArrayOutputStream;
20 import java.io.IOException;
21
22 import org.apache.commons.imaging.ImagingException;
23 import org.apache.commons.io.output.UnsynchronizedByteArrayOutputStream;
24
25 public final class PackBits {
26
27 public static byte[] compress(final byte[] bytes) throws IOException {
28
29 try (UnsynchronizedByteArrayOutputStream baos = UnsynchronizedByteArrayOutputStream.builder().setBufferSize(Allocator.checkByteArray(bytes.length * 2))
30 .get()) {
31 int ptr = 0;
32 while (ptr < bytes.length) {
33 int dup = findNextDuplicate(bytes, ptr);
34
35 if (dup == ptr) {
36
37 final int len = findRunLength(bytes, dup);
38 final int actualLen = Math.min(len, 128);
39 baos.write(-(actualLen - 1));
40 baos.write(bytes[ptr]);
41 ptr += actualLen;
42 } else {
43
44 int len = dup - ptr;
45
46 if (dup > 0) {
47 final int runlen = findRunLength(bytes, dup);
48 if (runlen < 3) {
49
50 final int nextptr = ptr + len + runlen;
51 final int nextdup = findNextDuplicate(bytes, nextptr);
52 if (nextdup != nextptr) {
53
54 dup = nextdup;
55 len = dup - ptr;
56 }
57 }
58 }
59
60 if (dup < 0) {
61 len = bytes.length - ptr;
62 }
63 final int actualLen = Math.min(len, 128);
64
65 baos.write(actualLen - 1);
66 for (int i = 0; i < actualLen; i++) {
67 baos.write(bytes[ptr]);
68 ptr++;
69 }
70 }
71 }
72 return baos.toByteArray();
73 }
74 }
75
76 public static byte[] decompress(final byte[] bytes, final int expected) throws ImagingException {
77 int total = 0;
78
79 final ByteArrayOutputStream baos = new ByteArrayOutputStream();
80
81
82 int i = 0;
83 while (total < expected) {
84
85 if (i >= bytes.length) {
86 throw new ImagingException("Tiff: Unpack bits source exhausted: " + i + ", done + " + total + ", expected + " + expected);
87 }
88
89 final int n = bytes[i++];
90 if (n >= 0 && n <= 127) {
91
92
93 final int count = n + 1;
94
95 total += count;
96 for (int j = 0; j < count; j++) {
97 baos.write(bytes[i++]);
98 }
99 } else if (n >= -127 && n <= -1) {
100
101
102
103 final int b = bytes[i++];
104 final int count = -n + 1;
105
106 total += count;
107 for (int j = 0; j < count; j++) {
108 baos.write(b);
109 }
110 } else if (n == -128) {
111
112 throw new ImagingException("Packbits: " + n);
113 }
114 }
115
116 return baos.toByteArray();
117
118 }
119
120 private static int findNextDuplicate(final byte[] bytes, final int start) {
121
122 if (start >= bytes.length) {
123 return -1;
124 }
125
126 byte prev = bytes[start];
127
128 for (int i = start + 1; i < bytes.length; i++) {
129 final byte b = bytes[i];
130
131 if (b == prev) {
132 return i - 1;
133 }
134
135 prev = b;
136 }
137
138 return -1;
139 }
140
141 private static int findRunLength(final byte[] bytes, final int start) {
142 final byte b = bytes[start];
143
144 int i;
145
146 for (i = start + 1; i < bytes.length && bytes[i] == b; i++) {
147
148 }
149
150 return i - start;
151 }
152
153 private PackBits() {
154
155 }
156 }