sharplib/ar/ArithmeticCompress.cs

128 lines
4.2 KiB
C#

using System;
using System.IO;
/*
* Reference arithmetic coding
* Copyright (c) Project Nayuki
*
* https://www.nayuki.io/page/reference-arithmetic-coding
* https://github.com/nayuki/Reference-arithmetic-coding
*/
/// <summary>
/// Compression application using static arithmetic coding.
/// <para>Usage: java ArithmeticCompress InputFile OutputFile</para>
/// <para>Then use the corresponding "ArithmeticDecompress" application to recreate the original input file.</para>
/// <para>Note that the application uses an alphabet of 257 symbols - 256 symbols for the byte
/// values and 1 symbol for the EOF marker. The compressed file format starts with a list
/// of 256 symbol frequencies, and then followed by the arithmetic-coded data.</para>
/// </summary>
public class ArithmeticCompress
{
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
//ORIGINAL LINE: public static void main(String[] args) throws java.io.IOException
public static void Main( string[] args )
{
/* @@ PORT
// Handle command line arguments
if (args.Length != 2)
{
Console.Error.WriteLine("Usage: java ArithmeticCompress InputFile OutputFile");
Environment.Exit(1);
return;
}
File inputFile = new File(args[0]);
File outputFile = new File(args[1]);
// Read input file once to compute symbol frequencies
FrequencyTable freqs = getFrequencies(inputFile);
freqs.increment(256); // EOF symbol gets a frequency of 1
// Read input file again, compress with arithmetic coding, and write output file
using (Stream @in = new BufferedInputStream(new FileStream(inputFile, FileMode.Open, FileAccess.Read)), BitOutputStream @out = new BitOutputStream(new BufferedOutputStream(new FileStream(outputFile, FileMode.Create, FileAccess.Write))))
{
writeFrequencies(@out, freqs);
compress(freqs, @in, @out);
}
*/
}
// Returns a frequency table based on the bytes in the given file.
// Also contains an extra entry for symbol 256, whose frequency is set to 0.
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
//ORIGINAL LINE: private static FrequencyTable getFrequencies(java.io.File file) throws java.io.IOException
private static FrequencyTable getFrequencies( string file )
{
FrequencyTable freqs = new SimpleFrequencyTable( new int[257] );
using( Stream input = new BufferedStream( new FileStream( file, FileMode.Open, FileAccess.Read ) ) )
{
while( true )
{
int b = input.ReadByte();
if( b == -1 )
{
break;
}
freqs.increment( b );
}
}
return freqs;
}
// To allow unit testing, this method is package-private instead of private.
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
//ORIGINAL LINE: static void writeFrequencies(BitOutputStream out, FrequencyTable freqs) throws java.io.IOException
internal static void writeFrequencies( BitOutputStream @out, FrequencyTable freqs )
{
for( int i = 0; i < 256; i++ )
{
writeInt( @out, 32, freqs.get( i ) );
}
}
// To allow unit testing, this method is package-private instead of private.
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
//ORIGINAL LINE: static void compress(FrequencyTable freqs, java.io.InputStream in, BitOutputStream out) throws java.io.IOException
internal static void compress( FrequencyTable freqs, Stream @in, BitOutputStream @out )
{
ArithmeticEncoder enc = new ArithmeticEncoder( 32, @out );
while( true )
{
int symbol = @in.ReadByte();
if( symbol == -1 )
{
break;
}
enc.write( freqs, symbol );
}
enc.write( freqs, 256 ); // EOF
enc.finish(); // Flush remaining code bits
}
// Writes an unsigned integer of the given bit width to the given stream.
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
//ORIGINAL LINE: private static void writeInt(BitOutputStream out, int numBits, int value) throws java.io.IOException
private static void writeInt( BitOutputStream @out, int numBits, int value )
{
if( numBits < 0 || numBits > 32 )
{
throw new System.ArgumentException();
}
for( int i = numBits - 1; i >= 0; i-- )
{
@out.write( ( (int)( (uint)value >> i ) ) & 1 ); // Big endian
}
}
}