libansilove

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

tundra.c (4358B)


      1 /*
      2  * tundra.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 <stddef.h>
     15 #include <stdint.h>
     16 #include <string.h>
     17 #include "ansilove.h"
     18 #include "drawchar.h"
     19 #include "fonts.h"
     20 #include "output.h"
     21 
     22 #define TUNDRA_VERSION 24
     23 #define TUNDRA_STRING "TUNDRA24"
     24 
     25 #define TUNDRA_HEADER_LENGTH 9 /* 8 + 1 */
     26 
     27 #define TUNDRA_POSITION 1
     28 #define TUNDRA_COLOR_BACKGROUND 2
     29 #define TUNDRA_COLOR_FOREGROUND 4
     30 #define TUNDRA_COLOR_BOTH 6
     31 
     32 int
     33 ansilove_tundra(struct ansilove_ctx *ctx, struct ansilove_options *options)
     34 {
     35 	if (ctx == NULL || options == NULL) {
     36 		if (ctx)
     37 			ctx->error = ANSILOVE_INVALID_PARAM;
     38 
     39 		return -1;
     40 	}
     41 
     42 	if (ctx->length < TUNDRA_HEADER_LENGTH) {
     43 		ctx->error = ANSILOVE_FORMAT_ERROR;
     44 		return -1;
     45 	}
     46 
     47 	struct fontStruct fontData;
     48 	char tundra_version;
     49 
     50 	options->columns = options->columns ? options->columns : 80;
     51 	int16_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 	/* extract tundra header */
     61 	tundra_version = ctx->buffer[0];
     62 
     63 	if (tundra_version != TUNDRA_VERSION ||
     64 	    strncmp((const char *)ctx->buffer + 1, TUNDRA_STRING, 8)) {
     65 		ctx->error = ANSILOVE_FORMAT_ERROR;
     66 		return -1;
     67 	}
     68 
     69 	/* read tundra file a first time to find the image size */
     70 	uint32_t cursor, character, background = 0, foreground = 0;
     71 	size_t loop = TUNDRA_HEADER_LENGTH;
     72 	int32_t column = 0, row = 1;
     73 
     74 	while (loop < ctx->length) {
     75 		if (column == columns) {
     76 			column = 0;
     77 			row++;
     78 		}
     79 
     80 		cursor = ctx->buffer[loop];
     81 
     82 		switch (cursor) {
     83 		case TUNDRA_POSITION:
     84 			row = (ctx->buffer[loop + 1] << 24) +
     85 			    (ctx->buffer[loop + 2] << 16) +
     86 			    (ctx->buffer[loop + 3] << 8) +
     87 			    ctx->buffer[loop + 4];
     88 
     89 			column = (ctx->buffer[loop + 5] << 24) +
     90 			    (ctx->buffer[loop + 6] << 16) +
     91 			    (ctx->buffer[loop + 7] << 8) +
     92 			    ctx->buffer[loop + 8];
     93 
     94 			loop += 8;
     95 			break;
     96 
     97 		case TUNDRA_COLOR_BACKGROUND:
     98 			loop += 5;
     99 			column++;
    100 			break;
    101 
    102 		case TUNDRA_COLOR_FOREGROUND:
    103 			loop += 5;
    104 			column++;
    105 			break;
    106 
    107 		case TUNDRA_COLOR_BOTH:
    108 			loop += 9;
    109 			column++;
    110 			break;
    111 
    112 		default:
    113 			column++;
    114 		}
    115 
    116 		loop++;
    117 	}
    118 
    119 
    120 	/* allocate buffer image memory */
    121 	canvas = gdImageCreateTrueColor(columns * options->bits,
    122 	    row * fontData.height);
    123 
    124 	if (!canvas) {
    125 		ctx->error = ANSILOVE_GD_ERROR;
    126 		return -1;
    127 	}
    128 
    129 	/* process tundra */
    130 	column = 0;
    131 	row = 0;
    132 
    133 	loop = TUNDRA_HEADER_LENGTH;
    134 
    135 	while (loop < ctx->length) {
    136 		if (column == columns) {
    137 			column = 0;
    138 			row++;
    139 		}
    140 
    141 		cursor = character = ctx->buffer[loop];
    142 
    143 		switch (cursor) {
    144 		case TUNDRA_POSITION:
    145 			row = (ctx->buffer[loop + 1] << 24) +
    146 			    (ctx->buffer[loop + 2] << 16) +
    147 			    (ctx->buffer[loop + 3] << 8) +
    148 			    ctx->buffer[loop + 4];
    149 
    150 			column =
    151 			    (ctx->buffer[loop + 5] << 24) +
    152 			    (ctx->buffer[loop + 6] << 16) +
    153 			    (ctx->buffer[loop + 7] << 8) +
    154 			    ctx->buffer[loop + 8];
    155 
    156 			loop += 8;
    157 			break;
    158 
    159 		case TUNDRA_COLOR_BACKGROUND:
    160 			foreground =
    161 			    (ctx->buffer[loop + 3] << 16) +
    162 			    (ctx->buffer[loop + 4] << 8) +
    163 			    ctx->buffer[loop + 5];
    164 
    165 			character = ctx->buffer[loop+1];
    166 
    167 			loop += 5;
    168 			break;
    169 
    170 		case TUNDRA_COLOR_FOREGROUND:
    171 			background = (ctx->buffer[loop + 3] << 16) +
    172 			    (ctx->buffer[loop + 4] << 8) +
    173 			    ctx->buffer[loop + 5];
    174 
    175 			character = ctx->buffer[loop + 1];
    176 
    177 			loop += 5;
    178 			break;
    179 
    180 		case TUNDRA_COLOR_BOTH:
    181 			foreground =
    182 			    (ctx->buffer[loop + 3] << 16) +
    183 			    (ctx->buffer[loop + 4] << 8) +
    184 			    ctx->buffer[loop + 5];
    185 
    186 			background =
    187 			    (ctx->buffer[loop + 7] << 16) +
    188 			    (ctx->buffer[loop + 8] << 8) +
    189 			    ctx->buffer[loop + 9];
    190 
    191 			character = ctx->buffer[loop + 1];
    192 
    193 			loop += 9;
    194 			break;
    195 		}
    196 
    197 		if (character != TUNDRA_POSITION &&
    198 		    character != TUNDRA_COLOR_BACKGROUND &&
    199 		    character != TUNDRA_COLOR_FOREGROUND &&
    200 		    character != TUNDRA_COLOR_BOTH) {
    201 			drawchar(canvas, fontData.font_data, options->bits,
    202 			    fontData.height, column, row, background,
    203 			    foreground, character);
    204 
    205 			column++;
    206 		}
    207 
    208 		loop++;
    209 	}
    210 
    211 	/* create output image */
    212 	return output(ctx, options, canvas);
    213 }