libansilove

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

artworx.c (2312B)


      1 /*
      2  * artworx.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 "ansilove.h"
     19 #include "config.h"
     20 #include "drawchar.h"
     21 #include "output.h"
     22 
     23 #define ADF_HEADER_LENGTH 4289 /* 192 + 4096 + 1 */
     24 
     25 #define STATE_CHARACTER 0
     26 #define STATE_ATTRIBUTE 1
     27 
     28 int
     29 ansilove_artworx(struct ansilove_ctx *ctx, struct ansilove_options *options)
     30 {
     31 	uint8_t character, attribute, *cursor, state = STATE_CHARACTER;
     32 	uint32_t column = 0, row = 0;
     33 	uint32_t foreground, background;
     34 	uint32_t width, height;
     35 	size_t index, loop;
     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 < ADF_HEADER_LENGTH) {
     48 		ctx->error = ANSILOVE_FORMAT_ERROR;
     49 		return -1;
     50 	}
     51 
     52 	/* create ADF instance */
     53 	width = 640;
     54 	height = (ctx->length - ADF_HEADER_LENGTH) / 2 / 80 * 16;
     55 
     56 	if (!width || !height) {
     57 		ctx->error = ANSILOVE_FORMAT_ERROR;
     58 		return -1;
     59 	}
     60 
     61 	canvas = gdImageCreate(width, height);
     62 
     63 	if (!canvas) {
     64 		ctx->error = ANSILOVE_GD_ERROR;
     65 		return -1;
     66 	}
     67 
     68 
     69 	/* process ADF palette */
     70 	for (loop = 0; loop < 16; loop++) {
     71 		index = (adf_colors[loop] * 3) + 1;
     72 		gdImageColorAllocate(canvas,
     73 		    ctx->buffer[index] << 2 | ctx->buffer[index] >> 4,
     74 		    ctx->buffer[index + 1] << 2 | ctx->buffer[index + 1] >> 4,
     75 		    ctx->buffer[index + 2] << 2 | ctx->buffer[index + 2] >> 4);
     76 	}
     77 
     78 	/* process ADF */
     79 	loop = ADF_HEADER_LENGTH;
     80 
     81 	while (loop < ctx->length) {
     82 		cursor = &ctx->buffer[loop];
     83 
     84 		if (column == 80) {
     85 			column = 0;
     86 			row++;
     87 		}
     88 
     89 		switch (state) {
     90 		case STATE_CHARACTER:
     91 			character = *cursor;
     92 			state = STATE_ATTRIBUTE;
     93 			break;
     94 		case STATE_ATTRIBUTE:
     95 			attribute = *cursor;
     96 
     97 			background = (attribute & 240) >> 4;
     98 			foreground = attribute & 15;
     99 
    100 			drawchar(canvas, ctx->buffer+193, 8, 16, column, row,
    101 			    background, foreground, character);
    102 
    103 			column++;
    104 
    105 			state = STATE_CHARACTER;
    106 			break;
    107 		}
    108 
    109 		loop++;
    110 	}
    111 
    112 	/* create output file */
    113 	return output(ctx, options, canvas);
    114 }