gbdk-2020 | GameBoy Development Kit |
| download: https://git.y1.nz/archives/gbdk.tar.gz | |
| README | Files | Log | Refs | LICENSE |
gbdk-support/png2hicolorgb/src/main.c
1 // See LICENSE file for license details
2
3 #include <stdio.h>
4 #include <string.h>
5 #include <stdlib.h>
6 #include <unistd.h>
7 #include <stdbool.h>
8 #include <stdint.h>
9
10
11 #include "common.h"
12 #include "path_ops.h"
13 #include "options.h"
14 #include "logging.h"
15 #include "image_load.h"
16
17 #include <hicolour.h>
18
19
20 #define VERSION "version 1.4.2"
21
22 #define HELP_HISTORICAL_CREDITS_STR \
23 "Historical credits and info:\n" \
24 " Original Concept : Icarus Productions\n" \
25 " Original Code : Jeff Frohwein\n" \
26 " Full Screen Modification : Anon\n" \
27 " Adaptive Code : Glen Cook\n" \
28 " Windows Interface : Glen Cook\n" \
29 " Additional Windows Programming : Rob Jones\n" \
30 " Original Quantiser Code : Benny\n" \
31 " Quantiser Conversion : Glen Cook\n" \
32 "\n"
33
34 static void init(void);
35 static void cleanup(void);
36 static void display_help(void);
37 static int handle_args(int argc, char * argv[]);
38 static bool handle_args_L_R_patterns(const char * str_opt_side, const char * str_value);
39 #ifdef DRAG_AND_DROP_MODE
40 static void set_drag_and_drop_mode_defaults(void);
41 #endif
42
43 image_data src_image;
44 char filename_in[MAX_STR_LEN] = "";
45 char opt_filename_out[MAX_STR_LEN] = "";
46 char opt_varname[MAX_STR_LEN] = "";
47 // bool opt_strip_output_filename_ext = true;
48
49 bool show_help_and_exit = false;
50 bool show_full_credits = false;
51
52
53 static void init(void) {
54 // Handle global init
55 src_image.p_img_data = NULL;
56 hicolor_init();
57 }
58
59
60 // Registered as an atexit handler
61 static void cleanup(void) {
62 // Handle any cleanup on exit
63 // Free the image data
64 if (src_image.p_img_data != NULL)
65 free(src_image.p_img_data);
66
67 }
68
69
70 int main( int argc, char *argv[] ) {
71
72 int ret = EXIT_FAILURE; // Default to failure on exit
73
74 // Register cleanup with exit handler
75 atexit(cleanup);
76
77 init();
78
79 #ifdef DRAG_AND_DROP_MODE
80 // Non-interactive mode, set some reasonable default
81 set_drag_and_drop_mode_defaults();
82 #endif
83
84 if (handle_args(argc, argv)) {
85
86 if (show_help_and_exit) {
87 ret = EXIT_SUCCESS;
88 }
89 else {
90 // detect file extension
91 if (matches_extension(filename_in, (char *)".png")) {
92
93 // Load source image (from first argument)
94 if (image_load(&src_image, filename_in, IMG_TYPE_PNG)) {
95
96 // If output filename is not specified, use source filename
97 if (opt_filename_out[0] == '\0')
98 strcpy(opt_filename_out, filename_in);
99
100 filename_remove_extension(opt_filename_out);
101
102 // If output symbol name is not specified, use output filename
103 if (opt_varname[0] == '\0')
104 strcpy(opt_varname, opt_filename_out);
105
106 hicolor_process_image(&src_image, opt_filename_out, opt_varname);
107 ret = EXIT_SUCCESS; // Exit with success
108 }
109 }
110 }
111 }
112
113 // Override exit code if was set during processing
114 if (get_exit_error())
115 ret = EXIT_FAILURE;
116
117 // if (ret == EXIT_FAILURE)
118 // log_error("Error loading, converting or writing out the image: %s\n", filename_in);
119
120 #ifdef DRAG_AND_DROP_MODE
121 // Wait for input to keep the console window open after processing
122 LOG("\n\nPress Any Key to Continue\n");
123 getchar();
124 #endif
125
126 return ret;
127 }
128
129
130 static void display_help(void) {
131 LOG(
132 "\n"
133 "png2hicolorgb input_image.png [options]\n"
134 VERSION": bbbbbr. Based on Glen Cook's Windows GUI \"hicolour.exe\" 1.2\n"
135 "Convert an image to Game Boy Hi-Color format\n"
136 "\n"
137 "Options\n"
138 "-h : Show this help\n"
139 "-v* : Set log level: \"-v\" verbose, \"-vQ\" quiet, \"-vE\" only errors, \"-vD\" debug\n"
140 "-o <file> : Set base output filename (otherwise from input image)\n"
141 "-s <name> : Set output variable/symbol name (otherwise derived from output filename)\n"
142 // "--keepext : Do not strip extension from output filename\n"
143 "--csource : Export C source format with incbins for data files\n"
144 "--bank=N : Set bank number for C source output where N is decimal bank number 1-511\n"
145 "--type=N : Set conversion type where N is one of below \n"
146 " 1: Median Cut - No Dither (*Default*)\n"
147 " 2: Median Cut - With Dither\n"
148 " 3: Wu Quantiser (best quality)\n"
149 "-p : Show screen attribute pattern options (no processing)\n"
150 "-L=N : Set Left side of screen palette arrangement where N is name listed below or decimal entry\n"
151 "-R=N : Set Right side of screen palette arrangement where N is name listed below or decimal entry\n"
152 " Named options for N: \"adaptive-fast\", \"adaptive-medium\", \"adaptive-best\" (-p for full options) \n"
153 "--best : Use highest quality conversion settings (--type=3 -L=adaptive-best -R=adaptive-best)\n"
154 "--vaddrid : Map uses vram id (128->255->0->127) instead of (*Default*) sequential tile order (0->255)\n"
155 "--nodedupe : Turn off tile pattern deduplication\n"
156 "--precompiled : Export Palette data as pre-compiled executable loading code\n"
157 "--palendbit : Set unused bit .15 = 1 for last u16 entry in palette data indicating end (not in precompiled)\n"
158 "--addendcolor=N : Append 32 x color N (hex BGR555) in pal data to clear BG for shorter images (64 bytes) (not in precompiled)\n"
159 "\n"
160 "Example 1: \"png2hicolorgb myimage.png\"\n"
161 "Example 2: \"png2hicolorgb myimage.png --csource -o my_output_filename\"\n"
162 "Example 2: \"png2hicolorgb myimage.png --palendbit --addendcolor 0x7FFF -o my_output_filename -s my_variable_name\"\n"
163 "* Default settings provide good results. Better quality but slower: \"--type=3 -L=adaptive-best -R=adaptive-best\"\n"
164 "\n"
165 );
166
167 if (show_full_credits)
168 LOG(HELP_HISTORICAL_CREDITS_STR);
169 }
170
171
172 #ifdef DRAG_AND_DROP_MODE
173 // Default options for Windows Drag and Drop recipient mode
174 static void set_drag_and_drop_mode_defaults(void) {
175
176 // Set some options here
177 }
178 #endif
179
180
181
182 static int handle_args(int argc, char * argv[]) {
183
184 int i;
185
186 if( argc < 2 ) {
187 display_help();
188 return false;
189 }
190
191 // Copy input filename (if not preceded with option dash)
192 if (argv[1][0] != '-')
193 snprintf(filename_in, sizeof(filename_in), "%s", argv[1]);
194
195 // Start at first optional argument, argc is zero based
196 for (i = 1; i <= (argc -1); i++ ) {
197
198 if ((strstr(argv[i], "-h") == argv[i]) || (strstr(argv[i], "-?") == argv[i])) {
199 show_full_credits = true;
200 display_help();
201 show_help_and_exit = true;
202 return true; // Don't parse further input when -h is used
203 } else if (strstr(argv[i], "-p") == argv[i]) {
204 LOG(HELP_CONV_PATTERN_STR);
205 show_help_and_exit = true;
206 return true; // Don't parse further input when -h is used
207
208 } else if (strstr(argv[i], "-vD") == argv[i]) {
209 set_log_level(OUTPUT_LEVEL_DEBUG);
210 } else if (strstr(argv[i], "-vE") == argv[i]) {
211 set_log_level(OUTPUT_LEVEL_ONLY_ERRORS);
212 } else if (strstr(argv[i], "-vQ") == argv[i]) {
213 set_log_level(OUTPUT_LEVEL_ONLY_ERRORS);
214 } else if (strstr(argv[i], "-v") == argv[i]) {
215 set_log_level(OUTPUT_LEVEL_VERBOSE);
216
217 } else if (strstr(argv[i], "--type=") == argv[i]) {
218 uint8_t new_type = strtol(argv[i] + strlen("--type="), NULL, 10);
219 if ((new_type < CONV_TYPE_MIN) || (new_type > CONV_TYPE_MAX)) {
220 LOG("Error: --type specified with invalid conversion setting: %d\n", new_type);
221 display_help();
222 show_help_and_exit = true;
223 return false; // Abort
224 }
225 else
226 hicolor_set_type(new_type);
227 } else if (strstr(argv[i], "-L=") == argv[i]) {
228 if (!handle_args_L_R_patterns((const char *)"-L=", argv[i] + strlen("-L="))) {
229 show_help_and_exit = true;
230 return false; // Abort
231 }
232
233 } else if (strstr(argv[i], "-R=") == argv[i]) {
234 if (!handle_args_L_R_patterns((const char *)"-R=", argv[i] + strlen("-R="))) {
235 show_help_and_exit = true;
236 return false; // Abort
237 }
238
239 } else if (strstr(argv[i], "--best") == argv[i]) {
240 hicolor_set_type(CONV_TYPE_WU);
241 hicolor_set_convert_left_pattern(HICOLOR_PATTERN_ADAPTIVE_BEST);
242 hicolor_set_convert_right_pattern(HICOLOR_PATTERN_ADAPTIVE_BEST);
243
244
245 } else if (strstr(argv[i], "-o") == argv[i]) {
246 if (i < (argc -1))
247 i++; // Move to next argument if one is available
248 else {
249 LOG("Error: -o specified but filename is missing\n");
250 show_help_and_exit = true;
251 return false; // Abort
252 }
253
254 // Require filename to be present
255 if (*argv[i] == '-') LOG("Warning: -o specified but filename (%s) has dash and looks like an option argument. Usage: -o my_base_output_filename\n", argv[i]);
256 snprintf(opt_filename_out, sizeof(opt_filename_out), "%s", argv[i]);
257
258 } else if (strstr(argv[i], "-s") == argv[i]) {
259 if (i < (argc -1))
260 i++; // Move to next argument if one is available
261 else {
262 LOG("Error: -s specified but variable name is missing\n");
263 show_help_and_exit = true;
264 return false; // Abort
265 }
266
267 // Require varname to be present
268 if (*argv[i] == '-') LOG("Warning: -s specified but varname (%s) has dash and looks like an option argument. Usage: -s my_varname\n", argv[i]);
269 snprintf(opt_varname, sizeof(opt_varname), "%s", argv[i]);
270
271
272 } else if (strstr(argv[i], "--csource") == argv[i]) {
273 opt_set_c_file_output(true);
274
275 } else if (strstr(argv[i], "--bank=") == argv[i]) {
276 opt_set_bank_num( strtol(argv[i] + strlen("--bank="), NULL, 10) );
277 if ((opt_get_bank_num() < BANK_NUM_MIN) || (opt_get_bank_num() > BANK_NUM_MAX)) {
278 LOG("Error: Invalid bank number specified with --bank=%d\n", opt_get_bank_num());
279 display_help();
280 show_help_and_exit = true;
281 return false; // Abort
282 }
283
284 } else if (strstr(argv[i], "--vaddrid") == argv[i]) {
285 opt_set_map_tile_order(OPT_MAP_TILE_ORDER_BY_VRAM_ID);
286
287 } else if (strstr(argv[i], "--nodedupe") == argv[i]) {
288 opt_set_tile_dedupe(false);
289
290 } else if (strstr(argv[i], "--precompiled") == argv[i]) {
291 opt_set_precompiled_palette(true);
292
293 } else if (strstr(argv[i], "--palendbit") == argv[i]) {
294 opt_set_pal_end_bit(true);
295
296 } else if (strstr(argv[i], "--addendcolor=") == argv[i]) {
297 // Color should be in BGR555 hex format, so white: 0x7FFFF, max red 0x7C00, max green 0x3E00, etc
298 opt_set_enable_pal_end_color( strtol(argv[i] + strlen("--addendcolor="), NULL, 16) );
299
300 } else if (argv[i][0] == '-') {
301 ERR("Unknown argument: %s\n\n", argv[i]);
302 display_help();
303 return false;
304 }
305
306 }
307
308
309 // Check and warn about option compatibility
310 if (opt_get_pal_end_bit() && opt_get_precompiled_palette()) {
311 LOG("Warning: --palendbit ignored when --precompiled is enabled\n");
312 }
313
314 if (opt_get_enable_pal_end_color() && opt_get_precompiled_palette()) {
315 LOG("Warning: --addendcolor ignored when --precompiled is enabled\n");
316 }
317
318 return true;
319 }
320
321
322 static bool handle_args_L_R_patterns(const char * str_opt_side, const char * str_value) {
323
324 if (*str_value == '\0') {
325 ERR("Missing value for %s argument\n", str_opt_side);
326 return false;
327 }
328
329 unsigned int pattern_num = hicolor_get_pattern_by_name(str_value);
330
331 if (pattern_num == HICOLOR_PATTERN_NOT_FOUND_HAS_CHARS) {
332 ERR("Invalid value for %s argument: %s\n", str_opt_side, str_value);
333 return false;
334 }
335 else if (pattern_num == HICOLOR_PATTERN_NOT_FOUND) {
336 // Try numeric conversion on option instead named conversion
337 pattern_num = (unsigned int)strtoul(str_value, NULL, 10);
338 }
339
340 if (pattern_num > HICOLOR_PATTERN_OPT_MAX) {
341 ERR("Invalid value for %s argument: %s\n", str_opt_side, str_value);
342 return false;
343 }
344
345 // Got a valid option value, now apply it
346 if (strstr(str_opt_side, "-L=") == str_opt_side)
347 hicolor_set_convert_left_pattern(pattern_num);
348 else
349 hicolor_set_convert_right_pattern(pattern_num);
350
351 return true;
352 }
This webpage is intended to be an accessible preview of this repository. To get a fuller picture, clone it and use the git CLI.