libansilove

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

binary.c (2775B)


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