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