blob: ed44d01588348511c1baff68a490a36d6057e842 [file] [log] [blame]
/*
* 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(byte bytes[], int expected)
throws ImageReadException
{
int total = 0;
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);
int n = bytes[i++];
// If n is between 0 and 127 inclusive, copy the next n+1 bytes literally.
if ((n >= 0) && (n <= 127))
{
int count = n + 1;
total += count;
for (int j = 0; j < count; j++)
baos.write(bytes[i++]);
}
// Else if n is between -127 and -1 inclusive, copy the next byte -n+1
// times.
else if ((n >= -127) && (n <= -1))
{
int b = bytes[i++];
int count = -n + 1;
total += count;
for (int j = 0; j < count; j++)
baos.write(b);
}
else if (n == -128)
throw new ImageReadException("Packbits: " + n);
// Else if n is between -127 and -1 inclusive, copy the next byte -n+1
// times.
// else
// Else if n is -128, noop.
}
byte result[] = baos.toByteArray();
return result;
}
private int findNextDuplicate(byte bytes[], int start)
{
// int last = -1;
if (start >= bytes.length)
return -1;
byte prev = bytes[start];
for (int i = start + 1; i < bytes.length; i++)
{
byte b = bytes[i];
if (b == prev)
return i - 1;
prev = b;
}
return -1;
}
private int findRunLength(byte bytes[], int start)
{
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(byte bytes[]) throws IOException
{
MyByteArrayOutputStream baos = new MyByteArrayOutputStream(
bytes.length * 2); // max length 1 extra byte for every 128
int ptr = 0;
int count = 0;
while (ptr < bytes.length)
{
count++;
int dup = findNextDuplicate(bytes, ptr);
if (dup == ptr) // write run length
{
int len = findRunLength(bytes, dup);
int actual_len = Math.min(len, 128);
baos.write(-(actual_len - 1));
baos.write(bytes[ptr]);
ptr += actual_len;
}
else
{ // write literals
int len = dup - ptr;
if (dup > 0)
{
int runlen = findRunLength(bytes, dup);
if (runlen < 3) // may want to discard next run.
{
int nextptr = ptr + len + runlen;
int nextdup = findNextDuplicate(bytes, nextptr);
if (nextdup != nextptr) // discard 2-byte run
{
dup = nextdup;
len = dup - ptr;
}
}
}
if (dup < 0)
len = bytes.length - ptr;
int actual_len = Math.min(len, 128);
baos.write(actual_len - 1);
for (int i = 0; i < actual_len; i++)
{
baos.write(bytes[ptr]);
ptr++;
}
}
}
byte result[] = baos.toByteArray();
return result;
}
}