mirror of
https://github.com/SatDump/SatDump
synced 2026-08-13 17:47:30 -04:00
886 lines
34 KiB
C++
886 lines
34 KiB
C++
/********************************************************************
|
|
*
|
|
* MODULE NAME : RECON.C
|
|
*
|
|
* TITLE : Reconstruction (De-Compression) Software for SOHO LASCO/EIT
|
|
*
|
|
* CC # : ??
|
|
*
|
|
* AUTHOR : Mitchell R Grunes (ATSC/NRL)
|
|
* Karl Hoppel (NRL)
|
|
*
|
|
* DATE : 07/11/96
|
|
*
|
|
* PURPOSE : This is the software to perform image reconstruction
|
|
* for the LASCO/EIT experiments on board the ESA/NASA
|
|
* SOHO spacecraft. It will be run on the ground.
|
|
* FUNCTIONAL
|
|
* DESCRIPTION : A sample call is located in sohorecon.c.
|
|
*
|
|
* CONTROL DATE : 07/11/96
|
|
*
|
|
* REVISION
|
|
* HISTORY : It is requsted by NRL that Lockheed/Avionics make
|
|
* no revisions to this file.
|
|
*
|
|
*************************************************************************/
|
|
|
|
/*============================================================================
|
|
The documentation for the interface to this software is contained in file
|
|
sohorecon.c and in the final report.
|
|
|
|
NOTE: Although we have used named parameters for clarity, they cannot be easily
|
|
changed, because some other parameters here and elsewhere depend on them,
|
|
increasing values could produce arithmetic overflows, and because the DCT size
|
|
must match BlkSz. Furthermore, the compression and reconstruction programs
|
|
must also match.*/
|
|
|
|
/*============================================================================*/
|
|
/* #define DEBUG 0 */
|
|
#define PRINTBAT 1 /*To print bit allocation table. \
|
|
This might be set to 0 for the final \
|
|
code. */
|
|
#define UseCheckSum /*Don't process a packet if it contains \
|
|
a CheckSum. If errors turn out to \
|
|
be very common, we will have to think \
|
|
about this. */
|
|
|
|
/*The following #define's must be the same as in the calling program
|
|
(sohorecon.c): */
|
|
#include "logger.h"
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include "rice_decomp.h"
|
|
|
|
#ifndef _MSC_VER
|
|
#pragma GCC diagnostic push
|
|
#pragma GCC diagnostic ignored "-Wunused-variable"
|
|
#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
|
|
#endif
|
|
|
|
namespace soho_compression
|
|
{
|
|
/* =======================Form of Call=======================
|
|
void Recon(int *ncol, int *nrow, int *SignFlag, uword Image[]);
|
|
void Recon(&ncol,&nrow,SignFlag,Image);
|
|
======================Input Variables=====================
|
|
none--all input will come from routine ReadPack.
|
|
=====================Output Variables=====================
|
|
ncol,nrow =# of columns and rows of pixels in transmitted image.
|
|
Image =Array holding the output image.
|
|
The pixel in 0-origin column i and 0-origin row j will
|
|
be stored at Image[i+j*(long)ncol]. */
|
|
|
|
/*============================================================================*/
|
|
void SOHORiceDecompressor::Recon(int *ncol2, int *nrow2, int *SignFlag2, uword Image[])
|
|
{
|
|
/*Reconstruct an image */
|
|
/* Written by Mitchell R Grunes, ATSC/NRL, 07/11/96 */
|
|
long *Block0, Pix;
|
|
uword *Image0;
|
|
int i, j, iBlkVold, iblkold;
|
|
int nBlock, nBlockGood;
|
|
long nPixel;
|
|
FoundHeader = 0;
|
|
iBlkVold = -1;
|
|
iblkold = -1;
|
|
Valid = 1;
|
|
nBlock = 0;
|
|
nBlockGood = 0;
|
|
a:
|
|
StartPacket();
|
|
|
|
// Aang23 : Prevent div by 0
|
|
if ((BCol2 - BCol1 + 1) == 0)
|
|
{
|
|
output_was_valid = false;
|
|
*ncol2 = 0;
|
|
*nrow2 = 0;
|
|
return;
|
|
}
|
|
|
|
iBlkV = iblk / (BCol2 - BCol1 + 1); /*Convert block # to block row and */
|
|
iBlkH = iblk % (BCol2 - BCol1 + 1); /* block column # */
|
|
if (AtEnd == 0)
|
|
{
|
|
nBlock++;
|
|
ReconPacket(); /*Reconstruct (De-compress) block */
|
|
if (Valid == 0)
|
|
{ /*Was not a valid packet: */
|
|
nBitP = 0;
|
|
goto a;
|
|
}
|
|
if (Valid && iblk < MaxBlk)
|
|
{
|
|
#if ENABLE_PRINTF_OUT
|
|
if (iBlkV != iBlkVold)
|
|
printf("\nBlock Row %d Col ", iBlkV);
|
|
printf("%d ", iBlkH);
|
|
#endif
|
|
iBlkVold = iBlkV;
|
|
if (iBlkH >= ncol / BlkSz || iBlkV >= nrow / BlkSz)
|
|
{
|
|
Error((char *)"Out of range block # (%d)", 0, iblk, 0);
|
|
goto a;
|
|
}
|
|
if (UseBlock(iBlkH, iBlkV) == 0)
|
|
{
|
|
Error((char *)"Block was not usable (occulted)", 0, 0, 0);
|
|
goto a;
|
|
}
|
|
if (iblkold >= iblk)
|
|
Error((char *)"Out of sequence Block #", 0, 0, 0);
|
|
iblkold = iblk;
|
|
for (j = 0; j < BlkSz; j++)
|
|
{ /*Copy Block into Image */
|
|
Image0 = &Image[iBlkH * BlkSz + (j + iBlkV * BlkSz) * (long)ncol];
|
|
Block0 = &Block[j * BlkSz];
|
|
for (i = 0; i < BlkSz; i++)
|
|
{
|
|
Pix = Block0[i];
|
|
if ((Pix < (long)(ulong)MinPixAll) || (Pix > (long)(ulong)MaxPixAll))
|
|
{
|
|
if (Method >= 2)
|
|
{ /*Lossy--just clip */
|
|
if (Pix < (long)(ulong)MinPixAll)
|
|
Pix = (long)(ulong)MinPixAll;
|
|
else
|
|
Pix = (long)(ulong)MaxPixAll;
|
|
}
|
|
else
|
|
{ /*Lossless--should not happen */
|
|
Error((char *)"Out of Bounds Pixel Value (%ld at pixel %d)",
|
|
0, (int)Pix, i);
|
|
}
|
|
}
|
|
if (SqrtFlag)
|
|
Pix = Pix * Pix + Pix;
|
|
if (nshift)
|
|
Pix = (Pix << (long)nshift) + TwoP[nshift - 1];
|
|
if (SignFlag)
|
|
Pix -= 32768L;
|
|
Image0[i] = (uword)Pix;
|
|
}
|
|
}
|
|
}
|
|
if (Valid)
|
|
nBlockGood++;
|
|
goto a;
|
|
}
|
|
nPixel = ncol * (long)nrow;
|
|
#if ENABLE_PRINTF_OUT
|
|
printf("\nreconstructed image took %ld bytes.\n", nPixel * 2);
|
|
printf("(Following #'s do not include Science Packet overhead)\n");
|
|
printf("Compressed image took %ld bytes (%ld without packet overhead),\n",
|
|
MaxPTot, (MaxPTo2 + 7) / 8);
|
|
printf(" which is %lf bits/pixel.\n",
|
|
(double)MaxPTot * 8. / (double)(nPixel));
|
|
printf("Compression Factor=%lf from 16 bits/pixel",
|
|
(2. * nPixel) / MaxPTot);
|
|
printf(" (%lf from %d).\n", (nPixel * 2. * nBitPix) / (MaxPTot * 16), nBitPix);
|
|
printf("Without packet overhead bpp=%lf CF=%lf\n",
|
|
(MaxPTo2) / ((double)nPixel), ((double)nPixel) * 16. / (MaxPTo2));
|
|
#endif
|
|
if (nBlock < (ncol / BlkSz) * (nrow / BlkSz))
|
|
{
|
|
nPixel = (long)nBlock * (long)nPixBlk;
|
|
#if ENABLE_PRINTF_OUT
|
|
printf("If we only consider the %d transmitted blocks, we get:\n", nBlock);
|
|
printf(" %lf bits/pixel.\n",
|
|
(double)MaxPTot * 8. / nPixel);
|
|
printf(" Compression Factor=%lf from 16 bits/pixel",
|
|
(2. * nPixel) / MaxPTot);
|
|
printf(" (%lf from %d).\n", (nPixel * 2. * nBitPix) / (MaxPTot * 16), nBitPix);
|
|
printf(" Without packet overhead bpp=%lf CF=%lf\n",
|
|
(MaxPTo2) / ((double)nPixel), ((double)nPixel) * 16. / (MaxPTo2));
|
|
#endif
|
|
}
|
|
#if ENABLE_PRINTF_OUT
|
|
printf("--%d out of %d blocks were good--\n", nBlockGood, nBlock);
|
|
#endif
|
|
*ncol2 = ncol; /*Copy statics back to caller */
|
|
*nrow2 = nrow;
|
|
*SignFlag2 = SignFlag;
|
|
}
|
|
|
|
/*============================================================================*/
|
|
void SOHORiceDecompressor::StartPacket()
|
|
{ /*Start a Compression Packet */
|
|
/* Written by Mitchell R Grunes, ATSC/NRL, 07/11/96 */
|
|
// static unsigned long totalnWdP = 0l;
|
|
int nWdP;
|
|
OldValid = Valid;
|
|
ReadPack(Pack, &Valid, &AtEnd, &nByteP, &nBitP, &nBytePacket);
|
|
if (AtEnd)
|
|
return;
|
|
nByteP = nBitP = Ended = CheckSum = 0;
|
|
nBytePacket = 4;
|
|
iblk = RdBit(nBksBit);
|
|
#ifdef DEBUG
|
|
printf("StartPacket: iblk = %u\n", iblk);
|
|
#endif
|
|
if (FoundHeader == 0 && iblk != 2045 && iblk != 2047)
|
|
{
|
|
#if ENABLE_PRINTF_OUT
|
|
Error("Have not yet read image header packet!", 0, 0, 0);
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
nWdP = RdBit(MaxWBit);
|
|
CheckSum -= nWdP; /*Was 0 at time checksum written */
|
|
nBytePacket = nWdP * 2;
|
|
MaxPTot += nBytePacket;
|
|
MaxPTo2 += nBytePacket * 8 - nBksBit - MaxWBit - 4;
|
|
#ifdef DEBUG
|
|
printf("StartPacket(): nWdP = %u total_bytes %lu Start CheckSum = %d\n",
|
|
nWdP, MaxPTot, CheckSum);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
/*============================================================================*/
|
|
void SOHORiceDecompressor::EndPacket()
|
|
{ /*End a Compression Packet */
|
|
/* Written by Mitchell R Grunes, ATSC/NRL, 07/11/96 */
|
|
int CheckSumAct, idummy;
|
|
if (AtEnd != 0 || Ended != 0)
|
|
return;
|
|
Ended = 1;
|
|
CheckSumAct = 15 & ((CheckSum) + (CheckSum >> 4) +
|
|
(CheckSum >> 8) + (CheckSum >> 12));
|
|
CheckSum = RdBit(4);
|
|
|
|
#ifdef DEBUG
|
|
printf("EndPacket(): Calc checksum = %u Block Checksum = %u\n", CheckSumAct, CheckSum);
|
|
#endif
|
|
|
|
if ((nByteP + 1) / 2 * 2 != nBytePacket)
|
|
Error((char *)"Wrong # of words in Packet", 0, 0, 0);
|
|
if (CheckSumAct != CheckSum)
|
|
{
|
|
#ifdef UseCheckSum
|
|
Error((char *)"Error:Invalid CheckSum: (Nominal, Actual)", 0, CheckSum, CheckSumAct);
|
|
#endif
|
|
#ifndef UseCheckSum
|
|
Warning("Invalid CheckSum: Nominal %d Actual %d", CheckSum, CheckSumAct);
|
|
#endif
|
|
}
|
|
/*Flush to start of next word */
|
|
while (((nBitP != 0) || nByteP % 2 != 0) && AtEnd == 0)
|
|
idummy = RdBit(1);
|
|
}
|
|
|
|
/*============================================================================*/
|
|
void SOHORiceDecompressor::ReconPacket()
|
|
{ /*Reconstruct one block of pixels.
|
|
--OUTPUTS--
|
|
Block= BlkSz*BlkSz element block of
|
|
image pixels, stored in BlkSz*BlkSz*2
|
|
contiguous bytes.
|
|
--ALSO MODIFIED OR USED--
|
|
nBitP,Pack,CheckSum,Method */
|
|
/* Written by Mitchell R Grunes, ATSC/NRL, 07/11/96 */
|
|
if (AtEnd)
|
|
return;
|
|
if (iblk < MaxBlk)
|
|
{ /*Valid packet type */
|
|
if (Method == 0)
|
|
{ /*Uncompressed data */
|
|
NoRecon();
|
|
}
|
|
else if (Method == 1)
|
|
{ /*Rice Reconstruction */
|
|
RiceRecon();
|
|
}
|
|
else
|
|
{
|
|
#if ENABLE_PRINTF_OUT
|
|
Error("Invalid reconstruction method", 0, 0, 0);
|
|
#endif
|
|
}
|
|
}
|
|
else if (iblk == 2047)
|
|
{ /*Error Packet */
|
|
ErrorPacket();
|
|
}
|
|
else if (iblk == 2045)
|
|
{ /*Image Header Packet */
|
|
if (FoundHeader)
|
|
{
|
|
Error((char *)"Header has already been read!", 0, 0, 0);
|
|
}
|
|
else
|
|
{
|
|
FoundHeader = 1;
|
|
ImageHeader(&BCol1, &BCol2, &BRow1, &BRow2,
|
|
&MinPixAll, &MaxPixAll,
|
|
&Method, &SignFlag, &nshift, &SqrtFlag,
|
|
&ncol, &nrow, &Valid);
|
|
if (Method < 0 || Method > 3 || MinPixAll > MaxPixAll ||
|
|
SignFlag < 0 || SignFlag > 1 ||
|
|
nshift < 0 || nshift > 15 || SqrtFlag < 0 || SqrtFlag > 1 ||
|
|
ncol < 0 || ncol > maxncol || BCol1 < 0 || BCol1 > BCol2 ||
|
|
BCol2 >= MaxBlkH || BRow1 < 0 || BRow1 > BRow2 || BRow2 >= MaxBlkV)
|
|
Error((char *)"Incorrect header parameter", 0, 0, 0);
|
|
nBitPix = nBitNeed((ulong)(MaxPixAll - MinPixAll));
|
|
if (Valid == 0)
|
|
FoundHeader = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (Valid)
|
|
OtherBlock(iblk);
|
|
}
|
|
EndPacket();
|
|
}
|
|
|
|
/*============================================================================*/
|
|
#define RiceBlk 16 /*Rice block size (factor of BlkSz), \
|
|
one side */
|
|
#define RiceBlks (BlkSz / RiceBlk)
|
|
#define RiceBlks2 (RiceBlks * RiceBlks)
|
|
#define nRiceBit 4 /*log base 2 of RiceBlk */
|
|
#define nRiceBits 2 /*log base 2 of RiceBlks */
|
|
/*============================================================================*/
|
|
void SOHORiceDecompressor::RiceRecon()
|
|
{ /*Called by ReconPacket to Reconstruct
|
|
1 block using Rice Algorithm */
|
|
/* Written by Mitchell R Grunes, ATSC/NRL, 07/11/96 */
|
|
uword Predict[nPixBlk]; /*Predict values for pixels */
|
|
uword MaxPix; /*Maximum pixel value */
|
|
uword MaxPixBit; /*# of bits needed to send MaxPix */
|
|
int nSum, Bit, i, ii, jj;
|
|
int RiceAdapt[RiceBlks2], MinAdapt;
|
|
uword MSB, MaxMSB, Adapt;
|
|
long Sum, Diff, Theta, Pix;
|
|
MaxPix = (uword)RdBit(nBitPix) + MinPixAll;
|
|
MaxPixBit = nBitNeed((ulong)MaxPix);
|
|
Pix = (ulong)((uword)RdBit(MaxPixBit) + MinPixAll);
|
|
Predict[0] = (uword)Pix;
|
|
Block[0] = Pix;
|
|
MinAdapt = RdBit(4);
|
|
Adapt = (uword)RdBit(3);
|
|
for (i = 0; i < RiceBlks2; i++)
|
|
RiceAdapt[i] = RdBit((int)Adapt) + MinAdapt;
|
|
for (i = 1; i < nPixBlk; i++)
|
|
{
|
|
jj = i >> nBlkBit;
|
|
ii = i - (jj << nBlkBit);
|
|
Sum = nSum = 0;
|
|
if (jj > 0)
|
|
{
|
|
if (ii > 0)
|
|
{
|
|
Sum += (long)(ulong)Predict[i - BlkSz - 1];
|
|
nSum++;
|
|
}
|
|
Sum += (long)(ulong)Predict[i - BlkSz];
|
|
nSum++;
|
|
if (ii < BlkSz - 1)
|
|
{
|
|
Sum += (long)(ulong)Predict[i - BlkSz + 1];
|
|
nSum++;
|
|
}
|
|
}
|
|
if (ii > 0)
|
|
{
|
|
Sum += (long)(ulong)Predict[i - 1];
|
|
nSum++;
|
|
}
|
|
Predict[i] = (uword)((Sum + (nSum >> 1)) / nSum);
|
|
jj = jj >> nRiceBit;
|
|
ii = ii >> nRiceBit;
|
|
Adapt = RiceAdapt[ii + (jj << nRiceBits)];
|
|
if (Adapt == 15u)
|
|
{
|
|
Pix = (ulong)((uword)RdBit(MaxPixBit) + MinPixAll);
|
|
}
|
|
else if (Adapt > 0u)
|
|
{
|
|
MSB = 0;
|
|
MaxMSB = MaxPix >> Adapt;
|
|
while ((Bit = RdBit(1)) == 0 && AtEnd == 0 && MSB < (uword)(MaxMSB - 1u))
|
|
MSB++;
|
|
if (Bit == 0)
|
|
MSB++;
|
|
Diff = (ulong)((uword)(MSB << Adapt) | (uword)RdBit(Adapt));
|
|
Theta = (long)(ulong)MaxPix - (long)(ulong)Predict[i];
|
|
if (Theta > (long)(ulong)Predict[i])
|
|
Theta = (long)(ulong)Predict[i];
|
|
if (Diff <= Theta + Theta)
|
|
{
|
|
if (Diff & 1)
|
|
Diff = -(Diff + 1) / 2;
|
|
else
|
|
Diff = Diff / 2;
|
|
}
|
|
else
|
|
{
|
|
Diff = Diff - Theta;
|
|
if (Theta != (long)(ulong)Predict[i])
|
|
Diff = -Diff;
|
|
}
|
|
Pix = (long)(ulong)Predict[i] + Diff;
|
|
}
|
|
else
|
|
{
|
|
Pix = (long)(ulong)Predict[i];
|
|
}
|
|
if (Pix > (long)(ulong)MaxPix)
|
|
{
|
|
Error((char *)"Out of bounds predict value (%d at pixel %d)", 0, (short)Pix, i);
|
|
return;
|
|
}
|
|
Predict[i] = (uword)Pix;
|
|
Block[i] = Pix;
|
|
}
|
|
}
|
|
|
|
/*============================================================================*/
|
|
void SOHORiceDecompressor::NoRecon()
|
|
{ /*Called by ReconPacket to use
|
|
uncompressed data */
|
|
/* Written by Mitchell R Grunes, ATSC/NRL, 07/11/96 */
|
|
int i;
|
|
for (i = 0; i < nPixBlk; i++)
|
|
Block[i] = (long)(ulong)RdBit(16);
|
|
}
|
|
|
|
/*============================================================================*/
|
|
void SOHORiceDecompressor::ErrorPacket()
|
|
{ /*Read an error packet */
|
|
/* Written by Mitchell R Grunes, ATSC/NRL, 07/11/96 */
|
|
long iblk2, error, Method, Phase, Process;
|
|
iblk2 = RdBitL(32);
|
|
error = RdBitL(32);
|
|
Method = RdBitL(32);
|
|
Phase = RdBitL(32);
|
|
Process = RdBitL(32);
|
|
#if ENABLE_PRINTF_OUT
|
|
Error("===Encountered Error Packet Error Code %d===", 0, (int)error, 0);
|
|
printf("iblk=%ld error=%ld Method=%ld Phase=%ld Process=%ld\n",
|
|
iblk2, error, Method, Phase, Process);
|
|
#endif
|
|
if (error == 1)
|
|
printf("Incorrect Method or Phase detected by InitComp\n");
|
|
if (error == 2)
|
|
printf("Incorrect Method, Phase or iblk detected by Comp\n");
|
|
if (error == 3)
|
|
printf("Out of range nByteP\n");
|
|
if (error == 4)
|
|
printf("ADCT Binary search for # of words did not converge\n");
|
|
if (error == 5)
|
|
printf("Invalid Scaling factor on initial packet\n");
|
|
if (error == 6)
|
|
printf("Invalid ADCT decision table scaling\n");
|
|
if (error == 7)
|
|
printf("Invalid ADCT coefficient scaling\n");
|
|
if (error == 8)
|
|
printf("Invalid ADCT Block Class\n");
|
|
if (error == 9)
|
|
printf("Invalid ADCT intermediate scaling\n");
|
|
if (error == 10)
|
|
printf("Incorrect block detected by Compress\n");
|
|
if (error == 11)
|
|
printf("Incorrect input parameters detected by Compress\n");
|
|
if (error == 12)
|
|
printf("Pixel value has more than nPixBit bits\n");
|
|
if (error == 13)
|
|
printf("Maximum pixel value has more than nPixBit bits\n");
|
|
if (error == 14)
|
|
printf("Average pixel value has too many bits\n");
|
|
}
|
|
|
|
/*============================================================================*/
|
|
void SOHORiceDecompressor::Error(char *Mes, int iexit, int Var1, int Var2)
|
|
{ /*Process error codes */
|
|
/* Written by Mitchell R Grunes, ATSC/NRL, 07/11/96 */
|
|
if (Valid != 0 && OldValid != 0)
|
|
{ /*Don't keep giving errors if
|
|
This packet or the previous
|
|
one has already been flagged*/
|
|
printf("\n=ERROR=");
|
|
printf("%s %d %d", Mes, Var1, Var2);
|
|
printf("\n");
|
|
}
|
|
Valid = 0;
|
|
if (iexit != 0)
|
|
logger->critical("Wanted to exit!"); // exit(0);
|
|
}
|
|
|
|
/*============================================================================*/
|
|
void SOHORiceDecompressor::Warning(char *Mes, long Var1, long Var2)
|
|
{ /*Process warning codes */
|
|
/* Written by Mitchell R Grunes, ATSC/NRL, 07/11/96 */
|
|
printf("\n\a====================WARNING====================\n");
|
|
printf(Mes, Var1, Var2);
|
|
printf("\n");
|
|
}
|
|
|
|
/*============================================================================*/
|
|
int SOHORiceDecompressor::RdBit(int ibit)
|
|
{ /*Read ival from Pack buffer in ibit
|
|
bits */
|
|
/* Written by Mitchell R Grunes, ATSC/NRL, 07/11/96 */
|
|
uword nDiscard, ival, MSB;
|
|
if (ibit < 0 || ibit > 32)
|
|
Error((char *)"Invalid RdBit %d \n", 0, ibit, 0);
|
|
if (AtEnd)
|
|
return 0;
|
|
CheckSum += ibit;
|
|
ival = 0;
|
|
while (ibit > 0)
|
|
{
|
|
if (nBitP <= 0)
|
|
{
|
|
if (nByteP >= nBytePacket || nByteP < 0)
|
|
{
|
|
AtEnd = 1; /*End of file flag */
|
|
Error((char *)"Packet extended past end of file", 0, nByteP, nBytePacket);
|
|
}
|
|
NextByte = Pack[nByteP++];
|
|
nBitP = 8;
|
|
}
|
|
if (ibit <= nBitP)
|
|
{
|
|
nDiscard = nBitP - ibit;
|
|
MSB = NextByte >> nDiscard;
|
|
ival = (ival << (uword)ibit) | MSB;
|
|
NextByte -= MSB << nDiscard;
|
|
nBitP -= ibit;
|
|
ibit = 0;
|
|
}
|
|
else
|
|
{
|
|
ival = (ival << nBitP) | NextByte;
|
|
ibit -= nBitP;
|
|
nBitP = 0;
|
|
}
|
|
}
|
|
CheckSum += ival;
|
|
return (int)(unsigned)ival;
|
|
}
|
|
|
|
/*============================================================================*/
|
|
long SOHORiceDecompressor::RdBitL(int ibit)
|
|
{ /*Same as RdBit, for longs */
|
|
/* Written by Mitchell R Grunes, ATSC/NRL, 07/11/96 */
|
|
long ival;
|
|
ival = 0;
|
|
if (ibit > 16)
|
|
{
|
|
ival = (long)RdBit(ibit - 16);
|
|
ibit = 16;
|
|
}
|
|
ival = (ival << 16) | (long)RdBit(ibit);
|
|
return ival;
|
|
}
|
|
|
|
/*============================================================================*/
|
|
int SOHORiceDecompressor::nBitNeed(ulong i)
|
|
{ /*# of bits needed to represent i
|
|
(i must be >= 0) */
|
|
/* Written by Mitchell R Grunes, ATSC/NRL, 07/11/96 */
|
|
ulong j;
|
|
int need;
|
|
j = i;
|
|
need = 0;
|
|
while (j > 0)
|
|
{
|
|
j = j >> 1u;
|
|
need++;
|
|
}
|
|
return need;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////// rice64.c
|
|
|
|
/*============================================================================*/
|
|
void SOHORiceDecompressor::ReadPack(uchar Pack[], int *Valid, int *AtEnd, int *nByteP,
|
|
int *nBitP, int *nBytePacket)
|
|
{ /*Read 1 packet into Pack.
|
|
Set AtEnd=0 if there was a packet,
|
|
1 if end of image reached.
|
|
For right now we ignore Science
|
|
super-packet structure, and we assume
|
|
no transmission errors. */
|
|
/* Written by Mitchell R Grunes, ATSC/NRL, 07/11/96 */
|
|
static int FirstPacket = 1; /*First packet? */
|
|
static int byterev = 0; /*Need to byte reverse file? */
|
|
static long PrevStart; /*Previous packet start position */
|
|
int iblk, nWdP;
|
|
uchar c;
|
|
int i;
|
|
#ifndef SEEK_SET
|
|
#define SEEK_SET 0 /*Should be part of C language--but \
|
|
isn't for gcc. */
|
|
#endif
|
|
if (*Valid == 0)
|
|
{ /*Handle invalid packets */
|
|
*Valid = 1;
|
|
PrevStart += 2;
|
|
/*&&&printf("Re-trying at file position %ld\n",PrevStart); */
|
|
#if RICE_MEMORY_VERSION
|
|
if (bfseek(PrevStart, SEEK_SET))
|
|
#else
|
|
if (fseek(fp1, PrevStart, SEEK_SET))
|
|
#endif
|
|
Error((char *)"Bad fseek call", 1, 0, 0);
|
|
}
|
|
else
|
|
{
|
|
*Valid = 1;
|
|
}
|
|
#if RICE_MEMORY_VERSION
|
|
if ((PrevStart = bftell()) < 0)
|
|
#else
|
|
if ((PrevStart = ftell(fp1)) < 0)
|
|
#endif
|
|
Error((char *)"Bad ftell call", 1, 0, 0);
|
|
|
|
*AtEnd = 0; /*Initialize */
|
|
#if RICE_MEMORY_VERSION
|
|
if (bfeof() != 0 || bfread(Pack, (size_t)2, (size_t)2) != (size_t)2)
|
|
#else
|
|
if (feof(fp1) != 0 || fread(Pack, (size_t)2, (size_t)2, fp1) != (size_t)2)
|
|
#endif
|
|
{
|
|
*AtEnd = 1;
|
|
return;
|
|
}
|
|
if (byterev)
|
|
{
|
|
for (i = 0; i < 4; i += 2)
|
|
{
|
|
c = Pack[i];
|
|
Pack[i] = Pack[i + 1];
|
|
Pack[i + 1] = c;
|
|
}
|
|
}
|
|
*nByteP = *nBitP = 0;
|
|
*nBytePacket = 4; /*So we can use RdBit to get length */
|
|
iblk = RdBit(nBksBit); /*Block # */
|
|
if (FirstPacket)
|
|
{ /*Check for byte reversal */
|
|
if (iblk == 2045 || iblk == 2047)
|
|
{ /*Found first packet or error packet! */
|
|
FirstPacket = 0;
|
|
}
|
|
else
|
|
{ /*If not, try byte reversal */
|
|
for (i = 0; i < 4; i += 2)
|
|
{
|
|
c = Pack[i];
|
|
Pack[i] = Pack[i + 1];
|
|
Pack[i + 1] = c;
|
|
}
|
|
*nByteP = *nBitP = 0;
|
|
iblk = RdBit(nBksBit);
|
|
if (iblk == 2045 || iblk == 2047)
|
|
{
|
|
FirstPacket = 0;
|
|
byterev = 1;
|
|
/*printf("Words being byte reversed!\n");*/
|
|
}
|
|
else
|
|
{
|
|
Error((char *)"First block not image header--", 0, 0, 0);
|
|
}
|
|
}
|
|
}
|
|
nWdP = RdBit(MaxWBit);
|
|
if (nWdP > 2)
|
|
{
|
|
#if RICE_MEMORY_VERSION
|
|
if (bfread(&Pack[4], (size_t)(nWdP - 2), (size_t)2) != (size_t)2)
|
|
#else
|
|
if (fread(&Pack[4], (size_t)(nWdP - 2), (size_t)2, fp1) != (size_t)2)
|
|
#endif
|
|
{
|
|
Error((char *)"Packet extended past end of file", 0, 0, 0);
|
|
}
|
|
}
|
|
if (byterev)
|
|
{
|
|
*nBytePacket = nWdP * 2;
|
|
for (i = 4; i < *nBytePacket; i += 2)
|
|
{
|
|
c = Pack[i];
|
|
Pack[i] = Pack[i + 1];
|
|
Pack[i + 1] = c;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*The user must supply an ImageHeader routine to read the image header packet:
|
|
|
|
=======================Form of Call=======================
|
|
|
|
void ImageHeader(int *BCol1, int *BCol2, int *BRow1, int *BRow2,
|
|
uword *MinPixAll, uword *MaxPixAll,
|
|
int *Method, int *SignFlag, int *nshift, int *SqrtFlag,
|
|
int *ncol, int *nrow, int *Valid);
|
|
ImageHeader(&BCol1,&BCol2,&BRow1,&BRow2,
|
|
&MinPixAll,&MaxPixAll,
|
|
&Method,&SignFlag,&nshift,&SqrtFlag)
|
|
&ncol,&nrow,&Valid);
|
|
|
|
======================Input Variables=====================
|
|
|
|
Input is through RdBit routine
|
|
Valid =non-zero if everything in block was valid--may be
|
|
changed by RdBit mid-way through.
|
|
|
|
============================Output=============================
|
|
|
|
BCol1 =Starting 0-Origin block column number.
|
|
BCol2 =Ending 0-Origin block column number.
|
|
Means software will transmit 0-origin columns
|
|
BCol1*BlkSz to BCol2*BlkSz+BlkSz-1
|
|
|
|
BRow1 =Starting 0-Origin block row number.
|
|
BRow2 =Ending 0-Origin block row number.
|
|
Means software will transmit 0-origin rows
|
|
BRow1*BlkSz to BRow2*BlkSz+BlkSz-1
|
|
MaxPixAll=Maximum pixel value
|
|
MinPixAll=Minimum pixel value:
|
|
Method =Compression Method.
|
|
0=Uncompressed (used only to debug system)
|
|
1=(Rice Algorithm) Lossless Compression
|
|
2=(ADCT Algorithm) Lossy Compression
|
|
3-7 Reserved
|
|
SignFlag=0 if image pixels unsigned, non-zero if signed
|
|
nshift =# of bits input should be is to be right shifted
|
|
SqrtFlag=non-zero if square root is to be taken
|
|
ncol =# of columns in output image&&&
|
|
nrow =# of rows in output image
|
|
|
|
|
|
Our example follows. The user may change ImageHeader to match a particular
|
|
format. If that is done, the ImageHeader routine in the compression program
|
|
must also be changed. This program, if modified, must still set all of the
|
|
variables included in this example: */
|
|
|
|
/*============================================================================*/
|
|
|
|
void SOHORiceDecompressor::ImageHeader(int *BCol1, int *BCol2, int *BRow1, int *BRow2,
|
|
uword *MinPixAll, uword *MaxPixAll,
|
|
int *Method, int *SignFlag, int *nshift, int *SqrtFlag,
|
|
int *ncol, int *nrow, int * /*Valid*/)
|
|
{ /*Reconstruct Image Header Packet */
|
|
/* Written by Mitchell R Grunes, ATSC/NRL, 07/11/96 */
|
|
long index;
|
|
uword *Image0;
|
|
*Method = RdBit(3);
|
|
*BCol1 = RdBit(nBitNeed((ulong)(MaxBlkH - 1)));
|
|
*BCol2 = RdBit(nBitNeed((ulong)(MaxBlkH - 1)));
|
|
*BRow1 = RdBit(nBitNeed((ulong)(MaxBlkV - 1)));
|
|
*BRow2 = RdBit(nBitNeed((ulong)(MaxBlkV - 1)));
|
|
*ncol = (*BCol2 - *BCol1 + 1) * BlkSz;
|
|
*nrow = (*BRow2 - *BRow1 + 1) * BlkSz;
|
|
*MaxPixAll = (uword)RdBit(16);
|
|
*MinPixAll = (uword)RdBit(nBitNeed((ulong)*MaxPixAll));
|
|
*SignFlag = RdBit(1);
|
|
*nshift = RdBit(4);
|
|
*SqrtFlag = RdBit(1);
|
|
#if ENABLE_PRINTF_OUT
|
|
printf("Method=%d BCol1=%d BCol2=%d BRow1=%d BRow2=%d ncol=%d nrow=%d\n",
|
|
*Method, *BCol1, *BCol2, *BRow1, *BRow2, *ncol, *nrow);
|
|
printf("MinPixAll=%hu MaxPixAll=%hu SignFlag=%d nshift=%d SqrtFlag=%d\n",
|
|
*MinPixAll, *MaxPixAll, *SignFlag, *nshift, *SqrtFlag);
|
|
#endif
|
|
|
|
#ifdef DEBUG2
|
|
/* test pattern */
|
|
printf("Checking DEBUG2 ImageHeader\n");
|
|
uword icount = 0, power[12];
|
|
uword power2[12] = {1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048};
|
|
for (icount = 0; icount < 12; icount++)
|
|
{
|
|
power[icount] = RdBit(nBitNeed(power2[icount]));
|
|
if (power[icount] != power2[icount])
|
|
{
|
|
printf("Imageheader() : DEBUG2 error\n");
|
|
}
|
|
}
|
|
#endif
|
|
|
|
// Aang23 : FIX OVERFLOW
|
|
if (maxncol < *ncol || maxnrow < *nrow || *nrow < 0 || *ncol < 0)
|
|
{
|
|
output_was_valid = false;
|
|
*ncol = maxncol;
|
|
*nrow = maxnrow;
|
|
}
|
|
|
|
Image0 = Image; /*Zero fill image. */
|
|
for (index = *ncol * (long)*nrow; index; index--)
|
|
{
|
|
*Image0 = 0;
|
|
Image0++;
|
|
}
|
|
EndPacket();
|
|
#if ENABLE_PRINTF_OUT
|
|
if (*Valid)
|
|
printf("(Successful Read of Image Header Packet)--\n");
|
|
printf("--------------------------------------------------------\n");
|
|
#endif
|
|
}
|
|
/*The user must supply an OtherBlock routine to handle block types (as stated
|
|
earlier, code 7666 is free to assign other block types 2021-2040) not specified
|
|
by code 7230. Our example simply prints a message: */
|
|
|
|
/*============================================================================*/
|
|
void SOHORiceDecompressor::OtherBlock(int /*iblk*/)
|
|
{ /*Interpret other types of block */
|
|
/* Written by Mitchell R Grunes, ATSC/NRL, 07/11/96 */
|
|
static unsigned int firstOther = 0;
|
|
#if ENABLE_PRINTF_OUT
|
|
if (firstOther == 0)
|
|
printf("\n--Undefined Block type %d- ", iblk);
|
|
else
|
|
printf("%d-");
|
|
#endif
|
|
firstOther++;
|
|
}
|
|
/*The user must supply a UseBlock routine to specify which blocks may have been
|
|
sent. (Certain blocks in the images will be occulted, and so do not need to be
|
|
sent.) All blocks in the ranges specified by BCol, BCol2, BRow1 and BRow2 will
|
|
have been sent unless the UseBlock routine returned zero on board the
|
|
spacecraft; ideally UseBlock should return the same values on the ground so that
|
|
invalid block numbers will be detectable. However, if no transmission errors
|
|
occur, that will not be necessary.
|
|
|
|
=======================Form of Call=======================
|
|
|
|
result=UseBlock(iBlkH,iBlkV)
|
|
|
|
======================Input Variables=====================
|
|
|
|
iBlkH =(int) 0-origin sub-image block column #
|
|
iBlkV =(int) 0-origin sub-image block row #
|
|
(The sub image block referred to by iBlkH,iBlkV includes the following pixels:
|
|
Image[iBlkH*BlkSz to (iBlkH+1)*BlkSz-1, iBlkV*BlkSz to (iBlkV+1)*BlkSz-1]
|
|
|
|
|
|
=====================Output Variables=====================
|
|
|
|
result =(int)0 if block is not to be transmitted.
|
|
non-zero if block is to be sent
|
|
|
|
In our example, UseBlock will always indicate that the block number was valid:*/
|
|
|
|
/*============================================================================*/
|
|
int SOHORiceDecompressor::UseBlock(int /*iBlkH*/, int /*iBlkV*/)
|
|
{ /*Return 0 if sub-image block is to be
|
|
sent, else return non-zero. */
|
|
/* Written by Mitchell R Grunes, ATSC/NRL, 07/11/96 */
|
|
return 1; /*For this example we always send. */
|
|
}
|
|
}
|
|
|
|
#ifndef _MSC_VER
|
|
#pragma GCC diagnostic pop
|
|
#endif
|