Skip to content

Commit 2915389

Browse files
committed
add encoder
1 parent 640ede2 commit 2915389

File tree

6 files changed

+606
-2
lines changed

6 files changed

+606
-2
lines changed

Makefile

+5-2
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,17 @@ DEBUG = -g -O0 -fsanitize=address
1717

1818
.PHONY: all clean debug
1919

20-
all: huffdec
20+
all: huffdec huffenc
2121

2222
debug: CFLAGS+=$(DEBUG)
2323
debug: all
2424

2525
clean:
26-
rm -f hufdec
26+
rm -f huffdec huffenc
2727

2828
huffdec: decoder.c bit_reader.c huff_dec.c
2929
$(CC) $(FLAGS) $(CFLAGS) $(LFLAGS) -o $@ $^
3030

31+
huffenc: encoder.c bit_writer.c huff_enc.c
32+
$(CC) $(FLAGS) $(CFLAGS) $(LFLAGS) -o $@ $^
33+

bit_writer.c

+96
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
/*
2+
* @file bit_writer.c
3+
* @author Fabjan Sukalia <[email protected]>
4+
* @date 2016-02-16
5+
*/
6+
7+
#include <stdlib.h>
8+
#include "bit_writer.h"
9+
10+
struct bit_writer {
11+
FILE *file;
12+
uint8_t buffer;
13+
uint8_t bit_pos;
14+
};
15+
16+
struct bit_writer *bit_writer_create(FILE *out)
17+
{
18+
struct bit_writer *writer = calloc(1, sizeof(*writer));
19+
writer->file = out;
20+
return writer;
21+
}
22+
23+
void bit_writer_destroy(struct bit_writer *writer)
24+
{
25+
/* write out remaining bits */
26+
if (writer->bit_pos > 0) {
27+
/* append '1' */
28+
while(writer->bit_pos != 0)
29+
bit_writer_next_bit(writer, 1);
30+
}
31+
32+
free(writer);
33+
}
34+
35+
bool bit_writer_next_bit(struct bit_writer *writer, uint8_t bit)
36+
{
37+
uint8_t buffer = writer->buffer;
38+
uint8_t bit_pos = writer->bit_pos;
39+
40+
buffer |= (bit & 0x01) << (7 - bit_pos);
41+
bit_pos++;
42+
43+
if (bit_pos == 8) {
44+
if (fwrite(&buffer, sizeof(buffer), 1, writer->file) != 1)
45+
return false;
46+
47+
if (buffer == 0xFF) {
48+
buffer = 0;
49+
if (fwrite(&buffer, sizeof(buffer), 1, writer->file) != 1)
50+
return false;
51+
}
52+
bit_pos = 0;
53+
buffer = 0;
54+
}
55+
56+
writer->buffer = buffer;
57+
writer->bit_pos = bit_pos;
58+
return true;
59+
}
60+
61+
bool bit_writer_next_bits(struct bit_writer *writer, uint16_t bits, uint8_t num)
62+
{
63+
/* Msb first */
64+
for (int i = 0; i < num; i++) {
65+
uint8_t bit = (bits >> (num - i - 1));
66+
if (!bit_writer_next_bit(writer, bit))
67+
return false;
68+
69+
}
70+
71+
return true;
72+
}
73+
74+
#if 0
75+
76+
int main(void)
77+
{
78+
FILE *out = fopen("test1.bin", "wr");
79+
80+
struct bit_writer *writer = bit_writer_create(out);
81+
bit_writer_next_bits(writer, 0x04, 3); // H
82+
bit_writer_next_bits(writer, 0x0A, 4); // e
83+
bit_writer_next_bits(writer, 0x00, 2); // l
84+
bit_writer_next_bits(writer, 0x00, 2); // l
85+
bit_writer_next_bits(writer, 0x01, 2); // o
86+
bit_writer_next_bits(writer, 0x0B, 4); // SPACE
87+
bit_writer_next_bits(writer, 0x0C, 4); // W
88+
bit_writer_next_bits(writer, 0x01, 2); // o
89+
bit_writer_next_bits(writer, 0x0D, 4); // r
90+
bit_writer_next_bits(writer, 0x00, 2); // l
91+
bit_writer_next_bits(writer, 0x0E, 4); // d
92+
bit_writer_next_bits(writer, 0x0F, 4); // \n
93+
bit_writer_destroy(writer);
94+
}
95+
#endif
96+

bit_writer.h

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/*
2+
* @file bit_writer.h
3+
* @author Fabjan Sukalia <[email protected]>
4+
* @date 2016-02-16
5+
* @brief Module to write bitwise to a file.
6+
*/
7+
8+
#ifndef BIT_WRITER_H
9+
#define BIT_WRITER_H
10+
11+
#include <stdio.h>
12+
#include <stdint.h>
13+
#include <stdbool.h>
14+
15+
struct bit_writer;
16+
17+
struct bit_writer *bit_writer_create(FILE *out);
18+
void bit_writer_destroy(struct bit_writer *writer);
19+
20+
bool bit_writer_next_bit(struct bit_writer *writer, uint8_t bit);
21+
bool bit_writer_next_bits(struct bit_writer *writer, uint16_t bits, uint8_t num);
22+
23+
#endif
24+

encoder.c

+165
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
/*
2+
* @file encoder.c
3+
* @author Fabjan Sukalia <[email protected]>
4+
* @date 2016-02-21
5+
* @brief Tool to encode data using huffman codes in JPEG format
6+
*/
7+
8+
#define _POSIX_C_SOURCE 1
9+
#define _DEFAULT_SOURCE
10+
11+
#include <sys/types.h>
12+
#include <sys/stat.h>
13+
#include <unistd.h>
14+
15+
#include <stdio.h>
16+
#include <stdlib.h>
17+
#include <string.h>
18+
#include <errno.h>
19+
#include <stdint.h>
20+
#include "bit_writer.h"
21+
#include "huff_enc.h"
22+
23+
#define JPG_DHT (0xC4)
24+
25+
static const char *prog_name = "huffenc";
26+
27+
void usage(void)
28+
{
29+
fprintf(stderr, "USAGE: %s FILE_IN FILE_OUT\n", prog_name);
30+
exit(EXIT_FAILURE);
31+
}
32+
33+
static off_t get_file_size(FILE *file)
34+
{
35+
int fd = fileno(file);
36+
if (fd == -1)
37+
return 0;
38+
39+
struct stat buf;
40+
if (fstat(fd, &buf) != 0)
41+
return 0;
42+
43+
if (S_ISREG(buf.st_mode) == 0)
44+
return 0;
45+
46+
return buf.st_size;
47+
}
48+
49+
void encode(FILE *in, FILE *out)
50+
{
51+
off_t size = get_file_size(in);
52+
if (size == 0)
53+
return;
54+
55+
uint8_t *data = malloc(size);
56+
if (data == NULL)
57+
return;
58+
59+
if (fread(data, size, 1, in) != 1) {
60+
fprintf(stderr, "Couldn't read input data\n");
61+
exit(EXIT_FAILURE);
62+
}
63+
64+
uint32_t freq[256];
65+
huff_get_freq(data, size, freq);
66+
67+
struct huff_enc enc;
68+
struct huff_enc_info info;
69+
if (!huff_gen_enc(freq, &enc, &info)) {
70+
fprintf(stderr, "Couldn't create encoder\n");
71+
exit(EXIT_FAILURE);
72+
}
73+
74+
uint8_t header[21];
75+
header[0] = 0xFF;
76+
header[1] = JPG_DHT;
77+
78+
uint16_t header_length = 19 + info.num_codes;
79+
header[2] = header_length >> 8;
80+
header[3] = header_length & 0xFF;
81+
82+
header[4] = 0;
83+
84+
for (int i = 0; i < 16; i++) {
85+
header[5 + i] = info.codes_per_len[i];
86+
}
87+
88+
if (fwrite(header, sizeof(header), 1, out) != 1) {
89+
fprintf(stderr, "Couldn't write header\n");
90+
exit(EXIT_FAILURE);
91+
}
92+
93+
/* write symbols */
94+
for (int i = 0; i < 16; i++) {
95+
uint16_t num_symbols = info.codes_per_len[i];
96+
97+
if (num_symbols == 0)
98+
continue;
99+
100+
uint8_t symbols[num_symbols];
101+
102+
uint16_t sym_index = 0;
103+
for (int j = 0; j < info.num_codes; j++) {
104+
if (enc.codes[j].code_len != (i + 1))
105+
continue;
106+
107+
symbols[sym_index] = enc.codes[j].symbol;
108+
sym_index++;
109+
}
110+
111+
if (fwrite(symbols, num_symbols, 1, out) != 1) {
112+
fprintf(stderr, "Couldn't write header\n");
113+
exit(EXIT_FAILURE);
114+
}
115+
}
116+
117+
/* write uint32_t num_data_symbols */
118+
uint8_t num_bytes[4];
119+
num_bytes[0] = (size >> 24) & 0xFF;
120+
num_bytes[1] = (size >> 16) & 0xFF;
121+
num_bytes[2] = (size >> 8) & 0xFF;
122+
num_bytes[3] = size & 0xFF;
123+
124+
if (fwrite(num_bytes, 4, 1, out) != 1) {
125+
fprintf(stderr, "Couldn't write number of bytes\n");
126+
exit(EXIT_FAILURE);
127+
}
128+
129+
struct bit_writer *writer = bit_writer_create(out);
130+
huff_encode(&enc, size, data, writer);
131+
132+
bit_writer_destroy(writer);
133+
huff_enc_destroy(&enc);
134+
free(data);
135+
}
136+
137+
int main(int argc, char *argv[])
138+
{
139+
errno = 0;
140+
141+
if (argc > 1)
142+
prog_name = argv[0];
143+
144+
if (argc != 3)
145+
usage();
146+
147+
FILE *in = fopen(argv[1], "rb");
148+
if (in == NULL) {
149+
perror("Couldn't open input file");
150+
return EXIT_FAILURE;
151+
}
152+
153+
FILE *out = fopen(argv[2], "wb");
154+
if (out == NULL) {
155+
perror("Couldn't open output file");
156+
return EXIT_FAILURE;
157+
}
158+
159+
encode(in, out);
160+
161+
fclose(in);
162+
fclose(out);
163+
164+
return 0;
165+
}

0 commit comments

Comments
 (0)