Python CFFI bindings for image format libraries
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

120 lines
3.5KB

  1. #!/usr/bin/env python3
  2. # libflif cffi bindings
  3. # (c) 2017 Taeyeon Mori
  4. import os
  5. import re
  6. import cffi
  7. from simplecpp import simple_cpp
  8. flif_headers = "/usr/include/FLIF"
  9. # --------------------------------------------------------------
  10. # helper source code
  11. source = """
  12. #include <FLIF/flif.h>
  13. #include <Python.h>
  14. /*
  15. uint32_t flif_python_callback(uint32_t quality, int64_t bytes_read, uint8_t decode_over, void *user_data, void *context)
  16. {
  17. PyObject *py_callback = user_data;
  18. if (!user_data)
  19. {
  20. PyErr_SetString(PyExc_ValueError, "user_data cannot be NULL for python callbacks");
  21. return 0;
  22. }
  23. // TODO
  24. } */
  25. void flif_image_read_into_GRAY8(FLIF_IMAGE *image, void *buffer, size_t buffer_size)
  26. {
  27. uint32_t rows = flif_image_get_height(image);
  28. uint32_t columns = flif_image_get_width(image);
  29. for (uint32_t row = 0; row < rows && (row + 1) * columns <= buffer_size; ++row)
  30. {
  31. flif_image_read_row_GRAY8(image, row, buffer + row * columns, columns);
  32. }
  33. }
  34. void flif_image_read_into_RGBA8(FLIF_IMAGE *image, void *buffer, size_t buffer_size)
  35. {
  36. uint32_t rows = flif_image_get_height(image);
  37. uint32_t columns = flif_image_get_width(image);
  38. for (uint32_t row = 0; row < rows && (row + 1) * columns * 4 <= buffer_size; ++row)
  39. {
  40. flif_image_read_row_RGBA8(image, row, buffer + row * columns * 4, columns * 4);
  41. }
  42. }
  43. void flif_image_read_into_RGB8(FLIF_IMAGE *image, void *buffer, size_t buffer_size)
  44. {
  45. uint32_t rows = flif_image_get_height(image);
  46. uint32_t columns = flif_image_get_width(image);
  47. uint32_t row;
  48. for (row = 0; row < rows && row * columns * 3 + columns * 4 <= buffer_size; ++row)
  49. {
  50. // Read RGBA8
  51. uint8_t *row_buf = (uint8_t *)buffer + row * columns * 3;
  52. flif_image_read_row_RGBA8(image, row, row_buf, columns * 4);
  53. // Remove Alpha channel
  54. for (uint32_t col = 1; col < columns; ++col)
  55. {
  56. row_buf[col * 3] = row_buf[col * 4];
  57. row_buf[col * 3 + 1] = row_buf[col * 4 + 1];
  58. row_buf[col * 3 + 2] = row_buf[col * 4 + 2];
  59. }
  60. }
  61. // Last row
  62. if (row < rows && buffer_size >= (row + 1) * columns * 3)
  63. {
  64. uint8_t lastrow_buf[columns * 4];
  65. uint8_t *row_buf = (uint8_t *)buffer + row * columns * 3;
  66. flif_image_read_row_RGBA8(image, row, lastrow_buf, columns * 4);
  67. for (uint32_t col = 0; col < columns; ++col)
  68. {
  69. row_buf[col * 3] = lastrow_buf[col * 4];
  70. row_buf[col * 3 + 1] = lastrow_buf[col * 4 + 1];
  71. row_buf[col * 3 + 2] = lastrow_buf[col * 4 + 2];
  72. }
  73. }
  74. }
  75. """
  76. # --------------------------------------------------------------
  77. # Initialize CFFI
  78. libflif = cffi.FFI()
  79. libflif.set_source("imglibs._libflif", source, libraries=["flif"])
  80. # --------------------------------------------------------------
  81. # Import libflif symbols
  82. defs = {}
  83. for header in ("flif_common.h", "flif_dec.h", "flif_enc.h"):
  84. with open(os.path.join(flif_headers, header), "r") as f:
  85. libflif.cdef("".join(simple_cpp(f, defs)))
  86. # --------------------------------------------------------------
  87. # Define above helper funcs
  88. libflif.cdef("""
  89. void flif_image_read_into_GRAY8(FLIF_IMAGE *image, void *buffer, size_t buffer_size);
  90. void flif_image_read_into_RGBA8(FLIF_IMAGE *image, void *buffer, size_t buffer_size);
  91. void flif_image_read_into_RGB8(FLIF_IMAGE *image, void *buffer, size_t buffer_size);
  92. """)
  93. # --------------------------------------------------------------
  94. # Build
  95. if __name__ == "__main__":
  96. libflif.compile(verbose=True)