init with content
This commit is contained in:
commit
b4918934dc
16 changed files with 982 additions and 0 deletions
66
CMakeLists.txt
Normal file
66
CMakeLists.txt
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
set()
|
||||||
|
cmake_minimum_required(VERSION 3.12)
|
||||||
|
project(libbpic VERSION 1.0.0 LANGUAGES C DESCRIPTION "encode and decode any file to an image")
|
||||||
|
|
||||||
|
# dependencies
|
||||||
|
|
||||||
|
find_package(PNG REQUIRED)
|
||||||
|
message(STATUS ${PNG_INCLUDE_DIR})
|
||||||
|
include_directories(${PNG_INCLUDE_DIRS})
|
||||||
|
|
||||||
|
# sources
|
||||||
|
|
||||||
|
set(BPIC_SOURCES
|
||||||
|
src/bpic/common_utils.c
|
||||||
|
src/bpic/encode.c
|
||||||
|
src/bpic/decode.c)
|
||||||
|
set(BPIC_HEADERS
|
||||||
|
src/bpic/include/bpic.h
|
||||||
|
src/bpic/include/common_utils.h
|
||||||
|
src/bpic/include/decode.h
|
||||||
|
src/bpic/include/encode.h)
|
||||||
|
|
||||||
|
set(BPICENCODE_SOURCES
|
||||||
|
src/bpicencode/main.c)
|
||||||
|
|
||||||
|
set(BPICDECODE_SOURCES
|
||||||
|
src/bpicdecode/main.c)
|
||||||
|
|
||||||
|
set(BPICENCODE_TEST_SOURCES
|
||||||
|
src/bpicencode_test/main.c)
|
||||||
|
|
||||||
|
set(BPICDECODE_TEST_SOURCES
|
||||||
|
src/bpicdecode_test/main.c)
|
||||||
|
|
||||||
|
# building
|
||||||
|
|
||||||
|
add_library(bpic ${BPIC_HEADERS} ${BPIC_SOURCES})
|
||||||
|
set_target_property(TARGET bpic PROPERTY C_STANDARD 90)
|
||||||
|
|
||||||
|
target_include_directories(bpic PUBLIC src/bpic/include)
|
||||||
|
set_target_properties(bpic PROPERTIES PUBLIC_HEADER bpic.h)
|
||||||
|
|
||||||
|
add_executable(bpicencode ${BPICENCODE_SOURCES})
|
||||||
|
add_executable(bpicdecode ${BPICDECODE_SOURCES})
|
||||||
|
add_executable(bpicencode_test ${BPICENCODE_TEST_SOURCES})
|
||||||
|
add_executable(bpicdecode_test ${BPICDECODE_TEST_SOURCES})
|
||||||
|
|
||||||
|
|
||||||
|
# linking
|
||||||
|
message(STATUS ${PNG_LIBRARIES})
|
||||||
|
target_link_libraries(bpic ${PNG_LIBRARIES})
|
||||||
|
target_link_libraries(bpicencode bpic)
|
||||||
|
target_link_libraries(bpicdecode bpic)
|
||||||
|
target_link_libraries(bpicdecode_test bpic)
|
||||||
|
target_link_libraries(bpicencode_test bpic)
|
||||||
|
|
||||||
|
|
||||||
|
# installing
|
||||||
|
|
||||||
|
install(
|
||||||
|
TARGETS bpic
|
||||||
|
EXPORT bpic
|
||||||
|
LIBRARY DESTINATION lib
|
||||||
|
ARCHIVE DESTINATION lib
|
||||||
|
PUBLIC_HEADER DESTINATION include/${PROJECT_NAME}
|
||||||
|
)
|
21
LICENSE
Normal file
21
LICENSE
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2023 theBreadCompany
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
28
README.md
Normal file
28
README.md
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
# libbpic
|
||||||
|
|
||||||
|
**P**NG **V**isual **S**torage **F**format library to encode data to images and back.
|
||||||
|
|
||||||
|
## disclaimer
|
||||||
|
|
||||||
|
This library is not considered to be safe for production and is not delivered under any kind of warranty! Use with caution and only for educational and research purposes!
|
||||||
|
|
||||||
|
## building
|
||||||
|
|
||||||
|
Simply call:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone https://github.com/thebreadcompany/libbpic
|
||||||
|
cd libbpic
|
||||||
|
mkdir build && cd build
|
||||||
|
cmake .. && cmake --build .
|
||||||
|
```
|
||||||
|
|
||||||
|
You can find the library
|
||||||
|
|
||||||
|
## installing
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## usage
|
||||||
|
|
||||||
|
## use cases
|
BIN
src/.DS_Store
vendored
Normal file
BIN
src/.DS_Store
vendored
Normal file
Binary file not shown.
BIN
src/bpic/.DS_Store
vendored
Normal file
BIN
src/bpic/.DS_Store
vendored
Normal file
Binary file not shown.
37
src/bpic/common_utils.c
Normal file
37
src/bpic/common_utils.c
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
//
|
||||||
|
// common_utils.c
|
||||||
|
// bpic
|
||||||
|
//
|
||||||
|
// Created by theBreadCompany on 04.03.23.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <common_utils.h>
|
||||||
|
|
||||||
|
void throw_err(const char* message, int error) {
|
||||||
|
char *category = error ? "ERROR:" : "NOTE:";
|
||||||
|
fprintf(stderr, "%s %s", category, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
void debug(FILE *pipe, const char *message, ...) {
|
||||||
|
#if DEBUG || debug
|
||||||
|
fprintf(pipe, "%s", message);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
bpic_message bpic_error_input_file_null = "Input file is null!";
|
||||||
|
bpic_message bpic_error_input_buffer_null = "Input buffer is null!";
|
||||||
|
bpic_message bpic_error_input_buffer_small = "Input buffer too small!";
|
||||||
|
bpic_message bpic_warn_encoding_invalid = "Encoding is invalid, defaulting to bitwise (0)";
|
||||||
|
bpic_message bpic_warn_pxsize_null = "Pixel size is null, defaulting to 2";
|
||||||
|
|
||||||
|
uint16_t fletcher16(const unsigned char *data, size_t size) {
|
||||||
|
uint16_t sum1 = 0;
|
||||||
|
uint16_t sum2 = 0;
|
||||||
|
|
||||||
|
for (int index = 0; index < size; index++) {
|
||||||
|
sum1 = (sum1 + data[index]) % 0xFF;
|
||||||
|
sum2 = (sum2 + sum1) % 0xFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (sum2 << 8) | sum1;
|
||||||
|
}
|
212
src/bpic/decode.c
Normal file
212
src/bpic/decode.c
Normal file
|
@ -0,0 +1,212 @@
|
||||||
|
//
|
||||||
|
// decode.c
|
||||||
|
// bpic
|
||||||
|
//
|
||||||
|
// Created by theBreadCompany on 04.03.23.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "decode.h"
|
||||||
|
|
||||||
|
void read_to_buffer(png_structp png_ptr, png_bytep data, png_size_t length);
|
||||||
|
|
||||||
|
decoded_data *bpic_decode_memory(encoded_data *data, bool *checksum_matching) {
|
||||||
|
|
||||||
|
if(!data->buffer) { // is there even data
|
||||||
|
throw_err(bpic_error_input_buffer_null, 0);
|
||||||
|
return (void*)bpic_error_input_buffer_null;
|
||||||
|
}
|
||||||
|
if(data->size < 7) { // is there enough data to hold at least a header
|
||||||
|
throw_err(bpic_error_input_buffer_small, 0);
|
||||||
|
return (void*)bpic_error_input_buffer_small;
|
||||||
|
}
|
||||||
|
|
||||||
|
png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
|
||||||
|
png_infop png_info = png_create_info_struct(png_ptr);
|
||||||
|
|
||||||
|
//printf("%zu\n", data->size);
|
||||||
|
/*
|
||||||
|
mem_decode *input = malloc(sizeof(mem_decode));
|
||||||
|
input->buffer = data->buffer;
|
||||||
|
input->size = data->size;
|
||||||
|
input->pos = 0;
|
||||||
|
png_set_read_fn(png_ptr, input, read_to_buffer);
|
||||||
|
*/
|
||||||
|
|
||||||
|
decoded_data *output = bpic_decode_file(fmemopen(data->buffer, data->size, "r"), checksum_matching);
|
||||||
|
|
||||||
|
png_free(png_ptr, png_info);
|
||||||
|
png_destroy_read_struct(&png_ptr, NULL, NULL);
|
||||||
|
|
||||||
|
//free(png_ptr);
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
decoded_data* bpic_decode_file(FILE *input, bool *checksum_matching) {
|
||||||
|
fseek(input, 0, SEEK_SET);
|
||||||
|
|
||||||
|
png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
|
||||||
|
png_infop png_info = png_create_info_struct(png_ptr);
|
||||||
|
|
||||||
|
if(input) {
|
||||||
|
png_init_io(png_ptr, input);
|
||||||
|
} else {
|
||||||
|
printf("Failed to init png with file!\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
image_data *output = bpic_decode_png(png_ptr, png_info, checksum_matching);
|
||||||
|
|
||||||
|
png_free(png_ptr, png_info);
|
||||||
|
png_destroy_read_struct(&png_ptr, NULL, NULL);
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
decoded_data* bpic_decode_png(png_structp png_ptr, png_infop png_info, bool *checksum_matching) {
|
||||||
|
|
||||||
|
png_set_keep_unknown_chunks(png_ptr, PNG_HANDLE_CHUNK_IF_SAFE, (png_bytep)"pvSF", 1);
|
||||||
|
|
||||||
|
png_read_info(png_ptr, png_info);
|
||||||
|
|
||||||
|
printf("%u x %u\n", png_get_image_height(png_ptr, png_info), png_get_image_width(png_ptr, png_info));
|
||||||
|
|
||||||
|
png_unknown_chunkp chunks;
|
||||||
|
int chunk_count = png_get_unknown_chunks(png_ptr, png_info, &chunks);
|
||||||
|
|
||||||
|
bpic_info bpic_chunk;
|
||||||
|
bpic_chunk.length = 0;
|
||||||
|
if(chunk_count) { // are there unknown chunks
|
||||||
|
for(uint8_t i = 0; i < chunk_count; i++) { // for every unknown chunk
|
||||||
|
png_unknown_chunk chunk = chunks[i]; // store chunk
|
||||||
|
|
||||||
|
char *name = malloc(5); // alloc name
|
||||||
|
memcpy(name, chunk.name, 5); // copy name (same procedure as setting it
|
||||||
|
if(!strcmp(name, "pvSF") && chunk.size == 7) { // if name is pvSF header name and size is 12 bytes
|
||||||
|
bpic_chunk.px_size = pow(2, chunk.data[0] >> 3); // remember, the stored pxsize is a power of 2 leftshifted by 2
|
||||||
|
bpic_chunk.encoding = chunk.data[0] & 0b11;
|
||||||
|
memcpy(&bpic_chunk.length, chunk.data + 1, 4);
|
||||||
|
memcpy(&bpic_chunk.fletcher16, chunk.data + 5, 2);
|
||||||
|
|
||||||
|
for(int byte = 0; byte < 7; byte++) {
|
||||||
|
for(int bit = 1; bit < 9; bit++) {
|
||||||
|
printf("%s", chunk.data[byte] >> (8 - bit) & 1 ? "1" : "0");
|
||||||
|
}
|
||||||
|
printf(" ");
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
free(name);
|
||||||
|
free(chunk.data);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw_err("input is missing unknown chunks, meaning that the pvSF chunk is also missing!", 0);
|
||||||
|
return (void*)"input is missing unknown chunks, meaning that the pvSF chunk is also missing!";
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!bpic_chunk.length) {
|
||||||
|
fprintf(stderr, "Missing data length in bpic chunk!\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(chunks);
|
||||||
|
printf("pxsize: %u; encoding: %u; length: %zu; checksum: %u\n", bpic_chunk.px_size, bpic_chunk.encoding, bpic_chunk.length, bpic_chunk.fletcher16);
|
||||||
|
|
||||||
|
int width = png_get_image_width(png_ptr, png_info);// * bpic_chunk.px_size;
|
||||||
|
int height = png_get_image_height(png_ptr, png_info);// * bpic_chunk.px_size;
|
||||||
|
|
||||||
|
png_bytep *row_data = png_malloc(png_ptr, sizeof(png_bytep) * height * bpic_chunk.px_size);
|
||||||
|
for(int y = 0; y < height; y++) row_data[y] = png_malloc(png_ptr, sizeof(png_byte) * width * bpic_chunk.px_size);
|
||||||
|
png_set_rows(png_ptr, png_info, row_data);
|
||||||
|
png_read_image(png_ptr, row_data);
|
||||||
|
png_read_end(png_ptr, NULL);
|
||||||
|
|
||||||
|
|
||||||
|
int bits = png_get_bit_depth(png_ptr, png_info);
|
||||||
|
|
||||||
|
// create a filebuffer that can hold as many bytes as needed according to the header
|
||||||
|
unsigned char *filebuffer = malloc(bpic_chunk.length);//(width/bits * height/bits);//(bpic_chunk.length);
|
||||||
|
// if encoding is bitwise
|
||||||
|
if(!bpic_chunk.encoding) {
|
||||||
|
// if the data is encoded in an 8 bit grayscale image
|
||||||
|
if(bits == 8) {
|
||||||
|
// for every [px_size]th in the data; also init a bit count
|
||||||
|
for(int y = 0, bit_i = 0; y < height; y += bpic_chunk.px_size) {
|
||||||
|
// for every [px_size]th column; also increment the bit count
|
||||||
|
for(int x = 0; x < width && (bit_i >> 3) < bpic_chunk.length; x += bpic_chunk.px_size, bit_i++) {
|
||||||
|
// store the pixel data
|
||||||
|
png_byte px = row_data[y][x * bpic_chunk.px_size];
|
||||||
|
// store the corresponding the data
|
||||||
|
uint8_t value = px & (0x80 >> (bit_i & 0b111));
|
||||||
|
// add the data in the byte of the buffer; 8 bit = 1 byte, so divide the bit count by 8 to get the byte position
|
||||||
|
filebuffer[bit_i >> 3] += value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// if the data is encoded as a 1 bit grayscale image
|
||||||
|
} else if(bits == 1) {
|
||||||
|
// the image widths are required to be divisible by 8 to make parsing easier
|
||||||
|
// basically same algorithm, but now
|
||||||
|
for(int y = 0, bit_i = 0; y < height; y += bpic_chunk.px_size) {
|
||||||
|
// for every [px_size]th column; also increment the bit count
|
||||||
|
for(int x = 0; x < width && (bit_i >> 3) < bpic_chunk.length; x += bpic_chunk.px_size, bit_i++) {
|
||||||
|
// store the pixel data
|
||||||
|
png_byte px = row_data[y][x * bpic_chunk.px_size];
|
||||||
|
// store the corresponding the data
|
||||||
|
uint8_t value = px & (0x80 >> (bit_i & 0b111));
|
||||||
|
// add the data in the byte of the buffer; 8 bit = 1 byte, so divide the bit count by 8 to get the byte position
|
||||||
|
filebuffer[bit_i >> 3] += value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// unknown bit count, cancel...
|
||||||
|
} else {
|
||||||
|
|
||||||
|
}
|
||||||
|
// othrwise the encoding is bytewise
|
||||||
|
} else {
|
||||||
|
// this is far more straightforward as the rows literally represent the data
|
||||||
|
if(bpic_chunk.px_size == 1) {
|
||||||
|
// every row, except the last as it may break the available range of the file buffer
|
||||||
|
for(int y = 0; y < height - 1; y++) {
|
||||||
|
// copy the row to the filebuffer with an offset of the number of already processed bytes
|
||||||
|
memcpy(filebuffer + y * width, row_data[y], width);
|
||||||
|
}
|
||||||
|
// the required data size to be copied is calculated as the required length minus the already parsed length
|
||||||
|
memcpy(filebuffer + (height - 1) * width, row_data[height-1], bpic_chunk.length - width * (height - 1));
|
||||||
|
// except if the pixel size is > 1, then only every [px_size]th pixel is valid data
|
||||||
|
} else {
|
||||||
|
// for every [px_size]th row except the last
|
||||||
|
for(int y = 0; y < height - bpic_chunk.px_size; y += bpic_chunk.px_size) {
|
||||||
|
// for every [px_size]th column
|
||||||
|
for(int x = 0; x < width; x += bpic_chunk.px_size) {
|
||||||
|
// copy every [px_size]th byte to the buffer at offset of the current byte
|
||||||
|
memcpy(filebuffer + y / bpic_chunk.px_size * width + x / bpic_chunk.px_size, row_data[y] + x * bpic_chunk.px_size, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// separatly go through the last row as it may contain more data than required
|
||||||
|
for(int x = 0; x < bpic_chunk.length - (height - 1) * width; x += bpic_chunk.px_size) {
|
||||||
|
memcpy(filebuffer + (height - 1) * width + x / bpic_chunk.px_size, row_data[height - 1] + x * bpic_chunk.px_size, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for(int y = 0; y < height; y++) png_free(png_ptr, row_data[y]);
|
||||||
|
png_free(png_ptr, row_data);
|
||||||
|
|
||||||
|
uint16_t checksum = fletcher16(filebuffer, bpic_chunk.length);
|
||||||
|
printf("Checksum of decoded data: %u\n", checksum);
|
||||||
|
*checksum_matching = bpic_chunk.fletcher16 == checksum;
|
||||||
|
|
||||||
|
|
||||||
|
decoded_data *output = malloc(sizeof(decoded_data));
|
||||||
|
output->buffer = filebuffer;
|
||||||
|
output->size = bpic_chunk.length;
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
void read_to_buffer(png_structp png_ptr, png_bytep data, png_size_t length) {
|
||||||
|
mem_decode *data_info = png_get_io_ptr(png_ptr);
|
||||||
|
if(data_info->size < data_info->pos + length) {
|
||||||
|
printf("How... The input is bigger than expected, already at %lu/%zu\n", data_info->pos + length, data_info->size);
|
||||||
|
}
|
||||||
|
memcpy(data, data_info->buffer + data_info->pos, length);
|
||||||
|
data_info->pos += length;
|
||||||
|
}
|
243
src/bpic/encode.c
Normal file
243
src/bpic/encode.c
Normal file
|
@ -0,0 +1,243 @@
|
||||||
|
//
|
||||||
|
// encode.c
|
||||||
|
// bpic
|
||||||
|
//
|
||||||
|
// Created by theBreadCompany on 04.03.23.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "encode.h"
|
||||||
|
|
||||||
|
void write_to_buffer(png_structp png_ptr, png_bytep data, png_size_t length);
|
||||||
|
|
||||||
|
png_bytepp convert_bitwise_1bit_grayscale(image_data *data, png_structp png_ptr, png_infop info_ptr);
|
||||||
|
png_bytepp convert_bitwise_8bit_grayscale(image_data *data, png_structp png_ptr, png_infop info_ptr);
|
||||||
|
png_bytepp convert_bytewise_8bit_rgb(image_data *data, png_structp png_ptr, png_infop info_ptr);
|
||||||
|
|
||||||
|
png_bytepp convert_bitwise_1bit_grayscale(image_data *data, png_structp png_ptr, png_infop info_ptr) {
|
||||||
|
int width = round(sqrt((double)(data->size << 3)));
|
||||||
|
int height = round((data->size << 3) / (double)width);
|
||||||
|
|
||||||
|
png_bytepp row_data = convert_bytewise_8bit_rgb(data, png_ptr, info_ptr);
|
||||||
|
|
||||||
|
png_set_IHDR(png_ptr, info_ptr, width, height, 1, PNG_COLOR_TYPE_GRAY, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
|
||||||
|
|
||||||
|
return row_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
png_bytepp convert_bitwise_8bit_grayscale(image_data *data, png_structp png_ptr, png_infop info_ptr) {
|
||||||
|
// width as the squareroot of the size times 8 because each bit requires a separate pixel; round app for
|
||||||
|
int width = round(sqrt((double)(data->size << 3)));
|
||||||
|
// height is size divided by width,
|
||||||
|
//int height = round(data->size * 8 / (double)width);
|
||||||
|
int height = width + (width * width < data->size << 3);
|
||||||
|
// embed image information
|
||||||
|
png_set_IHDR(png_ptr, info_ptr, width, height, 8, PNG_COLOR_TYPE_GRAY, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
|
||||||
|
// alloc enough memory to hold the pointers to the individual rows
|
||||||
|
png_byte **row_data = calloc(height, sizeof(png_bytep));
|
||||||
|
// for every row
|
||||||
|
for(int y = 0; y < height; y++) {
|
||||||
|
// alloc row memory
|
||||||
|
row_data[y] = calloc(width, sizeof(png_byte));
|
||||||
|
// for every column
|
||||||
|
for(int x = 0; x < width; x++) {
|
||||||
|
// get bit index
|
||||||
|
int px_i = y * width + x;
|
||||||
|
// check if already at EOF/EOB
|
||||||
|
if(px_i == (data->size << 3)) return row_data;
|
||||||
|
// get on/of state at bit index
|
||||||
|
uint8_t value = data->buffer[px_i >> 3] >> (7 - px_i % 8) & 1;
|
||||||
|
// store value at the current position in the image data (assigning 266 to uint8 results in 0, as 256 > uint8)
|
||||||
|
row_data[y][x] = value * 0xFF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return row_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
png_bytepp convert_bytewise_8bit_rgb(image_data *data, png_structp png_ptr, png_infop info_ptr) {
|
||||||
|
int width = round(sqrt((double)data->size));
|
||||||
|
int height = width;
|
||||||
|
|
||||||
|
png_bytep *row_data = calloc(height-1, sizeof(png_bytep));
|
||||||
|
|
||||||
|
for(int y = 0; y < height - 1; y++) {
|
||||||
|
// alloc row memory
|
||||||
|
row_data[y] = malloc(width * sizeof(png_byte));
|
||||||
|
// literally copy chunks of the source to the PNG
|
||||||
|
memcpy(row_data[y], data->buffer + y * width, width);
|
||||||
|
}
|
||||||
|
// copy the last chunk separatly as it may be smaller than the width -> prevent random data
|
||||||
|
row_data[height-1] = calloc(width, sizeof(png_byte));
|
||||||
|
printf("Copying last chunk to row %d of length %lu, starting at index %d in buffer\n", height-1, data->size - width*(height-1), (height-1)*width);
|
||||||
|
memcpy(row_data[height-1], data->buffer + (height-1)*width, data->size - width*(height-1));
|
||||||
|
|
||||||
|
png_set_IHDR(png_ptr, info_ptr, width, height, 8, PNG_COLOR_TYPE_GRAY, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
|
||||||
|
|
||||||
|
return row_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
image_data *bpic_encode_memory(image_data *data, bpic_info* info) {
|
||||||
|
int width = 0;
|
||||||
|
int height = 0;
|
||||||
|
|
||||||
|
if(!data->buffer) {
|
||||||
|
throw_err(bpic_error_input_buffer_null, 0);
|
||||||
|
return (void*)bpic_error_input_buffer_null;
|
||||||
|
}
|
||||||
|
if(!info) info = (bpic_info*) malloc(sizeof(bpic_info));
|
||||||
|
|
||||||
|
|
||||||
|
if(info->encoding != bpic_bitwise_encoding && info->encoding != bpic_bytewise_encoding) info->encoding = bpic_bitwise_encoding;
|
||||||
|
//if(!info->px_size) info->px_size = 4;
|
||||||
|
//if(!info->px_size) info->px_size = 1;
|
||||||
|
info->px_size = 1;
|
||||||
|
|
||||||
|
//if(!data->size) data->size = data->size;
|
||||||
|
|
||||||
|
if(info->encoding == bpic_bitwise_encoding) {
|
||||||
|
width = round(sqrt((double)(data->size << 3)));
|
||||||
|
//width += width % 8;
|
||||||
|
height = width;//round(data->size * 8 / (double)width);
|
||||||
|
} else if(info->encoding == bpic_bytewise_encoding) {
|
||||||
|
width = sqrt((double)data->size);
|
||||||
|
height = width + (width * width < data->size);
|
||||||
|
} else {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("%u x %u -> %u x %u\n", width, height, width * info->px_size, height * info->px_size);
|
||||||
|
|
||||||
|
info->fletcher16 = fletcher16(data->buffer, data->size);
|
||||||
|
|
||||||
|
png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
|
||||||
|
png_infop info_ptr = png_create_info_struct(png_ptr);
|
||||||
|
|
||||||
|
//png_bytep image_data = malloc(sizeof(png_byte) * width * height);
|
||||||
|
png_byte **row_data = NULL;
|
||||||
|
if(!info->encoding) {
|
||||||
|
clock_t start_bit8 = clock();
|
||||||
|
row_data = convert_bitwise_8bit_grayscale(data, png_ptr, info_ptr); // works
|
||||||
|
clock_t end_bit8 = clock();
|
||||||
|
printf("8-bit / grayscale; time: %f sec\n", (double)(end_bit8 - start_bit8)/CLOCKS_PER_SEC);
|
||||||
|
} else {
|
||||||
|
clock_t start_byte = clock();
|
||||||
|
row_data = convert_bytewise_8bit_rgb(data, png_ptr, info_ptr); // why u no work
|
||||||
|
clock_t end_byte = clock();
|
||||||
|
printf("1-byte / grayscale; time: %f sec\n", (double)(end_byte - start_byte)/CLOCKS_PER_SEC);
|
||||||
|
}
|
||||||
|
|
||||||
|
png_byte **scaled_data = NULL;
|
||||||
|
|
||||||
|
// then scale it to its actual size
|
||||||
|
if(info->px_size > 1) {
|
||||||
|
// cache row size
|
||||||
|
int row_size = sizeof(png_byte) * width * info->px_size * 2;
|
||||||
|
// create a pointer to the scaled up data
|
||||||
|
scaled_data = malloc(height * info->px_size * sizeof(png_bytep));
|
||||||
|
// alloc memory here as rows will be allocated that normally would not be in range with the row index
|
||||||
|
for(int y = 0; y < height * info->px_size; y++) scaled_data[y] = malloc(row_size);
|
||||||
|
// for every [pixelsize]th row
|
||||||
|
for(int y = 0; y < height * info->px_size; y+=info->px_size) {
|
||||||
|
// for every [pixelsize]th column
|
||||||
|
for(int x = 0; x < width * info->px_size; x+=info->px_size) {
|
||||||
|
// copy the pixeldata from the 1x1 version to the scaled version; i.e. px_size=4, y=4, x=4 results in row_data[1][1]
|
||||||
|
memcpy(&scaled_data[y][x], &row_data[(y / info->px_size)][x / info->px_size], sizeof(png_byte));
|
||||||
|
// fill the following pixels with the data at the position in scaled_data, in the previous example y=4 and x=5,6,7
|
||||||
|
for(int x_offset = 1; x_offset < info->px_size; x_offset++) memcpy(&scaled_data[y][x+x_offset], &scaled_data[y][x], sizeof(png_byte));
|
||||||
|
}
|
||||||
|
// copy the previously calculated row "down", meaning the data from y=4 to y=5,6,7
|
||||||
|
for(int y_offset = 1; y_offset < info->px_size; y_offset++) memcpy(scaled_data[y+y_offset], scaled_data[y], row_size);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// if the pixel size is actually 1, just point to the already calculated data
|
||||||
|
scaled_data = row_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
png_bytep bpic_data = calloc(7, sizeof(png_byte));
|
||||||
|
|
||||||
|
bpic_data[0] += (uint8_t)sqrt(info->px_size) << 2;
|
||||||
|
bpic_data[0] += info->encoding;
|
||||||
|
memcpy(bpic_data + 1, &data->size, sizeof(uint32_t));
|
||||||
|
memcpy(bpic_data + 5, &info->fletcher16, sizeof(uint16_t));
|
||||||
|
|
||||||
|
for(int byte = 0; byte < 7; byte++) {
|
||||||
|
for(int bit = 1; bit < 9; bit++) {
|
||||||
|
printf("%s", bpic_data[byte] >> (8 - bit) & 1 ? "1" : "0");
|
||||||
|
}
|
||||||
|
printf(" ");
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
printf("pxsize: %u; encoding: %u; length: %zu; checksum: %u\n", info->px_size, info->encoding, data->size, info->fletcher16);
|
||||||
|
|
||||||
|
// Finally, set up the libpng stuff for writing
|
||||||
|
|
||||||
|
mem_encode *target = malloc(sizeof(mem_encode));
|
||||||
|
target->buffer = NULL;
|
||||||
|
target->size = 0;
|
||||||
|
png_set_write_fn(png_ptr, target, write_to_buffer, NULL);
|
||||||
|
|
||||||
|
png_bytep chunk_data = calloc(7, sizeof(png_byte));
|
||||||
|
memcpy(chunk_data, bpic_data, 7);
|
||||||
|
|
||||||
|
png_size_t size = 7;
|
||||||
|
png_bytep type = (png_bytep)"pvSF";
|
||||||
|
|
||||||
|
png_write_info(png_ptr, info_ptr);
|
||||||
|
png_write_chunk(png_ptr, type, bpic_data, size);
|
||||||
|
png_write_image(png_ptr, scaled_data);
|
||||||
|
png_write_end(png_ptr, info_ptr);
|
||||||
|
|
||||||
|
//fclose(out);
|
||||||
|
|
||||||
|
png_destroy_info_struct(png_ptr, &info_ptr);
|
||||||
|
png_destroy_write_struct(&png_ptr, &info_ptr);
|
||||||
|
|
||||||
|
|
||||||
|
if(info->px_size > 1) {
|
||||||
|
for(int y = 0; y < height; y++) free(scaled_data[y]);
|
||||||
|
free(scaled_data);
|
||||||
|
}
|
||||||
|
for(int y = 0; y < height / info->px_size; y++) free(row_data[y]);
|
||||||
|
free(row_data);
|
||||||
|
free(bpic_data);
|
||||||
|
free(chunk_data);
|
||||||
|
free(info);
|
||||||
|
|
||||||
|
return target;
|
||||||
|
}
|
||||||
|
|
||||||
|
image_data *bpic_encode_file(FILE *input, bpic_info* info) {
|
||||||
|
if(!input) throw_err(bpic_error_input_file_null, 1);
|
||||||
|
|
||||||
|
// prepare file
|
||||||
|
fseek(input, 0, SEEK_END);
|
||||||
|
size_t flen = ftell(input);
|
||||||
|
fseek(input, 0, SEEK_SET);
|
||||||
|
|
||||||
|
image_data *data = malloc(sizeof(image_data));
|
||||||
|
data->buffer = malloc(flen);
|
||||||
|
fread(data->buffer, sizeof(unsigned char), flen, input);
|
||||||
|
data->size = flen;
|
||||||
|
|
||||||
|
encoded_data *output = bpic_encode_memory(data, info);
|
||||||
|
|
||||||
|
free(data->buffer);
|
||||||
|
free(data);
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
void write_to_buffer(png_structp png_ptr, png_bytep data, png_size_t length) {
|
||||||
|
mem_encode* data_info = png_get_io_ptr(png_ptr);
|
||||||
|
size_t size = data_info->size + length;
|
||||||
|
|
||||||
|
if(data_info->buffer) {
|
||||||
|
data_info->buffer = realloc(data_info->buffer, size);
|
||||||
|
} else {
|
||||||
|
data_info->buffer = malloc(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(data_info->buffer + data_info->size, data, length);
|
||||||
|
data_info->size += length;
|
||||||
|
}
|
15
src/bpic/include/bpic.h
Normal file
15
src/bpic/include/bpic.h
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
//
|
||||||
|
// bpic.h
|
||||||
|
// VisualStorageKit
|
||||||
|
//
|
||||||
|
// Created by theBreadCompany on 04.03.23.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef bpic_h
|
||||||
|
#define bpic_h
|
||||||
|
|
||||||
|
#include "encode.h"
|
||||||
|
#include "decode.h"
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* bpic_h */
|
78
src/bpic/include/common_utils.h
Normal file
78
src/bpic/include/common_utils.h
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
//
|
||||||
|
// common_utils.h
|
||||||
|
// bpic
|
||||||
|
//
|
||||||
|
// Created by theBreadCompany on 04.03.23.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef common_utils_h
|
||||||
|
#define common_utils_h
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <png.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <strings.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
|
||||||
|
#pragma mark - Header Information
|
||||||
|
|
||||||
|
#define BPIC_BITWISE_ENCODING 0b00
|
||||||
|
#define BPIC_BYTEWISE_ENCODING 0b01
|
||||||
|
|
||||||
|
#define BPIC_UNCOMPRESSED 0b00
|
||||||
|
#define BPIC_COMPRESSED 0b10
|
||||||
|
|
||||||
|
enum bpic_encoding {
|
||||||
|
bpic_bitwise_encoding,
|
||||||
|
bpic_bytewise_encoding,
|
||||||
|
//bpic_bitwise_zipped_encoded,
|
||||||
|
//bpic_bytewise_zipped_encoded
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t px_size; // first 6 bits (limits px size to up to 2^6-1 = 63, which should be more than sufficient
|
||||||
|
enum bpic_encoding encoding; // 7th and 8th bit, allowing for 4 encodings (only two used for now
|
||||||
|
size_t length; // 9th - 40 th bit (4 bytes)
|
||||||
|
uint16_t fletcher16; // 41st - 56th bit (2 bytes)
|
||||||
|
|
||||||
|
} bpic_info;
|
||||||
|
|
||||||
|
#pragma mark - Helper structs
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
unsigned char *buffer;
|
||||||
|
size_t size;
|
||||||
|
} mem_encode;
|
||||||
|
|
||||||
|
typedef mem_encode image_data;
|
||||||
|
typedef image_data encoded_data;
|
||||||
|
typedef image_data decoded_data;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
unsigned char *buffer;
|
||||||
|
size_t size;
|
||||||
|
png_uint_32 pos;
|
||||||
|
} mem_decode;
|
||||||
|
|
||||||
|
#pragma mark - Crypto
|
||||||
|
|
||||||
|
uint16_t fletcher16(const unsigned char *data, size_t size); //
|
||||||
|
|
||||||
|
#pragma mark - Error Handling
|
||||||
|
|
||||||
|
typedef const char* bpic_message;
|
||||||
|
extern bpic_message bpic_error_input_file_null;
|
||||||
|
extern bpic_message bpic_error_input_buffer_null;
|
||||||
|
extern bpic_message bpic_error_input_buffer_small;
|
||||||
|
extern bpic_message bpic_warn_encoding_invalid;
|
||||||
|
extern bpic_message bpic_warn_pxsize_null;
|
||||||
|
|
||||||
|
|
||||||
|
void throw_err(bpic_message message, int error);
|
||||||
|
void debug(FILE *pipe, const char *message, ...);
|
||||||
|
|
||||||
|
#endif /* common_utils_h */
|
43
src/bpic/include/decode.h
Normal file
43
src/bpic/include/decode.h
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
//
|
||||||
|
// decode.h
|
||||||
|
// bpic
|
||||||
|
//
|
||||||
|
// Created by theBreadCompany on 04.03.23.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef decode_h
|
||||||
|
#define decode_h
|
||||||
|
|
||||||
|
#include "common_utils.h"
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
decode memory
|
||||||
|
|
||||||
|
@param data The buffer to decode
|
||||||
|
@param checksum_matching A pointer that stores stores whether the checksum matches the one encoded in the image
|
||||||
|
@return A pointer to the decoded memory or a bpic\_message on failure.
|
||||||
|
*/
|
||||||
|
decoded_data *bpic_decode_memory(encoded_data *data, bool *checksum_matching);
|
||||||
|
/**
|
||||||
|
decode a file
|
||||||
|
|
||||||
|
@param input A pointer to a file to decode; NULL is invalid
|
||||||
|
@param checksum_matching A pointer that stores stores whether the checksum matches the one encoded in the image
|
||||||
|
@returns A pointer to the decoded memory or a bpic\_message on failure.
|
||||||
|
*/
|
||||||
|
decoded_data *bpic_decode_file(FILE *input, bool *checksum_matching);
|
||||||
|
|
||||||
|
/**
|
||||||
|
Decode a png
|
||||||
|
|
||||||
|
This method may only be invoced via `bpic_decode_file(FILE *input)` or `bpic_decode_memory(encoded_data *data)`.
|
||||||
|
|
||||||
|
@param png_ptr A pointer to the png_ptr that is to be decoded. The input has to be set up, either via `png_set_read_fn` or `png_init_io`
|
||||||
|
@param png_info A pointer to a `png_info` struct if already available
|
||||||
|
@param checksum_matching A pointer that stores stores whether the checksum matches the one encoded in the image
|
||||||
|
@return A pointer to the decoded data
|
||||||
|
*/
|
||||||
|
decoded_data *bpic_decode_png(png_structrp png_ptr, png_inforp png_info, bool *checksum_matching);
|
||||||
|
|
||||||
|
#endif /* decode_h */
|
31
src/bpic/include/encode.h
Normal file
31
src/bpic/include/encode.h
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
//
|
||||||
|
// encode.h
|
||||||
|
// bpic
|
||||||
|
//
|
||||||
|
// Created by theBreadCompany on 04.03.23.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef encode_h
|
||||||
|
#define encode_h
|
||||||
|
|
||||||
|
#include "common_utils.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
encode memory
|
||||||
|
|
||||||
|
@param data The memory buffer to encode
|
||||||
|
@param info A bpic_info struct containing parameters like encoding and any calculated variables on return; NULL is valid.
|
||||||
|
@returns A pointer to the encoded memory or a bpic\_message on if an error occured.
|
||||||
|
*/
|
||||||
|
encoded_data *bpic_encode_memory(image_data *data, bpic_info* info);
|
||||||
|
|
||||||
|
/**
|
||||||
|
encode a file
|
||||||
|
|
||||||
|
@param input A pointer to the file to encode; NULL is invalid
|
||||||
|
@param info A bpic_info struct containing parameters like encoding and any calculated variables on return; NULL is valid.
|
||||||
|
@returns A pointer to the encoded memory or a bpic\_message on if an error occured.
|
||||||
|
*/
|
||||||
|
encoded_data *bpic_encode_file(FILE *input, bpic_info* info);
|
||||||
|
|
||||||
|
#endif /* encode_h */
|
74
src/bpicdecode/main.c
Normal file
74
src/bpicdecode/main.c
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
//
|
||||||
|
// main.m
|
||||||
|
// bpicdecode
|
||||||
|
//
|
||||||
|
// Created by theBreadCompany on 28.02.23.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "bpic.h"
|
||||||
|
|
||||||
|
|
||||||
|
int main(int argc, const char * argv[]) {
|
||||||
|
FILE *inputFile;
|
||||||
|
FILE *outputFile;
|
||||||
|
|
||||||
|
if(argc < 2) {
|
||||||
|
fprintf(stderr, "Missing path to file!\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
inputFile = fopen(argv[1], "rb");
|
||||||
|
if(!inputFile) {
|
||||||
|
fprintf(stderr, "Could not open file %s\n", argv[2]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// input as memory
|
||||||
|
encoded_data *input = malloc(sizeof(encoded_data));
|
||||||
|
fseek(inputFile, 0, SEEK_END);
|
||||||
|
input->size = ftell(inputFile);
|
||||||
|
fseek(inputFile, 0, SEEK_SET);
|
||||||
|
input->buffer = malloc(input->size);
|
||||||
|
fread(input->buffer, sizeof(unsigned char), input->size, inputFile);
|
||||||
|
|
||||||
|
|
||||||
|
clock_t start = clock();
|
||||||
|
bool checksum_matching = false;
|
||||||
|
//encoded_data *data = bpic_decode_file(inputFile);
|
||||||
|
encoded_data *data = bpic_decode_memory(input, &checksum_matching);
|
||||||
|
clock_t end = clock();
|
||||||
|
|
||||||
|
free(input->buffer);
|
||||||
|
free(input);
|
||||||
|
fclose(inputFile);
|
||||||
|
printf("Done in %f seconds.\n", (double)(end - start) / CLOCKS_PER_SEC);
|
||||||
|
|
||||||
|
uint8_t len = strlen(argv[1]) + 5;
|
||||||
|
char *oname = calloc(len, sizeof(const char));
|
||||||
|
strcpy(oname, argv[1]);
|
||||||
|
strcpy(oname + len - 5, ".png");
|
||||||
|
outputFile = fopen(oname, "wb");
|
||||||
|
|
||||||
|
int error = 0;
|
||||||
|
if(fwrite(data->buffer, sizeof(unsigned char), data->size, outputFile) != data->size * sizeof(unsigned char)) {
|
||||||
|
fprintf(stderr, "Failed writing output file!");
|
||||||
|
error = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(outputFile);
|
||||||
|
|
||||||
|
//free(inputFile);
|
||||||
|
free(oname);
|
||||||
|
free(data->buffer);
|
||||||
|
free(data);
|
||||||
|
//free(outputFile);
|
||||||
|
inputFile = NULL;
|
||||||
|
outputFile = NULL;
|
||||||
|
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
5
src/bpicdecode_test/main.c
Normal file
5
src/bpicdecode_test/main.c
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
#include <bpic.h>
|
||||||
|
|
||||||
|
int main(int argc, const char *argv[]) {
|
||||||
|
return 0;
|
||||||
|
}
|
121
src/bpicencode/main.c
Normal file
121
src/bpicencode/main.c
Normal file
|
@ -0,0 +1,121 @@
|
||||||
|
//
|
||||||
|
// main.m
|
||||||
|
// bpicencode
|
||||||
|
//
|
||||||
|
// Created by theBreadCompany on 28.02.23.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include "bpic.h"
|
||||||
|
|
||||||
|
// prototype for earlier use
|
||||||
|
void printHelper(void);
|
||||||
|
bool processArgv(int argc, const char *argv[], unsigned int *encoding, const char **input, const char **output, unsigned int *bit_depth);
|
||||||
|
|
||||||
|
void printHelp(void) {
|
||||||
|
printf(
|
||||||
|
"Usage: bpicencode <file> [-o <output> -e <encoding> -b <bitdepth>]\n"
|
||||||
|
"<file> the file to encode\n"
|
||||||
|
"--output,-o sets a destination file name; default: <file>.png\n"
|
||||||
|
"--encoding,-o sets a encoding (0 for bitwise, 1 for bytewise); default: 0\n"
|
||||||
|
"--bitdepth,-b sets a bit depth (1 (doesnt work with bytewise) or 8); default: 8\n"
|
||||||
|
"file sizes: 8 bit > 1 bit > bytewise encoding; safety is the other way around\n"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, const char * argv[]) {
|
||||||
|
int encoding;
|
||||||
|
FILE *inputFile;
|
||||||
|
FILE *outputFile;
|
||||||
|
|
||||||
|
|
||||||
|
if(argc == 1 || strlen(argv[1]) != 1 || !(strcmp(&argv[1][0], "0") || strcmp(&argv[1][0], "1"))) {
|
||||||
|
fprintf(stderr, "Encoding has to be either '0' for bitwise or '1' for bytewise!\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
encoding = strcmp(argv[1], "0");
|
||||||
|
|
||||||
|
inputFile = fopen(argv[2], "rb");
|
||||||
|
if(!inputFile) {
|
||||||
|
fprintf(stderr, "Could not open file %s!\n", argv[2]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
clock_t start = clock();
|
||||||
|
|
||||||
|
bpic_info *info = malloc(sizeof(bpic_info));
|
||||||
|
info->encoding = encoding;
|
||||||
|
|
||||||
|
decoded_data *data = bpic_encode_file(inputFile, info);
|
||||||
|
|
||||||
|
clock_t end = clock();
|
||||||
|
printf("Done in %f seconds.\n", (double)(end - start) / CLOCKS_PER_SEC);
|
||||||
|
|
||||||
|
uint8_t len = strlen(argv[2]);
|
||||||
|
char *oname = malloc(len + 4 + 1); // 4 bytes for ".png" and 1 byte for \0
|
||||||
|
strcpy(oname, argv[2]);
|
||||||
|
strcpy(oname + len, ".png");
|
||||||
|
outputFile = fopen(oname, "wb");
|
||||||
|
int code = 0;
|
||||||
|
if(fwrite(data->buffer, sizeof(unsigned char), data->size, outputFile) != data->size * sizeof(unsigned char)) {
|
||||||
|
fprintf(stderr, "Failed writing output file!");
|
||||||
|
code = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(outputFile);
|
||||||
|
free(oname);
|
||||||
|
free(data->buffer);
|
||||||
|
free(data);
|
||||||
|
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool processArgv(int argc, const char *argv[], unsigned int *encoding, const char **input, const char **output, unsigned int *bit_depth) {
|
||||||
|
for(int i = 0; i < argc; i++) {
|
||||||
|
if(strcmp(argv[i], "--output") || strcmp(argv[i], "-o")) {
|
||||||
|
if(i+1 <= argc || strncmp(argv[i+1], "-", 1)) {
|
||||||
|
fprintf(stderr, "missing output value!\n");
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
i++;
|
||||||
|
*output = argv[i];
|
||||||
|
}
|
||||||
|
} else if(strcmp(argv[i], "--bit-depth") || strcmp(argv[i], "-b")) {
|
||||||
|
if(i+1 <= argc || strncmp(argv[i+1], "-", 1)) {
|
||||||
|
fprintf(stderr, "missing bit depth value!\n");
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
i++;
|
||||||
|
*bit_depth = (int)strtol(argv[i], NULL, 10);
|
||||||
|
}
|
||||||
|
} else if(strcmp(argv[i], "--encoding") || strcmp(argv[i], "-e")) {
|
||||||
|
if(i+1 <= argc || strncmp(argv[i+1], "-", 1)) {
|
||||||
|
fprintf(stderr, "missing encoding value!\n");
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
i++;
|
||||||
|
*encoding = (int)strtol(argv[i], NULL, 10);
|
||||||
|
}
|
||||||
|
} else if(strncmp(argv[i], "--", 2)) {
|
||||||
|
fprintf(stderr, "unknown flag '%s'!\n", argv[i]);
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
FILE *fin = fopen(argv[i], "rb");
|
||||||
|
if(fin) {
|
||||||
|
*input = argv[i];
|
||||||
|
fclose(fin);
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "input file does not exist!\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
8
src/bpicencode_test/main.c
Normal file
8
src/bpicencode_test/main.c
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
#include <bpic.h>
|
||||||
|
|
||||||
|
int main(int argc, const char *argv[]) {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue