icedraw.c (3990B)
1 /* 2 * icedraw.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 <stdint.h> 17 #include <stdlib.h> 18 #include "ansilove.h" 19 #include "drawchar.h" 20 #include "output.h" 21 22 #define IDF_HEADER_LENGTH 12 23 #define IDF_FONT_LENGTH 4096 24 #define IDF_PALETTE_LENGTH 48 25 26 #define STATE_CHARACTER 0 27 #define STATE_ATTRIBUTE 1 28 #define STATE_RLE 2 29 30 int 31 ansilove_icedraw(struct ansilove_ctx *ctx, struct ansilove_options *options) 32 { 33 size_t index, loop = IDF_HEADER_LENGTH; 34 uint8_t *ptr, *idf_buffer; 35 uint8_t *cursor, state = STATE_CHARACTER; 36 uint32_t width, height; 37 uint32_t column = 0, row = 0; 38 uint32_t character, attribute, foreground, background; 39 uint32_t colors[16]; 40 uint32_t idf_sequence_length, i = 0; 41 42 /* libgd image pointers */ 43 gdImagePtr canvas; 44 45 if (ctx == NULL || options == NULL) { 46 if (ctx) 47 ctx->error = ANSILOVE_INVALID_PARAM; 48 49 return -1; 50 } 51 52 if (ctx->length < IDF_HEADER_LENGTH + IDF_FONT_LENGTH + IDF_PALETTE_LENGTH) { 53 ctx->error = ANSILOVE_FORMAT_ERROR; 54 return -1; 55 } 56 57 /* Get number of columns, 16-bit endian unsigned short */ 58 uint32_t x2 = (ctx->buffer[9] << 8) + ctx->buffer[8] + 1; 59 60 if (x2 < 1 || x2 > 4096) { 61 ctx->error = ANSILOVE_RANGE_ERROR; 62 return -1; 63 } 64 65 /* process IDF */ 66 /* dynamically allocated memory buffer for IDF data */ 67 idf_buffer = malloc(2); 68 69 if (idf_buffer == NULL) { 70 ctx->error = ANSILOVE_MEMORY_ERROR; 71 return -1; 72 } 73 74 while (loop < ctx->length - IDF_FONT_LENGTH - IDF_PALETTE_LENGTH) { 75 cursor = &ctx->buffer[loop]; 76 77 switch (state) { 78 case STATE_CHARACTER: 79 if (*cursor == 1) { 80 state = STATE_RLE; 81 loop++; 82 } else { 83 ptr = realloc(idf_buffer, i + 2); 84 if (ptr == NULL) { 85 ctx->error = ANSILOVE_MEMORY_ERROR; 86 goto error; 87 } 88 89 idf_buffer = ptr; 90 idf_buffer[i] = *cursor; 91 i++; 92 state = STATE_ATTRIBUTE; 93 } 94 95 loop++; 96 break; 97 case STATE_ATTRIBUTE: 98 idf_buffer[i] = *cursor; 99 i++; 100 101 state = STATE_CHARACTER; 102 103 loop++; 104 break; 105 case STATE_RLE: 106 /* RLE compressed data */ 107 idf_sequence_length = *cursor; 108 109 if (loop + 3 >= ctx->length) { 110 ctx->error = ANSILOVE_FORMAT_ERROR; 111 goto error; 112 } 113 114 while (idf_sequence_length--) 115 { 116 /* reallocate IDF buffer memory */ 117 ptr = realloc(idf_buffer, i + 2); 118 if (ptr == NULL) { 119 ctx->error = ANSILOVE_MEMORY_ERROR; 120 goto error; 121 } 122 123 idf_buffer = ptr; 124 125 idf_buffer[i] = ctx->buffer[loop +2]; 126 idf_buffer[i+1] = ctx->buffer[loop + 3]; 127 i += 2; 128 } 129 130 loop += 4; 131 state = STATE_CHARACTER; 132 } 133 } 134 135 width = x2 * 8; 136 height = i / 2 / 80 * 16; 137 138 if (!width || !height) { 139 ctx->error = ANSILOVE_FORMAT_ERROR; 140 goto error; 141 } 142 143 /* create IDF instance */ 144 canvas = gdImageCreate(width, height); 145 146 /* error output */ 147 if (!canvas) { 148 ctx->error = ANSILOVE_GD_ERROR; 149 goto error; 150 } 151 152 /* process IDF palette */ 153 for (loop = 0; loop < 16; loop++) { 154 index = (loop * 3) + ctx->length - IDF_PALETTE_LENGTH; 155 colors[loop] = gdImageColorAllocate(canvas, 156 ctx->buffer[index] << 2 | ctx->buffer[index] >> 4, 157 ctx->buffer[index + 1] << 2 | ctx->buffer[index + 1] >> 4, 158 ctx->buffer[index + 2] << 2 | ctx->buffer[index + 2] >> 4); 159 } 160 161 /* render IDF */ 162 for (loop = 0; loop < i; loop += 2) { 163 if (column == x2) { 164 column = 0; 165 row++; 166 } 167 168 character = idf_buffer[loop]; 169 attribute = idf_buffer[loop+1]; 170 171 background = (attribute & 240) >> 4; 172 foreground = attribute & 15; 173 174 drawchar(canvas, ctx->buffer+(ctx->length - IDF_FONT_LENGTH - IDF_PALETTE_LENGTH), 175 8, 16, column, row, 176 colors[background], colors[foreground], character); 177 178 column++; 179 } 180 181 /* create output file */ 182 if (output(ctx, options, canvas) != 0) 183 goto error; 184 185 free(idf_buffer); 186 return 0; 187 188 error: 189 free(idf_buffer); 190 return -1; 191 }