libansilove

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

pcboard.c (4207B)


      1 /*
      2  * pcboard.c
      3  * libansilove 1.2.4
      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 <stdint.h>
     15 #include <stdlib.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 LF	'\n'
     24 #define CR	'\r'
     25 #define TAB	'\t'
     26 #define SUB	26
     27 
     28 /* Character structure */
     29 struct pcbChar {
     30 	uint32_t column;
     31 	uint32_t row;
     32 	uint32_t background;
     33 	uint32_t foreground;
     34 	uint8_t character;
     35 };
     36 
     37 int
     38 ansilove_pcboard(struct ansilove_ctx *ctx, struct ansilove_options *options)
     39 {
     40 	if (ctx == NULL || options == NULL) {
     41 		if (ctx)
     42 			ctx->error = ANSILOVE_INVALID_PARAM;
     43 
     44 		return -1;
     45 	}
     46 
     47 	struct fontStruct fontData;
     48 	size_t loop = 0, structIndex = 0;
     49 
     50 	options->columns = options->columns ? options->columns : 80;
     51 	uint16_t columns = options->columns;
     52 
     53 	/* font selection */
     54 	memset(&fontData, 0, sizeof(struct fontStruct));
     55 	select_font(&fontData, options->font);
     56 
     57 	/* libgd image pointers */
     58 	gdImagePtr canvas;
     59 
     60 	uint8_t character, *cursor;
     61 	uint32_t background = 0, foreground = 7;
     62 	uint32_t column = 0, row = 0, rowMax = 0;
     63 
     64 	/* PCB buffer structure array definition */
     65 	struct pcbChar *ptr, *pcboard_buffer;
     66 
     67 	/* PCB buffer dynamic memory allocation */
     68 	pcboard_buffer = malloc(sizeof (struct pcbChar));
     69 
     70 	while (loop < ctx->length) {
     71 		cursor = &ctx->buffer[loop];
     72 
     73 		if (column == columns) {
     74 			row++;
     75 			column = 0;
     76 		}
     77 
     78 		switch (*cursor) {
     79 		case LF:
     80 			row++;
     81 			column = 0;
     82 			break;
     83 		case CR:
     84 			break;
     85 		case TAB:
     86 			column += 8;
     87 			break;
     88 		case SUB:
     89 			loop = ctx->length;
     90 			break;
     91 		case '@':
     92 			/* PCB sequence */
     93 			if (*++cursor == 'X') {
     94 				/* set graphics rendition */
     95 				background = ctx->buffer[loop+2];
     96 				foreground = ctx->buffer[loop+3];
     97 				loop += 3;
     98 			}
     99 
    100 			if (!memcmp(cursor, "CLS", 3)) {
    101 				/* erase display */
    102 				column = 0;
    103 				row = 0;
    104 
    105 				rowMax = 0;
    106 
    107 				/* reset pcboard buffer */
    108 				structIndex = 0;
    109 
    110 				loop += 4;
    111 			}
    112 
    113 			if (!memcmp(cursor, "POS:", 4)) {
    114 				/* cursor position */
    115 				if (ctx->buffer[loop+6] == '@')
    116 				{
    117 					column = ((ctx->buffer[loop+5])-48)-1;
    118 					loop += 5;
    119 				} else {
    120 					column = (10 * ((ctx->buffer[loop+5])-48) + (ctx->buffer[loop+6])-48)-1;
    121 					loop += 6;
    122 				}
    123 			}
    124 			break;
    125 		default:
    126 			/* record number of lines used */
    127 			if (row > rowMax)
    128 				rowMax = row;
    129 
    130 			/* reallocate structure array memory */
    131 			ptr = realloc(pcboard_buffer, (structIndex + 1) * sizeof (struct pcbChar));
    132 			if (ptr == NULL) {
    133 				ctx->error = ANSILOVE_MEMORY_ERROR;
    134 				free(pcboard_buffer);
    135 				return -1;
    136 			} else {
    137 				pcboard_buffer = ptr;
    138 			}
    139 
    140 			/* write current character in pcbChar structure */
    141 			pcboard_buffer[structIndex].column = column;
    142 			pcboard_buffer[structIndex].row = row;
    143 			pcboard_buffer[structIndex].background = pcb_colors[background];
    144 			pcboard_buffer[structIndex].foreground = pcb_colors[foreground];
    145 			pcboard_buffer[structIndex].character = *cursor;
    146 
    147 			column++;
    148 			structIndex++;
    149 		}
    150 
    151 		loop++;
    152 	}
    153 	rowMax++;
    154 
    155 	/* allocate buffer image memory */
    156 	canvas = gdImageCreate(columns * options->bits, (rowMax)*fontData.height);
    157 
    158 	if (!canvas) {
    159 		ctx->error = ANSILOVE_GD_ERROR;
    160 		free(pcboard_buffer);
    161 		return -1;
    162 	}
    163 
    164 	/* allocate color palette */
    165 	uint32_t colors[16];
    166 
    167 	for (size_t i = 0; i < 16; i++) {
    168 		colors[i] = gdImageColorAllocate(canvas, ansi_palette_red[i],
    169 		    ansi_palette_green[i], ansi_palette_blue[i]);
    170 	}
    171 
    172 	/* render PCB */
    173 	for (loop = 0; loop < structIndex; loop++) {
    174 		/* grab our chars out of the structure */
    175 		column = pcboard_buffer[loop].column;
    176 		row = pcboard_buffer[loop].row;
    177 		background = pcboard_buffer[loop].background;
    178 		foreground = pcboard_buffer[loop].foreground;
    179 		character = pcboard_buffer[loop].character;
    180 
    181 		drawchar(canvas, fontData.font_data, options->bits, fontData.height,
    182 		    column, row, colors[background], colors[foreground], character);
    183 	}
    184 
    185 	/* create output image */
    186 	if (output(ctx, options, canvas) != 0) {
    187 		free(pcboard_buffer);
    188 		return -1;
    189 	}
    190 
    191 	free(pcboard_buffer);
    192 
    193 	return 0;
    194 }