libansilove

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

icedraw.c (3332B)


      1 /*
      2  * icedraw.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 "ansilove.h"
     17 #include "drawchar.h"
     18 #include "output.h"
     19 
     20 #define IDF_HEADER_LENGTH 12
     21 #define IDF_FONT_LENGTH 4096
     22 #define IDF_PALETTE_LENGTH 48
     23 
     24 int
     25 ansilove_icedraw(struct ansilove_ctx *ctx, struct ansilove_options *options)
     26 {
     27 	if (ctx == NULL || options == NULL) {
     28 		if (ctx)
     29 			ctx->error = ANSILOVE_INVALID_PARAM;
     30 
     31 		return -1;
     32 	}
     33 
     34 	if (ctx->length < IDF_HEADER_LENGTH + IDF_FONT_LENGTH + IDF_PALETTE_LENGTH) {
     35 		ctx->error = ANSILOVE_FORMAT_ERROR;
     36 		return -1;
     37 	}
     38 
     39 	/* Get number of columns, 16-bit endian unsigned short */
     40 	uint32_t x2 = (ctx->buffer[9] << 8) + ctx->buffer[8] + 1;
     41 
     42 	/* libgd image pointers */
     43 	gdImagePtr canvas;
     44 
     45 	size_t index, loop = IDF_HEADER_LENGTH;
     46 	uint32_t colors[16];
     47 
     48 	/* process IDF */
     49 	uint32_t idf_sequence_length, i = 0;
     50 
     51 	/* dynamically allocated memory buffer for IDF data */
     52 	uint8_t *ptr, *idf_buffer;
     53 	idf_buffer = malloc(2);
     54 
     55 	while (loop < ctx->length - IDF_FONT_LENGTH - IDF_PALETTE_LENGTH) {
     56 		/* RLE compressed data */
     57 		if (ctx->buffer[loop] == 1) {
     58 			idf_sequence_length = ctx->buffer[loop+2];
     59 
     60 			while (idf_sequence_length--)
     61 			{
     62 				/* reallocate IDF buffer memory */
     63 				ptr = realloc(idf_buffer, i + 2);
     64 				if (ptr == NULL) {
     65 					ctx->error = ANSILOVE_MEMORY_ERROR;
     66 					free(idf_buffer);
     67 					return -1;
     68 				} else {
     69 					idf_buffer = ptr;
     70 				}
     71 
     72 				idf_buffer[i] = ctx->buffer[loop + 4];
     73 				idf_buffer[i+1] = ctx->buffer[loop + 5];
     74 				i += 2;
     75 			}
     76 			loop += 4;
     77 		} else {
     78 			/* reallocate IDF buffer memory */
     79 			ptr = realloc(idf_buffer, i + 2);
     80 			if (ptr == NULL) {
     81 				ctx->error = ANSILOVE_MEMORY_ERROR;
     82 				free(idf_buffer);
     83 				return -1;
     84 			} else {
     85 				idf_buffer = ptr;
     86 			}
     87 
     88 			/* normal character */
     89 			idf_buffer[i] = ctx->buffer[loop];
     90 			idf_buffer[i+1] = ctx->buffer[loop + 1];
     91 			i += 2;
     92 		}
     93 		loop += 2;
     94 	}
     95 
     96 	/* create IDF instance */
     97 	canvas = gdImageCreate(x2 * 8, i / 2 / 80 * 16);
     98 
     99 	/* error output */
    100 	if (!canvas) {
    101 		ctx->error = ANSILOVE_GD_ERROR;
    102 		free(idf_buffer);
    103 		return -1;
    104 	}
    105 
    106 	/* process IDF palette */
    107 	for (loop = 0; loop < 16; loop++) {
    108 		index = (loop * 3) + ctx->length - IDF_PALETTE_LENGTH;
    109 		colors[loop] = gdImageColorAllocate(canvas,
    110 		    (ctx->buffer[index] << 2 | ctx->buffer[index] >> 4),
    111 		    (ctx->buffer[index + 1] << 2 | ctx->buffer[index + 1] >> 4),
    112 		    (ctx->buffer[index + 2] << 2 | ctx->buffer[index + 2] >> 4));
    113 	}
    114 
    115 	/* render IDF */
    116 	uint32_t column = 0, row = 0;
    117 	uint32_t character, attribute, foreground, background;
    118 
    119 	for (loop = 0; loop < i; loop += 2) {
    120 		if (column == x2) {
    121 			column = 0;
    122 			row++;
    123 		}
    124 
    125 		character = idf_buffer[loop];
    126 		attribute = idf_buffer[loop+1];
    127 
    128 		background = (attribute & 240) >> 4;
    129 		foreground = attribute & 15;
    130 
    131 		drawchar(canvas, ctx->buffer+(ctx->length - IDF_FONT_LENGTH - IDF_PALETTE_LENGTH),
    132 		    8, 16, column, row,
    133 		    colors[background], colors[foreground], character);
    134 
    135 		column++;
    136 	}
    137 
    138 	/* create output file */
    139 	if (output(ctx, options, canvas) != 0) {
    140 		free(idf_buffer);
    141 		return -1;
    142 	}
    143 
    144 	free(idf_buffer);
    145 
    146 	return 0;
    147 }