From d647d0afe9a55ed2dc81bbaf08297c329eeb0148 Mon Sep 17 00:00:00 2001 From: Michael Pfeiffer Date: Sun, 16 Jan 2005 12:01:25 +0000 Subject: [PATCH] Implemented Delta Row Compression. git-svn-id: file:///srv/svn/repos/haiku/trunk/current@10775 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- .../drivers/pcl6/DeltaRowCompression.cpp | 155 ++++++++++++++++++ .../print/drivers/pcl6/DeltaRowCompression.h | 120 ++++++++++++++ 2 files changed, 275 insertions(+) create mode 100644 src/add-ons/print/drivers/pcl6/DeltaRowCompression.cpp create mode 100644 src/add-ons/print/drivers/pcl6/DeltaRowCompression.h diff --git a/src/add-ons/print/drivers/pcl6/DeltaRowCompression.cpp b/src/add-ons/print/drivers/pcl6/DeltaRowCompression.cpp new file mode 100644 index 0000000000..5f87b947ed --- /dev/null +++ b/src/add-ons/print/drivers/pcl6/DeltaRowCompression.cpp @@ -0,0 +1,155 @@ +/* +** DeltaRowCompression.cpp +** Copyright 2005, Michael Pfeiffer, laplace@users.sourceforge.net. All rights reserved. +** Distributed under the terms of the OpenBeOS License. +*/ +#include "DeltaRowCompression.h" + +#include + +#include + +AbstractDeltaRowCompressor::AbstractDeltaRowCompressor(int rowSize, uchar initialSeed) + : fSeedRow(new uchar[rowSize]) + , fSize(rowSize) + , fInitialSeed(initialSeed) +{ + Reset(); +} + +AbstractDeltaRowCompressor::~AbstractDeltaRowCompressor() +{ + delete fSeedRow; + fSeedRow = NULL; +} + +status_t AbstractDeltaRowCompressor::InitCheck() +{ + if (fSeedRow != NULL) { + return B_OK; + } else { + return B_NO_MEMORY; + } +} + +void AbstractDeltaRowCompressor::Reset() +{ + if (fSeedRow != NULL) { + memset(fSeedRow, fInitialSeed, fSize); + } +} + +int AbstractDeltaRowCompressor::CompressRaw(const uchar* row, bool updateSeedRow, bool updateDeltaRow) +{ + int index = DiffersIndex(row, 0); + if (index == -1) { + // no differences + return 0; + } + + fUpdateDeltaRow = updateDeltaRow; + fDeltaRowIndex = 0; + + int seedRowIndex = 0; + do { + int length = DiffersLength(row, index); + + // delta starts at index and contains length bytes + do { + + // control byte limits data bytes to 8 bytes + int deltaBytes = length; + if (length > 8) { + deltaBytes = 8; + } + + // calculate offset + int totalOffset = index - seedRowIndex; + bool needsOffsetBytes = totalOffset > 30; + int offset = totalOffset; + // control byte limits offset value to 31 + if (needsOffsetBytes) { + offset = 31; + } + + // write control byte (delta bytes bits 5-7; offset bits 0-4) + Put(((deltaBytes-1) << 5) | offset); + + if (needsOffsetBytes) { + // write additional offset bytes after control byte + // the last offset byte must be less than 255 + totalOffset -= offset; + while (totalOffset >= 255) { + Put(255); + totalOffset -= 255; + } + + Put(totalOffset); + } + + // write data bytes + for (int i = 0; i < deltaBytes; i ++) { + // copy row to seed row and delta row + uchar byte = row[index]; + if (updateSeedRow) { + ASSERT (index < fSize); + fSeedRow[index] = byte; + } + Put(byte); + index ++; + } + + seedRowIndex = index; + + length -= deltaBytes; + + } while (length > 0); + + index = DiffersIndex(row, index); + + } while (index != -1); + + return fDeltaRowIndex; +} + +int AbstractDeltaRowCompressor::CalculateSize(const uchar* row, bool updateSeedRow) +{ + return CompressRaw(row, updateSeedRow, false); +} + +void AbstractDeltaRowCompressor::Compress(const uchar* row) +{ + CompressRaw(row, true, true); +} + +#ifdef TEST_DELTA_ROW_COMPRESSION +void test(AbstractDeltaRowCompressor* compressor, uchar* row) { + int size = compressor->CalculateSize(row); + printf("size %d\n", size); + + if (size > 0) { + uchar* buffer = new uchar[size]; + compressor->Compress(row, buffer, size); + for (int i = 0; i < size; i ++) { + printf("%2.2x ", (int)buffer[i]); + } + printf("\n"); + delete buffer; + } + printf("\n"); +} + +int main(int argc, char *argv[]) +{ + int n = 5; + uchar row1[] = {0, 0, 0, 0, 0}; + uchar row2[] = {0, 1, 0, 0, 0}; + uchar row3[] = {1, 1, 0, 2, 2}; + + DeltaRowCompressor compressor(n, 0); + test(&compressor, row1); + test(&compressor, row2); + test(&compressor, row3); +} + +#endif diff --git a/src/add-ons/print/drivers/pcl6/DeltaRowCompression.h b/src/add-ons/print/drivers/pcl6/DeltaRowCompression.h new file mode 100644 index 0000000000..0d2d4705bb --- /dev/null +++ b/src/add-ons/print/drivers/pcl6/DeltaRowCompression.h @@ -0,0 +1,120 @@ +/* +** DeltaRowCompression.h +** Copyright 2005, Michael Pfeiffer, laplace@users.sourceforge.net. All rights reserved. +** Distributed under the terms of the OpenBeOS License. +*/ +#ifndef _DELTA_ROW_COMPRESSION_H +#define _DELTA_ROW_COMPRESSION_H + +#include + +class AbstractDeltaRowCompressor { +public: + AbstractDeltaRowCompressor(int rowSize, uchar initialSeed); + virtual ~AbstractDeltaRowCompressor(); + + // InitCheck returns B_OK on successful construction of this object or + // B_NO_MEMORY if the buffer for the seed row could not be allocated. + status_t InitCheck(); + + // Clears the seed row to the initial seed specified in the constructor + void Reset(); + + // Returns the size of the delta row. + // The size is 0 if the row is equal to the seed row (previous row). + // The seed row is updated only if updateSeedRow is true. + int CalculateSize(const uchar* row, bool updateSeedRow = false); + + // Compresses the row using the delta row compression algorithm. + // The seed row is updated. + void Compress(const uchar* row); + +protected: + // append byte to delta row + virtual void AppendByteToDeltaRow(uchar byte) = 0; + + // returns the current size of the delta row + inline int CurrentDeltaRowSize() { + return fDeltaRowIndex; + } + +private: + // Returns the index where seed row and row differ + // or -1 if both arrays are equal. + inline int DiffersIndex(const uchar* row, int index) + { + while (index < fSize) { + if (fSeedRow[index] != row[index]) { + return index; + } + + index ++; + } + + return -1; + } + + // Returns the number of bytes that row differs from seed row + // starting at the specified index. + inline int DiffersLength(const uchar* row, int index) + { + int startIndex = index; + + while (index < fSize) { + if (fSeedRow[index] == row[index]) { + break; + } + + index ++; + } + return index - startIndex; + } + + // Compresses row with delta row compression algorithm. + // The seed row is updated only if updateSeedRow is true. + // If updateDeltaRow is true the method AppendByteToDeltaRow is called. + int CompressRaw(const uchar* row, bool updateSeedRow, bool updateDeltaRow); + + // write byte to delta row and calculate size of delta row + // If a client overrides this method and wants to calculate the + // size of the delta row the method must be called. + void Put(uchar byte) { + if (fUpdateDeltaRow) { + AppendByteToDeltaRow(byte); + } + fDeltaRowIndex ++; + } + + uchar* fSeedRow; // the seed row + int fSize; // the size of the seed row in bytes + uchar fInitialSeed; // the value to initialize the seed row with + + int fDeltaRowIndex; // the index of the next byte to be written into the delta row + bool fUpdateDeltaRow; // write delta row +}; + +class DeltaRowCompressor : public AbstractDeltaRowCompressor +{ +public: + DeltaRowCompressor(int rowSize, uchar initialSeed) + : AbstractDeltaRowCompressor(rowSize, initialSeed) + { + // nothing to do + } + + // The delta row to be written to. + void SetDeltaRow(uchar* deltaRow) { + fDeltaRow = deltaRow; + } + +protected: + virtual void AppendByteToDeltaRow(uchar byte) { + fDeltaRow[CurrentDeltaRowSize()] = byte; + } + +private: + uchar* fDeltaRow; // the delta row +}; + +#endif +