diff --git a/tools/png2stratagus.cpp b/tools/png2stratagus.cpp new file mode 100644 index 000000000..0a5735701 --- /dev/null +++ b/tools/png2stratagus.cpp @@ -0,0 +1,387 @@ +// _________ __ __ +// / _____// |_____________ _/ |______ ____ __ __ ______ +// \_____ \\ __\_ __ \__ \\ __\__ \ / ___\| | \/ ___/ +// / \| | | | \// __ \| | / __ \_/ /_/ > | /\___ | +// /_______ /|__| |__| (____ /__| (____ /\___ /|____//____ > +// \/ \/ \//_____/ \/ +// ______________________ ______________________ +// T H E W A R B E G I N S +// Utility for Stratagus - A free fantasy real time strategy game engine +// +// Copyright (C) 2002 Ingo Ruhnke +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +/* To compile this programm: + + % g++ -o png2stratagus png2stratagus.cxx -lpng + */ + +/* This programm can be used to fix the palette of a indexed png file + to be suitable for Stratagus. It works like this: + + 1) You create a RGBA image in Gimp + + 2) You convert it to indexed with 227 colors + + [Generate Optimal Palette # Colors 227] (MAX_COLORS - 1) + + 3) You run png2stratagus on the image + + 4) The final images will be written to out.png in the current + directory + */ + +#include +#include +#include +#include +#include +#include + +#define MAX_COLORS 228 + +class Color +{ +public: + int red; + int green; + int blue; + + Color () + : red (0), green (255), blue (0) + { + } + + Color (int r, int g, int b) + : red (r), green (g), blue (b) + { + } +}; + +class Image +{ +private: + int m_width; + int m_height; + int m_transcol; + std::vector m_image; + std::vector m_palette; + +public: + /** Load an image from a given png source */ + Image (const std::string& filename) + { + FILE* fp; + png_structp png_ptr; + png_infop info_ptr; + png_uint_32 pwidth, pheight; + int bit_depth, color_type, interlace_type, compression_type, filter_type; + int row_bytes; + + if ((fp = fopen(filename.c_str (), "rb")) == NULL) + { + perror (filename.c_str ()); + exit (EXIT_FAILURE); + } + + png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, + NULL, NULL, NULL); + info_ptr = png_create_info_struct(png_ptr); + png_init_io(png_ptr, fp); + png_read_info(png_ptr, info_ptr); + png_get_IHDR(png_ptr, info_ptr, &pwidth, &pheight, + &bit_depth, &color_type, &interlace_type, + &compression_type, &filter_type); + row_bytes = png_get_rowbytes(png_ptr, info_ptr); + + // Create the 'data' array + png_bytep row_pointers[pheight]; + for (unsigned int i = 0; i < pheight; i++) + row_pointers[i] = new png_byte[row_bytes]; + + png_read_image(png_ptr, row_pointers); + + if (color_type != PNG_COLOR_TYPE_PALETTE) + { + std::cout << "Unsupported color type" << std::endl; + exit (EXIT_FAILURE); + } + + int num_colors; + int num_trans = 0; + png_colorp lpalette; + png_bytep trans; + png_color_16p trans_values; + + // Read some more data + png_get_PLTE(png_ptr, info_ptr, &lpalette, &num_colors); + png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, &trans_values); + + // not sure what trans_values stand for + + //for (int i = 0; i < num_trans; ++i) + //std::cout << "transcolors: " << trans_values[i] << std::endl; + + if (num_trans > 1) + { + std::cout << "Multiple transcolors not supported" << std::endl; + exit (EXIT_FAILURE); + } + else if (num_trans == 1) + m_transcol = trans[0]; + else + m_transcol = -1; + + for (int i = 0; i < num_trans; i++) + std::cout << "transcolor: " << int(trans[i]) << std::endl; + + m_width = pwidth; + m_height = pheight; + + m_image.resize (m_width * m_height); + + // Convert the png into our internal data structure + for (int y = 0; y < m_height; y++) + { + for (int i = 0; i < row_bytes; i++) + { + m_image[i + (m_width * y)] = row_pointers[y][i]; + } + } + + assert (num_colors <= 256); + + if (num_colors > MAX_COLORS) + { + std::cout << "Image has more than " << MAX_COLORS + << " colors (" << num_colors << "), bailout" << std::endl; + exit (EXIT_FAILURE); + } + + m_palette.resize (256); + for (int i = 0; i < num_colors; ++i) + { + m_palette[i].red = lpalette[i].red; + m_palette[i].green = lpalette[i].green; + m_palette[i].blue = lpalette[i].blue; + } + + png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); + fclose (fp); + } + + ~Image () + { + } + + void write_png (std::string filename) + { + FILE* fp; + png_structp png_ptr; + png_infop info_ptr; + png_colorp palette; + //png_uint_32 bytes_per_pixel = 1; + + fp = fopen(filename.c_str (), "wb"); + if (fp == NULL) + assert (false); + + png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, + NULL, NULL, NULL); + + png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + info_ptr = png_create_info_struct(png_ptr); + png_init_io(png_ptr, fp); + + png_set_IHDR(png_ptr, info_ptr, m_width, m_height, 8 /* bitdepth */, + PNG_COLOR_TYPE_PALETTE, + PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); + + palette = (png_colorp)png_malloc(png_ptr, PNG_MAX_PALETTE_LENGTH + * sizeof (png_color)); + + std::cout << "MAX: " << PNG_MAX_PALETTE_LENGTH << std::endl; + for (unsigned int i = 0; i < m_palette.size(); ++i) + { + palette[i].red = m_palette[i].red; + palette[i].green = m_palette[i].green; + palette[i].blue = m_palette[i].blue; + } + + /** insert palette converter here */ + png_set_PLTE(png_ptr, info_ptr, palette, PNG_MAX_PALETTE_LENGTH); + + png_write_info(png_ptr, info_ptr); + + + png_uint_32 height = m_height, width = m_width; + png_byte image[height * width /* *bytes_per_pixel */]; + png_bytep row_pointers[height]; + + // fill the image with data + for (unsigned int i = 0; i < m_image.size (); ++i) + { + image[i] = m_image[i]; + } + + for (unsigned int k = 0; k < height; k++) + row_pointers[k] = image + k * width /* * bytes_per_pixel*/; + + png_write_image(png_ptr, row_pointers); + + png_write_end(png_ptr, info_ptr); + png_free(png_ptr, palette); + //png_free(png_ptr, trans); + png_destroy_write_struct(&png_ptr, &info_ptr); + fclose(fp); + } + + /** swaps color a and color b in both the palette and the image */ + void swap_colors (int a, int b) + { + std::swap (m_palette[a], m_palette[b]); + + for (std::vector::iterator i = m_image.begin (); i != m_image.end (); ++i) + { + if (*i == a) + *i = b; + else if (*i == b) + *i = a; + } + } + + void set_color (int i, Color c) { + m_palette[i] = c; + } + + int get_transcolor () { + return m_transcol; + } + + int num_colors () { + return m_palette.size (); + } + + int get_width () { + return m_width; + } + + int get_height () { + return m_height; + } +}; + +int main (int argc, char* argv[]) +{ + if (argc != 3) + { + printf ("Usage: %s INFILE OUTFILE\n", argv[0]); + exit (EXIT_FAILURE); + } + else + { + Image mypng (argv[1]); + std::cout << "Width: " << mypng.get_width () + << " Height: " << mypng.get_height () + << " Colors: " << mypng.num_colors () << std::endl; + + /* + #0 general background (RGB = 0,0,0) + + #208 replaced by player color 1 + #209 replaced by player color 2 + #210 replaced by player color 3 + #211 replaced by player color 4 + + #38-#47 color cycle + #240-244 color cycle + + #253 general editors color (should NEVER be used in any image, RGB = 255,50,255) + + #255 general transparency color (RGB, 255,255,255) + */ + + if (mypng.get_transcolor () != -1) + mypng.swap_colors (mypng.get_transcolor (), 255); + + // Swap all colors to un used palette positions + mypng.swap_colors (0, 254); + mypng.swap_colors (208, 252); + mypng.swap_colors (209, 251); + mypng.swap_colors (210, 250); + mypng.swap_colors (211, 249); + + // Water Cycle + mypng.swap_colors (38, 248); + mypng.swap_colors (39, 247); + mypng.swap_colors (40, 246); + mypng.swap_colors (41, 245); + mypng.swap_colors (42, 239); + mypng.swap_colors (43, 238); + mypng.swap_colors (44, 237); + mypng.swap_colors (45, 236); + mypng.swap_colors (46, 235); + mypng.swap_colors (47, 234); + + mypng.swap_colors (240, 233); + mypng.swap_colors (241, 232); + mypng.swap_colors (242, 231); + mypng.swap_colors (243, 230); + mypng.swap_colors (244, 229); + + // This are in a range which shouldn't get touched, so changing + //them might not be needed + //mypng.swap_colors (253, 250); + //mypng.swap_colors (255, 249); + + // Set all hard-coded colors to some usefull defaults for preview + mypng.set_color (0, Color (0, 0, 0)); + + mypng.set_color (208, Color ( 60, 60, 0)); + mypng.set_color (209, Color (110, 110, 0)); + mypng.set_color (210, Color (200, 200, 0)); + mypng.set_color (211, Color (255, 255, 0)); + + // Button cycle + mypng.set_color (240, Color (255, 0, 255)); + mypng.set_color (241, Color (255, 0, 255)); + mypng.set_color (242, Color (255, 0, 255)); + mypng.set_color (243, Color (255, 0, 255)); + mypng.set_color (244, Color (255, 0, 255)); + + // Water cycle + mypng.set_color (38, Color (255, 0, 255)); + mypng.set_color (39, Color (255, 0, 255)); + mypng.set_color (40, Color (255, 0, 255)); + mypng.set_color (41, Color (255, 0, 255)); + mypng.set_color (42, Color (255, 0, 255)); + mypng.set_color (43, Color (255, 0, 255)); + mypng.set_color (44, Color (255, 0, 255)); + mypng.set_color (45, Color (255, 0, 255)); + mypng.set_color (46, Color (255, 0, 255)); + mypng.set_color (47, Color (255, 0, 255)); + + mypng.set_color (253, Color (255, 50, 255)); + mypng.set_color (255, Color (255, 255, 255)); + + mypng.write_png (argv[2]); + + std::cout << "Convert complete" << std::endl; + } +} + + +// EOF //