libansilove

Library for converting ANSI, ASCII, and other formats to PNG
Log | Files | Refs | README | LICENSE

binary.c (2731B)


      1 /*
      2  * binary.c
      3  * libansilove 1.2.7
      4  * https://www.ansilove.org
      5  *
      6  * Copyright (c) 2011-2020 Stefan Vogt, Brian Cassidy, and Frederic Cambus
      7  * All rights reserved.
      8  *
      9  * libansilove is licensed under the BSD 2-Clause License.
     10  * See LICENSE file for details.
     11  */
     12 
     13 #include <gd.h>
     14 #include <stddef.h>
     15 #include <stdint.h>
     16 #include <string.h>
     17 #include "ansilove.h"
     18 #include "config.h"
     19 #include "drawchar.h"
     20 #include "fonts.h"
     21 #include "output.h"
     22 
     23 #define STATE_CHARACTER 0
     24 #define STATE_ATTRIBUTE 1
     25 
     26 int
     27 ansilove_binary(struct ansilove_ctx *ctx, struct ansilove_options *options)
     28 {
     29 	uint8_t character, attribute, *cursor, state = STATE_CHARACTER;
     30 	int32_t column = 0, row = 0;
     31 	uint32_t background, foreground;
     32 	uint32_t width, height;
     33 	uint32_t colors[16];
     34 	size_t loop = 0;
     35 	struct fontStruct fontData;
     36 
     37 	/* libgd image pointers */
     38 	gdImagePtr canvas;
     39 
     40 	if (ctx == NULL || options == NULL) {
     41 		if (ctx)
     42 			ctx->error = ANSILOVE_INVALID_PARAM;
     43 
     44 		return -1;
     45 	}
     46 
     47 	if (!ctx->length) {
     48 		ctx->error = ANSILOVE_FORMAT_ERROR;
     49 		return -1;
     50 	}
     51 
     52 	if (options->bits != 8 && options->bits !=9) {
     53 		ctx->error = ANSILOVE_RANGE_ERROR;
     54 		return -1;
     55 	}
     56 
     57 	/* font selection */
     58 	memset(&fontData, 0, sizeof(struct fontStruct));
     59 	select_font(&fontData, options->font);
     60 
     61 	/* Default to 160 columns if columns option wasn't set */
     62 	options->columns = options->columns ? options->columns : 160;
     63 
     64 	if (options->columns < 1 || options->columns > 4096) {
     65 		ctx->error = ANSILOVE_RANGE_ERROR;
     66 		return -1;
     67 	}
     68 
     69 	width = options->columns * options->bits;
     70 	height = ctx->length / 2 / options->columns * fontData.height;
     71 
     72 	if (!width || !height) {
     73 		ctx->error = ANSILOVE_FORMAT_ERROR;
     74 		return -1;
     75 	}
     76 
     77 	/* allocate buffer image memory */
     78 	canvas = gdImageCreate(width, height);
     79 
     80 	if (!canvas) {
     81 		ctx->error = ANSILOVE_GD_ERROR;
     82 		return -1;
     83 	}
     84 
     85 	/* allocate color palette */
     86 	for (size_t i = 0; i < 16; i++)
     87 		colors[i] = gdImageColorAllocate(canvas, vga_palette_red[i],
     88 		    vga_palette_green[i], vga_palette_blue[i]);
     89 
     90 	/* process binary */
     91 	while (loop < ctx->length) {
     92 		cursor = &ctx->buffer[loop];
     93 
     94 		if (column == options->columns) {
     95 			column = 0;
     96 			row++;
     97 		}
     98 
     99 		switch (state) {
    100 		case STATE_CHARACTER:
    101 			character = *cursor;
    102 			state = STATE_ATTRIBUTE;
    103 			break;
    104 		case STATE_ATTRIBUTE:
    105 			attribute = *cursor;
    106 
    107 			background = (attribute & 240) >> 4;
    108 			foreground = attribute & 15;
    109 
    110 			if (background > 8 && !options->icecolors)
    111 				background -= 8;
    112 
    113 			drawchar(canvas, fontData.font_data, options->bits,
    114 			    fontData.height, column, row, colors[background],
    115 			    colors[foreground], character);
    116 
    117 			column++;
    118 
    119 			state = STATE_CHARACTER;
    120 			break;
    121 		}
    122 
    123 		loop++;
    124 	}
    125 
    126 	/* create output image */
    127 	return output(ctx, options, canvas);
    128 }