f256/tools/imageconvert/imageconvert.c
2024-01-20 19:48:23 -06:00

237 lines
6.1 KiB
C

/*
* Copyright (c) 2024 Scott Duensing, scott@kangaroopunch.com
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <stdio.h>
#include <stdbool.h>
#define STB_IMAGE_IMPLEMENTATION
#include "../shared/stb_image.h"
#include "../shared/util.h"
int writeImage(byte *data, int imageWidth, colorT *palette, int colors, char *filename, int xs, int ys, int width, int height) {
int x;
int y;
int n;
int a;
colorT c;
FILE *out;
printf("Writing %dx%d indexed image %s...\n", width, height, filename);
out = fopen(filename, "wb");
if (out == NULL) {
printf("Unable to write %s. Aborting.\n", filename);
return 5;
}
for (y=ys; y<ys+height; y++) {
for (x=xs; x<xs+width; x++) {
a = (y * imageWidth * 3) + (x * 3);
c.r = data[a++];
c.g = data[a++];
c.b = data[a++];
for (n=0; n<colors; n++) {
if ((palette[n].r == c.r) && (palette[n].g == c.g) && (palette[n].b == c.b)) {
fputc(n, out);
break;
}
}
// This should never happen.
if (n == colors) {
printf("Color (%d, %d, %d) not found at %dx%d! Aborting.\n", c.r, c.g, c.b, x, y);
printf("Palette:\n");
for (n=0; n<colors; n++) {
printf("Color %d = (%d, %d, %d)\n", n, palette[n].r, palette[n].g, palette[n].b);
}
return 9;
}
}
}
fclose(out);
return 0;
}
int main(int argc, char *argv[]) {
int x;
int y;
int w;
int h;
int i;
int j;
int n;
int colors = 0;
byte found;
byte *data;
byte *p;
byte spriteSize = 0;
colorT c;
colorT palette[256];
char *filename;
char *temp;
FILE *out;
char *inputImage;
char *outputType;
bool okay;
if (argc < 3 || argc > 4) {
printf("Usage: %s [type] [imagefile]\n", argv[0]);
printf("Where: [type] is the output type:\n");
printf(" - image (creates CLUT and indexed image)\n");
printf(" - sprite (creates CLUT and indexed sprites)\n");
return 1;
}
outputType = argv[1];
inputImage = argv[2];
// Are we making sprites?
if (utilStricmp(outputType, "sprite") == 0) {
okay = false;
if (argc == 4) {
inputImage = argv[3];
spriteSize = atoi(argv[2]);
if (spriteSize == 8 || spriteSize == 16 || spriteSize == 24 || spriteSize == 32) {
okay = true;
}
}
if (!okay) {
printf("Usage: %s sprite [size] [imagefile]\n", argv[0]);
printf("Where: [size] is 8, 16, 24, or 32\n");
return 6;
}
}
// Load image, check for valid size.
data = stbi_load(inputImage, &w, &h, &n, 3);
if (data == NULL) {
printf("Unable to load %s!\n", inputImage);
return 2;
}
if (spriteSize > 0) {
// Sprites must be multiples of 8, 16, 24, or 32.
okay = false;
if (((int)(w / 8) == (w / 8.0)) && ((int)(h / 8) == (h / 8.0))) okay = true;
if (((int)(w / 16) == (w / 16.0)) && ((int)(h / 16) == (h / 16.0))) okay = true;
if (((int)(w / 24) == (w / 24.0)) && ((int)(h / 24) == (h / 24.0))) okay = true;
if (((int)(w / 32) == (w / 32.0)) && ((int)(h / 32) == (h / 32.0))) okay = true;
if (!okay) {
printf("Height and width must be divisible 8, 16, 24, or 32!\n");
return 8;
}
} else {
// Images are more lax - we'll let anything of the right width through.
if (w != 320) {
free(data);
printf("Images must be 320 pixels in width!\n");
return 7;
}
}
// Build palette.
printf("Building palette...\n");
p = data;
for (y=0; y<h; y++) {
for (x=0; x<w; x++) {
c.r = *p++;
c.g = *p++;
c.b = *p++;
found = 0;
for (n=0; n<colors; n++) {
if ((palette[n].r == c.r) && (palette[n].g == c.g) && (palette[n].b == c.b)) {
found = 1;
break;
}
}
if (found == 0) {
palette[colors].r = c.r;
palette[colors].g = c.g;
palette[colors].b = c.b;
colors++;
if (colors > 256) {
free(data);
printf("More than 256 colors in the image. Aborting.\n");
return 3;
}
}
}
}
// Write out F256 CLUT.
filename = utilReplaceExtension(inputImage, ".clut");
printf("Writing %d color palette %s...\n", colors, filename);
out = fopen(filename, "wb");
if (out == NULL) {
printf("Unable to write %s. Aborting.\n", filename);
free(data);
free(filename);
return 4;
}
for (n=0; n<colors; n++) {
fputc(palette[n].b, out);
fputc(palette[n].g, out);
fputc(palette[n].r, out);
fputc(0xff, out);
}
fclose(out);
free(filename);
if (spriteSize == 0) {
// Write out raw indexed image.
filename = utilReplaceExtension(inputImage, ".indexed");
n = writeImage(data, w, palette, colors, filename, 0, 0, w, h);
free(filename);
if (n != 0) {
free(data);
return n;
}
} else {
// Split image into multiple sprite images.
temp = utilReplaceExtension(inputImage, "");
i = 1;
j = 1;
for (y=0; y<h; y+=spriteSize) {
for (x=0; x<w; x+=spriteSize) {
filename = utilCreateString("%s-%dx%d.indexed", temp, i++, j);
printf("Writing from %dx%d to %dx%d for %d bytes\n", x, y, x+spriteSize, y+spriteSize, spriteSize*spriteSize);
n = writeImage(data, w, palette, colors, filename, x, y, spriteSize, spriteSize);
free(filename);
if (n != 0) {
free(temp);
free(data);
return n;
}
}
i = 1;
j++;
}
free(temp);
}
free(data);
printf("Finished!\n");
return 0;
}