Skip to content

Instantly share code, notes, and snippets.

@Neboer
Last active July 21, 2022 08:22
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Neboer/f47a7fa2006650e9350a384225f94a4f to your computer and use it in GitHub Desktop.
Save Neboer/f47a7fa2006650e9350a384225f94a4f to your computer and use it in GitHub Desktop.
nbtp is a simple C/C++ program to convert any binary file to a validate png picture use lodepng
#include "lodepng.h"
#include <math.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#define max_buffer 0xFFFFFF
struct size
{
unsigned width;
unsigned height;
unsigned char *raw_image;
};
void encodeOneStep(unsigned char *raw_image_data, char *dest_filename,
unsigned width, unsigned height)
{
unsigned error = lodepng_encode_file(dest_filename, raw_image_data, width,
height, LCT_RGB, 8);
/*if there's an error, display it*/
if (error)
{
printf("error %u: %s\n", error, lodepng_error_text(error));
return;
}
}
struct size encode_file(const char *filename)
{
FILE *file_to_encode = fopen(filename, "rb");
unsigned char *generated_image = malloc(max_buffer);
size_t file_length =
fread(generated_image + 4, 1, max_buffer, file_to_encode);
printf("file length: %lu\n", file_length);
fclose(file_to_encode);
*((uint32_t *)generated_image) = file_length;
unsigned useful_data_size = file_length + 4;
unsigned useful_pixels = ceil((double)useful_data_size / (double)3.0);
unsigned side = ceil(sqrt((double)useful_pixels));
struct size result = {side, side, generated_image};
memset(generated_image + useful_data_size, 255, side * side * 3 - useful_data_size);
return result;
}
void decode_file(const char *source_png_fn, const char *output_fn)
{
struct size bin_file;
lodepng_decode_file(&bin_file.raw_image, &bin_file.width, &bin_file.height, source_png_fn, LCT_RGB, 8);
uint32_t file_length = *((uint32_t *)bin_file.raw_image);
FILE *output = fopen(output_fn, "wb");
fwrite(bin_file.raw_image + 4, 1, file_length, output);
fclose(output);
}
int main(int argc, char **argv)
{
if (argv[1][0] == 'd')
{
decode_file(argv[2], argv[3]);
}
else if (argv[1][0] == 'e')
{
struct size binary_content = encode_file(argv[2]);
printf("image size: %d * %d\n", binary_content.width, binary_content.height);
encodeOneStep(binary_content.raw_image, argv[3], binary_content.width,
binary_content.height);
}
}
#include <lodepng.h>
#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>
#include <string>
#include <cmath>
typedef std::vector<unsigned char> DataVect;
void encodeTwoSteps(const char* filename, std::vector<unsigned char>& image, unsigned width, unsigned height) {
std::vector<unsigned char> png;
unsigned error = lodepng::encode(png, image, width, height,LCT_RGB,8);
if(!error) lodepng::save_file(png, filename);
//if there's an error, display it
if(error) std::cout << "encoder error " << error << ": "<< lodepng_error_text(error) << std::endl;
}
DataVect decodeTwoSteps(const char* filename) {
std::vector<unsigned char> png;
std::vector<unsigned char> image; //the raw pixels
unsigned width, height;
//load and decode
unsigned error = lodepng::load_file(png, filename);
if(!error) error = lodepng::decode(image, width, height, png, LCT_RGB);
//if there's an error, display it
if(error) std::cout << "decoder error " << error << ": " << lodepng_error_text(error) << std::endl;
return image;
//the pixels are now in the vector "image", 4 bytes per pixel, ordered RGBARGBA..., use it as texture, draw it, ...
}
DataVect get_file_bin(const std::string& filename){
std::ifstream file(filename);
std::ostringstream ss;
ss << file.rdbuf();
file.close();
const std::string& s = ss.str();
DataVect vec(s.begin(), s.end());
return vec;
}
void write_to_disk(const std::string& filename,const DataVect &data){
FILE* dest_file = fopen(filename.c_str(),"w");
fwrite(&data[0],data.size(),1,dest_file);
fclose(dest_file);
}
int binary_to_raw_image(DataVect &input_data){
int original_size = input_data.size();
union {uint32_t size;unsigned char bytes[4];} prepend_size_data{};
prepend_size_data.size = original_size;
int length_of_side = ceil(sqrt((float)(original_size + 4) / 3.0));
int container_capacity = length_of_side * length_of_side * 3;
int rest_length = container_capacity - (original_size + 4);
std::cout << input_data.size() << std::endl;
input_data.insert(input_data.begin(),&prepend_size_data.bytes[0], &prepend_size_data.bytes[4]);
std::cout << input_data.size() << std::endl;
input_data.insert(input_data.end(),rest_length,'\0');
std::cout << input_data.size() << std::endl;
return length_of_side;
}
void raw_image_to_binary(DataVect &input_raw_image){
union {uint32_t size;unsigned char bytes[4];} prepend_size_data{};
memcpy(prepend_size_data.bytes,&input_raw_image[0],4);
//The range used is [first,last), which includes all the elements between first and last, including the element pointed by first but not the element pointed by last.
input_raw_image.erase(input_raw_image.begin(),input_raw_image.begin()+4);
input_raw_image.erase(input_raw_image.begin() + prepend_size_data.size, input_raw_image.end());
}
// usage: nbtp b2p/p2b file1 file2
int main(int argc, char** argv){
if (strcmp(argv[1],"b2p") == 0){
// input binary data output png file
DataVect bin = get_file_bin(argv[2]);
int side_length = binary_to_raw_image(bin);
encodeTwoSteps(argv[3],bin,side_length, side_length);
} else if (strcmp(argv[1],"p2b") == 0){
DataVect binary_image = decodeTwoSteps(argv[2]);
raw_image_to_binary(binary_image);
write_to_disk(argv[3],binary_image);
}
}
@Neboer
Copy link
Author

Neboer commented Sep 11, 2020

需要依赖lodepng,程序使用方法:(图片解码为文件)nbtp p2b ./tupian.png ./output

@Neboer
Copy link
Author

Neboer commented Sep 26, 2020

之前说的是nbtp.cpp的使用方法,这个程序存在bug,现在已经被第一个nbtp.c取代。请大家自行探索第一个程序的用法,其实和第二个大同小异!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment