org.apache.commons.imaging.common.PackBits Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of commons-imaging Show documentation
Show all versions of commons-imaging Show documentation
Apache Commons Imaging (previously Sanselan) is a pure-Java image library.
The newest version!
/*
* 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.common;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import org.apache.commons.imaging.ImageReadException;
public class PackBits {
public byte[] decompress(final byte[] bytes, final int expected)
throws ImageReadException {
int total = 0;
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
// Loop until you get the number of unpacked bytes you are expecting:
int i = 0;
while (total < expected) {
// Read the next source byte into n.
if (i >= bytes.length) {
throw new ImageReadException(
"Tiff: Unpack bits source exhausted: " + i
+ ", done + " + total + ", expected + "
+ expected);
}
final int n = bytes[i++];
if ((n >= 0) && (n <= 127)) {
// If n is between 0 and 127 inclusive, copy the next n+1 bytes
// literally.
final int count = n + 1;
total += count;
for (int j = 0; j < count; j++) {
baos.write(bytes[i++]);
}
} else if ((n >= -127) && (n <= -1)) {
// Else if n is between -127 and -1 inclusive, copy the next byte
// -n+1 times.
final int b = bytes[i++];
final int count = -n + 1;
total += count;
for (int j = 0; j < count; j++) {
baos.write(b);
}
} else if (n == -128) {
// Else if n is -128, noop.
throw new ImageReadException("Packbits: " + n);
}
}
return baos.toByteArray();
}
private int findNextDuplicate(final byte[] bytes, final int start) {
// int last = -1;
if (start >= bytes.length) {
return -1;
}
byte prev = bytes[start];
for (int i = start + 1; i < bytes.length; i++) {
final byte b = bytes[i];
if (b == prev) {
return i - 1;
}
prev = b;
}
return -1;
}
private int findRunLength(final byte[] bytes, final int start) {
final byte b = bytes[start];
int i;
for (i = start + 1; (i < bytes.length) && (bytes[i] == b); i++) {
// do nothing
}
return i - start;
}
public byte[] compress(final byte[] bytes) throws IOException {
// max length 1 extra byte for every 128
try (FastByteArrayOutputStream baos = new FastByteArrayOutputStream(bytes.length * 2)) {
int ptr = 0;
while (ptr < bytes.length) {
int dup = findNextDuplicate(bytes, ptr);
if (dup == ptr) {
// write run length
final int len = findRunLength(bytes, dup);
final int actualLen = Math.min(len, 128);
baos.write(-(actualLen - 1));
baos.write(bytes[ptr]);
ptr += actualLen;
} else {
// write literals
int len = dup - ptr;
if (dup > 0) {
final int runlen = findRunLength(bytes, dup);
if (runlen < 3) {
// may want to discard next run.
final int nextptr = ptr + len + runlen;
final int nextdup = findNextDuplicate(bytes, nextptr);
if (nextdup != nextptr) {
// discard 2-byte run
dup = nextdup;
len = dup - ptr;
}
}
}
if (dup < 0) {
len = bytes.length - ptr;
}
final int actualLen = Math.min(len, 128);
baos.write(actualLen - 1);
for (int i = 0; i < actualLen; i++) {
baos.write(bytes[ptr]);
ptr++;
}
}
}
final byte[] result = baos.toByteArray();
return result;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy