Skip to content

Instantly share code, notes, and snippets.

@jw910731
Created March 29, 2023 16:46
Show Gist options
  • Save jw910731/734765c9a5f1ce15c3fab68c7983ff46 to your computer and use it in GitHub Desktop.
Save jw910731/734765c9a5f1ce15c3fab68c7983ff46 to your computer and use it in GitHub Desktop.
A simple terminal bmp displayer
#include <stdint.h>
#include <sys/ioctl.h>
#include <stdio.h>
#include <unistd.h>
#include <stdbool.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <signal.h>
#define ASCII_ESC "\033"
#define CLR_RST ASCII_ESC"[0m"
typedef unsigned char byte;
struct bmpHeader {
char bm[2];
uint32_t size;
uint32_t reserve;
uint32_t offset;
uint32_t header_size;
int32_t width;
int32_t height;
uint16_t planes;
uint16_t bpp;
uint32_t compression;
uint32_t bitmap_size;
int32_t hres;
int32_t vres;
uint32_t used;
uint32_t important;
} __attribute__((__packed__));
struct pix_t {
byte b, g, r;
} __attribute__((__packed__));
struct picture_t {
struct pix_t *blob;
int32_t w, h;
};
/*
* Read BMP file
*
* @param file is the BMP file object
* @param out is the destination object
*
* @return successful or not
*/
bool read_bmp(struct picture_t *out, FILE *file){
if(file == NULL){
fprintf(stderr, "fopen(): %s\n", strerror(errno));
return false;
}
if(out == NULL) return false;
// read write header
struct bmpHeader header, outHeader;
fread(&header, 54, 1, file);
memcpy(&outHeader, &header, sizeof(header));
// calc info
*out = (struct picture_t){.w = abs(header.width),
.h = abs(header.height),
.blob =
calloc(abs(header.width) * abs(header.height),
sizeof(struct pix_t))};
int32_t ipad_siz = (((24 * out->w + 31) / 32) * 4) - (3 * out->w);
// read data by row
for (int32_t i = 0; i < out->h; ++i) {
fread(out->blob + (out->w * i), out->w, sizeof(struct pix_t), file);
// skip padding bytes
fseek(file, ipad_siz, SEEK_CUR);
}
fclose(file);
return true;
}
// global maintained terminal size object
static struct winsize term_size;
static inline void update_terminal_size(int sig) {
ioctl(STDOUT_FILENO, TIOCGWINSZ, &term_size);
term_size.ws_row -= 2;
}
int main(int argc, const char **argv) {
if(argc < 2) {
fprintf(stderr, "No enough argument.\n");
return 1;
}
struct picture_t picture;
if(!read_bmp(&picture, fopen(argv[1], "rb"))){
return 1;
}
update_terminal_size(SIGWINCH);
static const char clear_seq[] = {0x1b, 0x5b, 0x48, 0x1b, 0x5b, 0x32, 0x4a, 0x00};
fputs(clear_seq, stdout);
// display
for(int32_t i = term_size.ws_row ; i >= 0 ; --i){
for(int32_t j = 0 ; j < term_size.ws_col ; ++j){
int32_t x = (int32_t)(j*((double)(picture.w-1)/term_size.ws_col)+0.5),
y = (int32_t)(i*((double)(picture.h-1)/term_size.ws_row)+0.5);
struct pix_t *pix = picture.blob + (y*picture.w + x);
//printf("(%d, %d) -> (%hhu, %hhu, %hhu)\n", x, y, pix->r, pix->g, pix->b);
printf(ASCII_ESC"[38;2;%hhu;%hhu;%hhum█"CLR_RST, pix->r, pix->g, pix->b);
}
}
free(picture.blob);
return 0;
}
@aokblast
Copy link

Nin is too Dian

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