Commit 93b873f4 authored by Ralf Stemmer's avatar Ralf Stemmer

First public release

parent e828b859
*~
*.bak
*.o
jpeg2c/image.c
jpeg2c/jpegtranslater
#include "decoding.h"
#include <stdbool.h>
#include <stdint.h>
#include "image.h"
// Pixel: 0x00BBGGRR
void CreateRGBPixels(
token_t Y[8*8] /*in*/,
token_t Cr[8*8] /*in*/,
token_t Cb[8*8] /*in*/,
token_t Pixels[8*8] /*out*/
)
{
int16_t R, G, B; // While conversion, negative values and 9bit values are possible
for(uint8_t i=0; i<8*8; i++)
{
// Source: https://en.wikipedia.org/wiki/YCbCr
R = Y[i] + 1.402f * (Cr[i]-128.0f);
G = Y[i] - 0.34414f * (Cb[i]-128.0f) - 0.71414f * (Cr[i]-128.0f);
B = Y[i] + 1.772f * (Cb[i]-128.0f);
// Check boundaries
if(R < 0)
R = 0;
else if(R > 255)
R = 255;
if(G < 0)
G = 0;
else if(G > 255)
G = 255;
if(B < 0)
B = 0;
else if(B > 255)
B = 255;
// Create Pixel
Pixels[i] = (token_t)B << 16 | G << 8 | R;
}
}
void ColorConversion(
token_t Y[8*8] /*in*/,
token_t Cr[8*8] /*in*/,
token_t Cb[8*8] /*in*/,
token_t R[8*8] /*out*/,
token_t G[8*8] /*out*/,
token_t B[8*8] /*out*/
)
{
for(int i=0; i<8*8; i++)
{
// Source: https://en.wikipedia.org/wiki/YCbCr
R[i] = Y[i] + 1.402f * (Cr[i]-128.0f);
G[i] = Y[i] - 0.34414f * (Cb[i]-128.0f) - 0.71414f * (Cr[i]-128.0f);
B[i] = Y[i] + 1.772f * (Cb[i]-128.0f);
if(R[i] < 0)
R[i] = 0;
else if(R[i] > 255)
R[i] = 255;
if(G[i] < 0)
G[i] = 0;
else if(G[i] > 255)
G[i] = 255;
if(B[i] < 0)
B[i] = 0;
else if(B[i] > 255)
B[i] = 255;
}
}
void ConvertRGB24to16(
token_t Pixels24[8*8] /*in*/,
token_t Pixels16[8*8] /*out*/
)
{
for(uint8_t i=0; i<8*8; i++)
{
int16_t r,g,b; // The conversion algorithm can temporary create 9bit values
// Separate R,G,B from pixel
r = (Pixels24[i] ) & 0x000000FF;
g = (Pixels24[i] >> 8) & 0x000000FF;
b = (Pixels24[i] >> 16) & 0x000000FF;
// lazy rounding
r += 0x04;
g += 0x02;
b += 0x04;
if(r > 255) r = 255;
if(g > 255) g = 255;
if(b > 255) b = 255;
// Reduce color bit width
r = (r >> 3) & 0x1F; //RRRRRRRR >> 3 -> RRRRR (5)
g = (g >> 2) & 0x3F; //GGGGGGGG >> 2 -> GGGGGG (6)
b = (b >> 3) & 0x1F; //BBBBBBBB >> 3 -> BBBBB (5)
Pixels16[i] = (r << 11) | (g << 5) | (b << 0);
}
}
// vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4
#include "decoding.h"
#include <math.h>
#include <stdbool.h>
#ifdef DEBUG
#include <stdio.h>
#endif
#include <stdint.h>
#include "image.h"
#ifndef M_PI
#define M_PI 3.1415926f
#endif
void IDCT(token_t source[8*8], token_t destination[8*8])
{
for(int dsty=0; dsty<8; dsty++)
{
for(int dstx=0; dstx<8; dstx++)
{
float sum;
sum = 0.0f;
for(int srcy=0; srcy<8; srcy++)
{
for(int srcx=0; srcx<8; srcx++)
{
float cosx, cosy;
// Source: https://www.w3.org/Graphics/JPEG/itu-t81.pdf
cosx = cosf( ( M_PI * (2.0f * dstx + 1.0f) * srcx ) / 16.0f);
cosy = cosf( ( M_PI * (2.0f * dsty + 1.0f) * srcy ) / 16.0f);
float cx, cy;
if(srcx == 0)
cx = 1.0f / sqrtf(2.0f);
else
cx = 1.0f;
if(srcy == 0)
cy = 1.0f / sqrtf(2.0f);
else
cy = 1.0f;
sum += source[srcy*8+srcx] * cx * cy * cosx * cosy;
}
}
// Level shift as told in F.1.1.3: https://www.w3.org/Graphics/JPEG/itu-t81.pdf
destination[dsty*8+dstx] = roundf(0.25f * sum + 128.0f);
// Seen at https://github.com/matja/jpegdecoder/blob/master/jpegdecoder.c#L272
if(destination[dsty*8+dstx] < 0)
destination[dsty*8+dstx] = 0;
else if(destination[dsty*8+dstx] > 255)
destination[dsty*8+dstx] = 255;
}
}
#ifdef DEBUG
extern int dez2str(char* dst, long src);
extern void Print(const char *string);
Print("\e[1;34mSlow-Matrix:\e[0;36m\n");
for(int y=0; y<8; y++)
{
Print("\t");
for(int x=0; x<8; x++)
{
char data[20];
dez2str(data, destination[y*8+x]);
Print(data);
Print("\t");
}
Print("\n");
}
#endif
}
void FastIDCT(token_t source[8*8], token_t destination[8*8])
{
// Source:
// Author: Robert Danielsen
// Modified: T.W., 11-Nov-1996, Adopted from Momusys VM
// Modified by Ralf Stemmer (ralf.stemmer@uol.de)
// Modifications:
// - Using float instead of double
// - Adding offset of 128 to the result
// Link: https://github.com/usamaaftab80/multi-p2p/blob/5c46a17192e6483df1e560337fc0a50bdd7cc0b2/vic264/codec/h263/idctenc.c#L312
int j1, i, j;
float b[8], b1[8], dd[8][8];
float f0 = 0.7071068f;
float f1 = 0.4903926f;
float f2 = 0.4619398f;
float f3 = 0.4157348f;
float f4 = 0.3535534f;
float f5 = 0.2777851f;
float f6 = 0.1913417f;
float f7 = 0.0975452f;
float e, f, g, h;
/* Horizontal */
/* Descan coefficients first */
for (i = 0; i < 8; i++)
{
for (j = 0; j < 8; j++)
{
b[j] = (float)source[8 * i + j];
}
e = b[1] * f7 - b[7] * f1;
h = b[7] * f7 + b[1] * f1;
f = b[5] * f3 - b[3] * f5;
g = b[3] * f3 + b[5] * f5;
b1[0] = (b[0] + b[4]) * f4;
b1[1] = (b[0] - b[4]) * f4;
b1[2] = b[2] * f6 - b[6] * f2;
b1[3] = b[6] * f6 + b[2] * f2;
b[4] = e + f;
b1[5] = e - f;
b1[6] = h - g;
b[7] = h + g;
b[5] = (b1[6] - b1[5]) * f0;
b[6] = (b1[6] + b1[5]) * f0;
b[0] = b1[0] + b1[3];
b[1] = b1[1] + b1[2];
b[2] = b1[1] - b1[2];
b[3] = b1[0] - b1[3];
for (j = 0; j < 4; j++)
{
j1 = 7 - j;
dd[i][j] = b[j] + b[j1];
dd[i][j1] = b[j] - b[j1];
}
}
/* Vertical */
for (i = 0; i < 8; i++)
{
for (j = 0; j < 8; j++)
{
b[j] = dd[j][i];
}
e = b[1] * f7 - b[7] * f1;
h = b[7] * f7 + b[1] * f1;
f = b[5] * f3 - b[3] * f5;
g = b[3] * f3 + b[5] * f5;
b1[0] = (b[0] + b[4]) * f4;
b1[1] = (b[0] - b[4]) * f4;
b1[2] = b[2] * f6 - b[6] * f2;
b1[3] = b[6] * f6 + b[2] * f2;
b[4] = e + f;
b1[5] = e - f;
b1[6] = h - g;
b[7] = h + g;
b[5] = (b1[6] - b1[5]) * f0;
b[6] = (b1[6] + b1[5]) * f0;
b[0] = b1[0] + b1[3];
b[1] = b1[1] + b1[2];
b[2] = b1[1] - b1[2];
b[3] = b1[0] - b1[3];
for (j = 0; j < 4; j++)
{
j1 = 7 - j;
dd[j][i] = b[j] + b[j1];
dd[j1][i] = b[j] - b[j1];
}
}
for (i = 0; i < 8; i++)
{
for (j = 0; j < 8; j++)
{
#define MNINT(a) ((a) < 0 ? (int)(a - 0.5f) : (int)(a + 0.5f))
destination[i*8+j] = (token_t)(MNINT(dd[i][j]) + 128.0f);
}
}
#ifdef DEBUG
extern int dez2str(char* dst, long src);
extern void Print(const char *string);
Print("\e[1;34mFast-Matrix:\e[0;36m\n");
for(int y=0; y<8; y++)
{
Print("\t");
for(int x=0; x<8; x++)
{
char data[20];
dez2str(data, destination[y*8+x]);
Print(data);
Print("\t");
}
Print("\n");
}
#endif
}
// vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4
#include "decoding.h"
#include "image.h"
#include <stdint.h>
#include <stdbool.h>
uint8_t GetNextBitFromImage(bool reset)
{
static int byteindex = 0;
static int bitindex = 0;
if(reset)
{
byteindex = 0;
bitindex = 0;
return 0xFF;
}
uint8_t bit;
bit = Image_data[byteindex] >> (7-bitindex);
bit &= 0x01; // be aware of arithmetic shifting
if(bitindex >= 7)
{
bitindex = 0;
byteindex++;
}
else
{
bitindex++;
}
return bit;
}
// vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4
#ifndef JPEGDECODING
#define JPEGDECODING
/*
* CHANGELOG
* 25.10.19 - Comments reviewed for publication
* 24.05.19 - Interface of InverQuantization changed to avoid a configuration-depending branching behavior
* 13.05.19 - BlockInfo parameter of GetEncodedImageBlock is optional and can be NULL
* - Detailed comments added to this file
* - Cleaning up header file
*/
#include <stdint.h>
#ifndef LIBSDF_H
typedef int token_t; // Better include sdf.h to get token_t definition
#endif
enum component_t {COMP_Y=0, COMP_Cb=1, COMP_Cr=2};
enum blockinfoindex_t {BII_IMG_WIDTH=0, BII_IMG_HEIGHT=1, BII_CURRENTBLOCK=2, BII_MAXBLOCKS=3};
// Actors
/*
* File: huffman.c
* Features:
* Dependent X-Time: Yes, per Iteration (Image Input Data)
* Floatingpoint: No
* Mult./Div.: No
*/
void GetEncodedImageBlock(
token_t DCOffset[3] /*in/out*/,
token_t Y[8*8] /*out*/,
token_t Cr[8*8] /*out*/,
token_t Cb[8*8] /*out*/,
token_t BlockInfo[4] /*out [optional]*/); // 0: ImgW, 1: ImgH, 2: Block, 3: MaxBlocks
/*
* File: quantization.c
* Features:
* Dependent X-Time: Yes, per Instance (quantization table)
* Yes, per Iteration (QuantizedCoefficients get rounded
* Floatingpoint: No
* Mult./Div.: Yes (64 multiplications)
*/
void InverseQuantization(
const uint8_t quantizationtable[8*8], /*config*/
token_t QuantizedCoefficients[8*8] /*in*/,
token_t DCTCoefficients[8*8] /*out*/);
/*
* File: IDCT.c
* Features:
* Dependent X-Time: Yes, per Iteration (rounding)
* Floatingpoint: Yes (thousands of times incl sqrtf and cosf)
* Mult./Div.: Yes (thousands of multiplications and dividations)
*/
void IDCT(
token_t source[8*8] /*in*/,
token_t destination[8*8] /*out*/);
/*
* File: IDCT.c
* Features:
* Dependent X-Time: No
* Floatingpoint: Yes (Lots of *,+,-)
* Mult./Div.: No
*/
void FastIDCT(
token_t source[8*8] /*in*/,
token_t destination[8*8] /*out*/);
/*
* File: ColorConversion.c
* Features:
* Dependent X-Time: Yes, per Iteration (rounding)
* Floatingpoint: Yes (~100 +,-,·,/)
* Mult./Div.: No (Only float)
*/
void CreateRGBPixels(
token_t Y[8*8] /*in*/,
token_t Cr[8*8] /*in*/,
token_t Cb[8*8] /*in*/,
token_t Pixels[8*8] /*out*/
);
/*
* File: ColorConversion.c
* Features:
* Dependent X-Time: Yes, per Iteration (rounding)
* Floatingpoint: Yes (~100 +,-,·,/)
* Mult./Div.: No (Only float)
*/
void ColorConversion(
token_t Y[8*8] /*in*/,
token_t Cr[8*8] /*in*/,
token_t Cb[8*8] /*in*/,
token_t R[8*8] /*out*/,
token_t G[8*8] /*out*/,
token_t B[8*8] /*out*/
);
/*
* File: ColorConversion.c
* Features:
* Dependent X-Time: Yes, per Iteration (rounding)
* Floatingpoint: No
* Mult./Div.: No
*/
void ConvertRGB24to16(
token_t Pixels24[8*8] /*in*/,
token_t Pixels16[8*8] /*out*/
);
#endif
// vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4
#include "decoding.h"
#include <stdbool.h>
#ifdef DEBUG
#include <stdio.h>
#endif
#include <stdint.h>
#include "image.h"
// Internals
// Does not care about Image_size.
// To start from the beginning, call with reset=true - the returned value is then invalid!
uint8_t GetNextBitFromImage(bool reset);
// Huffman decoding
void GetEncodedImageBlockComponent(enum component_t component, token_t dcoffset, token_t matrix[8*8]);
uint8_t GetHuffmanDecodedValueFromImage(int tablesize, const uint16_t *codes, const uint8_t *values, const uint16_t *masks);
signed int DCCodeToInteger(uint16_t dccode, uint8_t dclength);
void GetEncodedImageBlock(token_t DCOffsets[3], token_t Y[8*8], token_t Cr[8*8], token_t Cb[8*8],
token_t BlockInfo[4])
{
// ">> 3" = "/ 8"
const uint16_t numofblocks = (Image_xdimension >> 3) * (Image_ydimension >> 3);
static uint16_t blockcount = 0;
// When this is the first block, …
if(blockcount == 0)
{
GetNextBitFromImage(true); // … reset decoder
DCOffsets[COMP_Y ] = 0;
DCOffsets[COMP_Cb] = 0;
DCOffsets[COMP_Cr] = 0;
}
// For Y, Cr, Cb
GetEncodedImageBlockComponent(COMP_Y, DCOffsets[COMP_Y ], Y);
GetEncodedImageBlockComponent(COMP_Cb, DCOffsets[COMP_Cb], Cb);
GetEncodedImageBlockComponent(COMP_Cr, DCOffsets[COMP_Cr], Cr);
DCOffsets[COMP_Y ] = Y[0];
DCOffsets[COMP_Cb] = Cb[0];
DCOffsets[COMP_Cr] = Cr[0];
// Output additional information
if(BlockInfo != NULL)
{
BlockInfo[0] = Image_xdimension;
BlockInfo[1] = Image_ydimension;
BlockInfo[2] = blockcount;
BlockInfo[3] = numofblocks;
}
// Update internal state for next block
blockcount++;
if(blockcount >= numofblocks)
blockcount = 0;
}
void GetEncodedImageBlockComponent(enum component_t component, token_t dcoffset, token_t matrix[8*8])
{
int DCHT_size;
const uint16_t *DCHT_codes;
const uint8_t *DCHT_values;
const uint16_t *DCHT_masks;
int ACHT_size;
const uint16_t *ACHT_codes;
const uint8_t *ACHT_values;
const uint16_t *ACHT_masks;
switch(component)
{
case COMP_Y:
DCHT_size = Y_DCHT_size;
DCHT_codes = Y_DCHT_codes;
DCHT_values = Y_DCHT_values;
DCHT_masks = Y_DCHT_masks;
ACHT_size = Y_ACHT_size;
ACHT_codes = Y_ACHT_codes;
ACHT_values = Y_ACHT_values;
ACHT_masks = Y_ACHT_masks;
break;
case COMP_Cr:
DCHT_size = Cr_DCHT_size;
DCHT_codes = Cr_DCHT_codes;
DCHT_values = Cr_DCHT_values;
DCHT_masks = Cr_DCHT_masks;
ACHT_size = Cr_ACHT_size;
ACHT_codes = Cr_ACHT_codes;
ACHT_values = Cr_ACHT_values;
ACHT_masks = Cr_ACHT_masks;
break;
case COMP_Cb:
DCHT_size = Cb_DCHT_size;
DCHT_codes = Cb_DCHT_codes;
DCHT_values = Cb_DCHT_values;
DCHT_masks = Cb_DCHT_masks;
ACHT_size = Cb_ACHT_size;
ACHT_codes = Cb_ACHT_codes;
ACHT_values = Cb_ACHT_values;
ACHT_masks = Cb_ACHT_masks;
break;
}
// Decode DC
// read code length
uint8_t dclength;
dclength = GetHuffmanDecodedValueFromImage(
DCHT_size,
DCHT_codes,
DCHT_values,
DCHT_masks
);
// read code word
uint16_t dccode = 0;
for(int i=0; i<dclength; i++)
dccode = (dccode << 1) | (uint16_t)GetNextBitFromImage(false);
// decode DC value
signed int dcvalue;
dcvalue = DCCodeToInteger(dccode, dclength);
#ifdef DEBUG
printf("\e[1;34mDC length: \e[0;36m0x%02X\n", dclength);
printf("\e[1;34mDC code: \e[0;36m0x%02X\n", dccode);
printf("\e[1;34mDC value: \e[0;36m%d\n", dcvalue);
#endif
matrix[0] = dcoffset + dcvalue; // Difference Encoding!
// Decode AC values
for(int i=1; i<8*8; i++)
{
uint8_t acrlc;
acrlc = GetHuffmanDecodedValueFromImage(
ACHT_size,
ACHT_codes,
ACHT_values,
ACHT_masks
);
if(acrlc == 0x00) // End Of Block - All left values are 0x00
{
for(; i<8*8; i++)
matrix[i] = 0x00;
break;
}
else if(acrlc == 0xF0) // ZRL Code
{
for(int zeros=0; zeros<16; zeros++, i++)
matrix[i] = 0x00;
continue;
}
// Decode Run-Length-Code
uint8_t numzeros, aclength;
numzeros = (acrlc >> 4) & 0x0F; // Beware of arithmetic right shift!
aclength = acrlc & 0x0F;
// Set zeros
for(int zeros=0; zeros<numzeros; zeros++, i++)
matrix[i] = 0x00;
// Get value code
uint16_t accode = 0;
for(int acvaluebit=0; acvaluebit<aclength; acvaluebit++)
accode = (accode << 1) | (uint16_t)GetNextBitFromImage(false);
// decode AC value
signed int acvalue;
acvalue = DCCodeToInteger(accode, aclength); // Same table for AC and DC
matrix[i] = acvalue;
}
#ifdef DEBUG
printf("\e[1;34mMatrix[%i]:\e[0;36m\n", component);
for(int y=0; y<8; y++)
{
printf("\t");
for(int x=0; x<8; x++)
{
printf("%d\t", matrix[y*8+x]);
}
printf("\n");
}
#endif
}
signed int DCCodeToInteger(uint16_t dccode, uint8_t dclength)
{
#ifdef DEBUG
if(dccode != 0)
{
printf("\e[1;30mDCCodeToInteger(0x%04X, %d) -> 0x%04X & 0x%04X\n",
dccode, dclength,
dccode, 1<<(dclength-1));
}
#endif
signed int dcvalue;
if(dccode & ( 1 << (dclength-1) )) // if first bit is 1, then this is a positive value
dcvalue = (signed int)(dccode);
else
dcvalue = (signed int)(dccode - ( (1<<dclength) - 1 ) );
return dcvalue;
}