diff --git a/buildsystem/modules/FindLibpng.cmake b/buildsystem/modules/FindLibpng.cmake new file mode 100644 index 00000000000..5f97e2adfe3 --- /dev/null +++ b/buildsystem/modules/FindLibpng.cmake @@ -0,0 +1,29 @@ +# Copyright 2020-2020 the openage authors. See copying.md for legal info. + +# - Find libpng library +# Find the native libpng headers and library. +# This module defines +# LIBPNG_INCLUDE_DIRS - where to find ogg/ogg.h etc. +# LIBPNG_LIBRARIES - List of libraries when using libogg +# LIBPNG_FOUND - True if ogg is found. + +find_path(LIBPNG_INCLUDE_DIR + NAMES libpng/png.h + DOC "libpng include directory" +) + +find_library(LIBPNG_LIBRARY + NAMES png + DOC "Path to libpng library" +) + +# handle the QUIETLY and REQUIRED arguments and set LIBPNG_FOUND to TRUE if +# all listed variables are TRUE +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(Libpng DEFAULT_MSG LIBPNG_INCLUDE_DIR LIBPNG_LIBRARY) + +mark_as_advanced(LIBPNG_INCLUDE_DIR LIBPNG_LIBRARY) + +# export the variables +set(LIBPNG_INCLUDE_DIRS "${LIBPNG_INCLUDE_DIR}") +set(LIBPNG_LIBRARIES "${LIBPNG_LIBRARY}") diff --git a/openage/convert/CMakeLists.txt b/openage/convert/CMakeLists.txt index fbf42aced01..c02f6f049da 100644 --- a/openage/convert/CMakeLists.txt +++ b/openage/convert/CMakeLists.txt @@ -35,4 +35,5 @@ add_subdirectory(hardcoded) add_subdirectory(interface) add_subdirectory(nyan) add_subdirectory(opus) +add_subdirectory(png) add_subdirectory(processor) diff --git a/openage/convert/opus/ogg.pxd b/openage/convert/opus/ogg.pxd index 5ad3d5aa8ab..25ac2979582 100644 --- a/openage/convert/opus/ogg.pxd +++ b/openage/convert/opus/ogg.pxd @@ -21,8 +21,6 @@ cdef extern from "ogg/ogg.h": ogg_int64_t granulepos ogg_int64_t packetno - - int ogg_stream_packetin(ogg_stream_state *os, ogg_packet *op) int ogg_stream_pageout(ogg_stream_state *os, ogg_page *og) int ogg_stream_flush(ogg_stream_state *os, ogg_page *og) diff --git a/openage/convert/png/CMakeLists.txt b/openage/convert/png/CMakeLists.txt new file mode 100644 index 00000000000..ebd2281a513 --- /dev/null +++ b/openage/convert/png/CMakeLists.txt @@ -0,0 +1,27 @@ +find_package(Libpng REQUIRED) + +# Currently there is no way to link cython modules to extra libraries. +# Since PYEXT_LINK_LIBRARY normally only includes libopenage (what +# opusenc doesn't need), we hijack this variable. This is ok, because +# there are no subdirectories, that will see the changed variable. +set(PYEXT_LINK_LIBRARY + ${LIBPNG_LIBRARIES} +) + +set(PYEXT_INCLUDE_DIRS + ${PYEXT_INCLUDE_DIRS} + ${LIBPNG_INCLUDE_DIRS} +) + +add_cython_modules( + png_create.pyx +) + +add_pxds( + __init__.pxd + libpng.pxd +) + +add_py_modules( + __init__.py +) diff --git a/openage/convert/png/__init__.pxd b/openage/convert/png/__init__.pxd new file mode 100644 index 00000000000..e69de29bb2d diff --git a/openage/convert/png/__init__.py b/openage/convert/png/__init__.py new file mode 100644 index 00000000000..598f6929ded --- /dev/null +++ b/openage/convert/png/__init__.py @@ -0,0 +1,5 @@ +# Copyright 2020-2020 the openage authors. See copying.md for legal info. + +""" +Cython module to create png files using libpng. +""" diff --git a/openage/convert/png/libpng.pxd b/openage/convert/png/libpng.pxd new file mode 100644 index 00000000000..3879d3fda53 --- /dev/null +++ b/openage/convert/png/libpng.pxd @@ -0,0 +1,59 @@ +# Copyright 2020-2020 the openage authors. See copying.md for legal info. + +from libc.stdio cimport FILE + +cdef extern from "libpng/png.h": + const char PNG_LIBPNG_VER_STRING[] + const int PNG_COLOR_TYPE_RGBA = 6 + const int PNG_INTERLACE_NONE = 0 + const int PNG_COMPRESSION_TYPE_DEFAULT = 0 + const int PNG_FILTER_TYPE_DEFAULT = 0 + const int PNG_TRANSFORM_IDENTITY = 0 + + ctypedef unsigned char png_byte + ctypedef png_byte** png_bytepp + ctypedef unsigned long int png_uint_32 + + ctypedef struct png_struct + ctypedef png_struct* png_structp + ctypedef png_struct* png_structrp + ctypedef png_struct** png_structpp + ctypedef const png_struct* png_const_structrp + + ctypedef struct png_info + ctypedef png_info* png_infop + ctypedef png_info* png_inforp + ctypedef png_info** png_infopp + + ctypedef const char* png_const_charp + ctypedef void* png_voidp + ctypedef (png_structp, png_const_charp)* png_error_ptr + ctypedef FILE* png_FILE_p + + png_structp png_create_write_struct(png_const_charp user_png_ver, + png_voidp error_ptr, + png_error_ptr error_fn, + png_error_ptr warn_fn) + + png_infop png_create_info_struct(png_const_structrp png_ptr) + + void png_set_IHDR(png_const_structrp png_ptr, + png_inforp info_ptr, + png_uint_32 width, + png_uint_32 height, + int bit_depth, + int color_type, + int interlace_method, + int compression_method, + int filter_method) + void png_init_io(png_structrp png_ptr, + png_FILE_p fp) + void png_set_rows(png_const_structrp png_ptr, + png_inforp info_ptr, + png_bytepp row_pointers) + void png_write_png(png_structrp png_ptr, + png_inforp info_ptr, + int transforms, + png_voidp params) + void png_destroy_write_struct(png_structpp png_ptr_ptr, + png_infopp info_ptr_ptr) \ No newline at end of file diff --git a/openage/convert/png/png_create.pyx b/openage/convert/png/png_create.pyx new file mode 100644 index 00000000000..33a381aa7e9 --- /dev/null +++ b/openage/convert/png/png_create.pyx @@ -0,0 +1,55 @@ +# Copyright 2020-2020 the openage authors. See copying.md for legal info. +# +# cython: profile=False + +from libc.stdio cimport fopen, fclose +from libc.stdint cimport uint8_t +from libc.stdlib cimport realloc +from cpython.mem cimport PyMem_Malloc + +from . cimport libpng + +cimport cython +import numpy +cimport numpy + + +@cython.boundscheck(False) +@cython.wraparound(False) +def save(filename, numpy.ndarray[numpy.uint8_t, ndim=3, mode="c"] imagedata not None): + """ + Save an image as a PNG file. + """ + cdef numpy.uint8_t[:,:,::1] mview = imagedata + cdef unsigned char* image = &mview[0,0,0] + png_create(filename.encode('UTF-8'), image) + + +cdef void png_create(char* filename, unsigned char* imagedata): + """ + Create a PNG file with libpng and write it to file. + """ + cdef libpng.png_FILE_p fp = fopen(filename, "wb") + + cdef libpng.png_structp png + cdef libpng.png_infop info + + png = libpng.png_create_write_struct(libpng.PNG_LIBPNG_VER_STRING, NULL, NULL, NULL) + info = libpng.png_create_info_struct(png) + + libpng.png_init_io(png, fp) + libpng.png_set_IHDR(png, + info, + sizeof(imagedata), + sizeof(imagedata[0]), + 8, + libpng.PNG_COLOR_TYPE_RGBA, + libpng.PNG_INTERLACE_NONE, + libpng.PNG_COMPRESSION_TYPE_DEFAULT, + libpng.PNG_FILTER_TYPE_DEFAULT) + libpng.png_set_rows(png, info, &imagedata) + libpng.png_write_png(png, info, libpng.PNG_TRANSFORM_IDENTITY, NULL) + + fclose(fp) + + libpng.png_destroy_write_struct(&png, &info) \ No newline at end of file diff --git a/openage/convert/slp.pyx b/openage/convert/slp.pyx index 73a7c1b23a9..3df5351ca63 100644 --- a/openage/convert/slp.pyx +++ b/openage/convert/slp.pyx @@ -968,7 +968,7 @@ cdef numpy.ndarray determine_rgba_matrix(vector[vector[pixel]] &image_matrix, cdef size_t height = image_matrix.size() cdef size_t width = image_matrix[0].size() - cdef numpy.ndarray[numpy.uint8_t, ndim=3] array_data = \ + cdef numpy.ndarray[numpy.uint8_t, ndim=3, mode="c"] array_data = \ numpy.zeros((height, width, 4), dtype=numpy.uint8) # micro optimization to avoid call to ColorTable.__getitem__() diff --git a/openage/convert/smp.pyx b/openage/convert/smp.pyx index 0945a211f34..b5f9bdf858c 100644 --- a/openage/convert/smp.pyx +++ b/openage/convert/smp.pyx @@ -689,7 +689,7 @@ cdef numpy.ndarray determine_rgba_matrix(vector[vector[pixel]] &image_matrix, cdef size_t height = image_matrix.size() cdef size_t width = image_matrix[0].size() - cdef numpy.ndarray[numpy.uint8_t, ndim=3] array_data = \ + cdef numpy.ndarray[numpy.uint8_t, ndim=3, mode="c"] array_data = \ numpy.zeros((height, width, 4), dtype=numpy.uint8) # micro optimization to avoid call to ColorTable.__getitem__() @@ -790,7 +790,7 @@ cdef numpy.ndarray determine_damage_matrix(vector[vector[pixel]] &image_matrix): cdef size_t height = image_matrix.size() cdef size_t width = image_matrix[0].size() - cdef numpy.ndarray[numpy.uint8_t, ndim=3] array_data = \ + cdef numpy.ndarray[numpy.uint8_t, ndim=3, mode="c"] array_data = \ numpy.zeros((height, width, 4), dtype=numpy.uint8) cdef uint8_t r diff --git a/openage/convert/smx.pyx b/openage/convert/smx.pyx index 2f75e1a7a17..85726d2e3de 100644 --- a/openage/convert/smx.pyx +++ b/openage/convert/smx.pyx @@ -1009,7 +1009,7 @@ cdef numpy.ndarray determine_rgba_matrix(vector[vector[pixel]] &image_matrix, cdef size_t height = image_matrix.size() cdef size_t width = image_matrix[0].size() - cdef numpy.ndarray[numpy.uint8_t, ndim=3] array_data = \ + cdef numpy.ndarray[numpy.uint8_t, ndim=3, mode="c"] array_data = \ numpy.zeros((height, width, 4), dtype=numpy.uint8) # micro optimization to avoid call to ColorTable.__getitem__() @@ -1104,7 +1104,7 @@ cdef numpy.ndarray determine_damage_matrix(vector[vector[pixel]] &image_matrix): cdef size_t height = image_matrix.size() cdef size_t width = image_matrix[0].size() - cdef numpy.ndarray[numpy.uint8_t, ndim=3] array_data = \ + cdef numpy.ndarray[numpy.uint8_t, ndim=3, mode="c"] array_data = \ numpy.zeros((height, width, 4), dtype=numpy.uint8) cdef uint8_t r diff --git a/openage/convert/texture.py b/openage/convert/texture.py index e31923fb0da..4322e60e5e1 100644 --- a/openage/convert/texture.py +++ b/openage/convert/texture.py @@ -145,6 +145,8 @@ def __init__(self, input_data, main_palette=None, raise Exception("cannot create Texture " "from unknown source type: %s" % (type(input_data))) + self.test_frame = frames[0].data # ASDF: Replace + self.image_data, (self.width, self.height), self.image_metadata\ = merge_frames(frames) @@ -214,6 +216,11 @@ def save(self, targetdir, filename, meta_formats=None): with targetdir[filename].open("wb") as imagefile: self.image_data.get_pil_image().save(imagefile, ext) + from .png import png_create + + if not isinstance(self.test_frame, TextureImage): + png_create.save("/tmp/test.png", self.test_frame) + if meta_formats: # generate formatted texture metadata formatter = data_formatter.DataFormatter()