mirror of https://github.com/opencv/opencv.git
parent
50e8ad285b
commit
3929e26276
18 changed files with 8707 additions and 12 deletions
@ -0,0 +1,47 @@ |
||||
# ---------------------------------------------------------------------------- |
||||
# CMake file for libspng. See root CMakeLists.txt |
||||
# |
||||
# ---------------------------------------------------------------------------- |
||||
|
||||
project(${SPNG_LIBRARY}) |
||||
|
||||
set(CURR_INCLUDE_DIR "${CMAKE_CURRENT_LIST_DIR}") |
||||
set_property(GLOBAL PROPERTY SPNG_INCLUDE_DIR ${CURR_INCLUDE_DIR}) |
||||
ocv_include_directories(${ZLIB_INCLUDE_DIRS}) |
||||
|
||||
file(GLOB_RECURSE spng_headers RELATIVE "${CMAKE_CURRENT_LIST_DIR}" "*.h") |
||||
file(GLOB_RECURSE spng_sources RELATIVE "${CMAKE_CURRENT_LIST_DIR}" "*.c") |
||||
|
||||
message(STATUS "libspng will be used as PNG codec") |
||||
|
||||
# ---------------------------------------------------------------------------------- |
||||
# Define the library target: |
||||
# ---------------------------------------------------------------------------------- |
||||
|
||||
if(MSVC) |
||||
add_definitions(-D_CRT_SECURE_NO_DEPRECATE) |
||||
endif(MSVC) |
||||
|
||||
add_library(${SPNG_LIBRARY} STATIC ${OPENCV_3RDPARTY_EXCLUDE_FROM_ALL} ${spng_headers} ${spng_sources}) |
||||
ocv_warnings_disable(CMAKE_C_FLAGS -Wunused-variable) |
||||
target_link_libraries(${SPNG_LIBRARY} ${ZLIB_LIBRARIES}) |
||||
|
||||
set_target_properties(${SPNG_LIBRARY} |
||||
PROPERTIES OUTPUT_NAME ${SPNG_LIBRARY} |
||||
DEBUG_POSTFIX "${OPENCV_DEBUG_POSTFIX}" |
||||
COMPILE_PDB_NAME ${SPNG_LIBRARY} |
||||
COMPILE_PDB_NAME_DEBUG "${SPNG_LIBRARY}${OPENCV_DEBUG_POSTFIX}" |
||||
ARCHIVE_OUTPUT_DIRECTORY ${3P_LIBRARY_OUTPUT_PATH} |
||||
) |
||||
|
||||
target_compile_definitions(${SPNG_LIBRARY} PUBLIC SPNG_STATIC) |
||||
|
||||
if(ENABLE_SOLUTION_FOLDERS) |
||||
set_target_properties(${SPNG_LIBRARY} PROPERTIES FOLDER "3rdparty") |
||||
endif() |
||||
|
||||
if(NOT BUILD_SHARED_LIBS) |
||||
ocv_install_target(${SPNG_LIBRARY} EXPORT OpenCVModules ARCHIVE DESTINATION ${OPENCV_3P_LIB_INSTALL_PATH} COMPONENT dev OPTIONAL) |
||||
endif() |
||||
|
||||
ocv_install_3rdparty_licenses(${SPNG_LIBRARY} LICENSE) |
@ -0,0 +1,25 @@ |
||||
BSD 2-Clause License |
||||
|
||||
Copyright (c) 2018-2022, Randy <randy408@protonmail.com> |
||||
All rights reserved. |
||||
|
||||
Redistribution and use in source and binary forms, with or without |
||||
modification, are permitted provided that the following conditions are met: |
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this |
||||
list of conditions and the following disclaimer. |
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice, |
||||
this list of conditions and the following disclaimer in the documentation |
||||
and/or other materials provided with the distribution. |
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE |
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR |
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,537 @@ |
||||
/* SPDX-License-Identifier: (BSD-2-Clause AND libpng-2.0) */ |
||||
#ifndef SPNG_H |
||||
#define SPNG_H |
||||
|
||||
#ifdef __cplusplus |
||||
extern "C" { |
||||
#endif |
||||
|
||||
#if (defined(_WIN32) || defined(__CYGWIN__)) && !defined(SPNG_STATIC) |
||||
#if defined(SPNG__BUILD) |
||||
#define SPNG_API __declspec(dllexport) |
||||
#else |
||||
#define SPNG_API __declspec(dllimport) |
||||
#endif |
||||
#else |
||||
#define SPNG_API |
||||
#endif |
||||
|
||||
#if defined(_MSC_VER) |
||||
#define SPNG_CDECL __cdecl |
||||
#else |
||||
#define SPNG_CDECL |
||||
#endif |
||||
|
||||
#include <stdlib.h> |
||||
#include <stdint.h> |
||||
#include <stdio.h> |
||||
|
||||
#define SPNG_VERSION_MAJOR 0 |
||||
#define SPNG_VERSION_MINOR 7 |
||||
#define SPNG_VERSION_PATCH 3 |
||||
|
||||
enum spng_errno |
||||
{ |
||||
SPNG_IO_ERROR = -2, |
||||
SPNG_IO_EOF = -1, |
||||
SPNG_OK = 0, |
||||
SPNG_EINVAL, |
||||
SPNG_EMEM, |
||||
SPNG_EOVERFLOW, |
||||
SPNG_ESIGNATURE, |
||||
SPNG_EWIDTH, |
||||
SPNG_EHEIGHT, |
||||
SPNG_EUSER_WIDTH, |
||||
SPNG_EUSER_HEIGHT, |
||||
SPNG_EBIT_DEPTH, |
||||
SPNG_ECOLOR_TYPE, |
||||
SPNG_ECOMPRESSION_METHOD, |
||||
SPNG_EFILTER_METHOD, |
||||
SPNG_EINTERLACE_METHOD, |
||||
SPNG_EIHDR_SIZE, |
||||
SPNG_ENOIHDR, |
||||
SPNG_ECHUNK_POS, |
||||
SPNG_ECHUNK_SIZE, |
||||
SPNG_ECHUNK_CRC, |
||||
SPNG_ECHUNK_TYPE, |
||||
SPNG_ECHUNK_UNKNOWN_CRITICAL, |
||||
SPNG_EDUP_PLTE, |
||||
SPNG_EDUP_CHRM, |
||||
SPNG_EDUP_GAMA, |
||||
SPNG_EDUP_ICCP, |
||||
SPNG_EDUP_SBIT, |
||||
SPNG_EDUP_SRGB, |
||||
SPNG_EDUP_BKGD, |
||||
SPNG_EDUP_HIST, |
||||
SPNG_EDUP_TRNS, |
||||
SPNG_EDUP_PHYS, |
||||
SPNG_EDUP_TIME, |
||||
SPNG_EDUP_OFFS, |
||||
SPNG_EDUP_EXIF, |
||||
SPNG_ECHRM, |
||||
SPNG_EPLTE_IDX, |
||||
SPNG_ETRNS_COLOR_TYPE, |
||||
SPNG_ETRNS_NO_PLTE, |
||||
SPNG_EGAMA, |
||||
SPNG_EICCP_NAME, |
||||
SPNG_EICCP_COMPRESSION_METHOD, |
||||
SPNG_ESBIT, |
||||
SPNG_ESRGB, |
||||
SPNG_ETEXT, |
||||
SPNG_ETEXT_KEYWORD, |
||||
SPNG_EZTXT, |
||||
SPNG_EZTXT_COMPRESSION_METHOD, |
||||
SPNG_EITXT, |
||||
SPNG_EITXT_COMPRESSION_FLAG, |
||||
SPNG_EITXT_COMPRESSION_METHOD, |
||||
SPNG_EITXT_LANG_TAG, |
||||
SPNG_EITXT_TRANSLATED_KEY, |
||||
SPNG_EBKGD_NO_PLTE, |
||||
SPNG_EBKGD_PLTE_IDX, |
||||
SPNG_EHIST_NO_PLTE, |
||||
SPNG_EPHYS, |
||||
SPNG_ESPLT_NAME, |
||||
SPNG_ESPLT_DUP_NAME, |
||||
SPNG_ESPLT_DEPTH, |
||||
SPNG_ETIME, |
||||
SPNG_EOFFS, |
||||
SPNG_EEXIF, |
||||
SPNG_EIDAT_TOO_SHORT, |
||||
SPNG_EIDAT_STREAM, |
||||
SPNG_EZLIB, |
||||
SPNG_EFILTER, |
||||
SPNG_EBUFSIZ, |
||||
SPNG_EIO, |
||||
SPNG_EOF, |
||||
SPNG_EBUF_SET, |
||||
SPNG_EBADSTATE, |
||||
SPNG_EFMT, |
||||
SPNG_EFLAGS, |
||||
SPNG_ECHUNKAVAIL, |
||||
SPNG_ENCODE_ONLY, |
||||
SPNG_EOI, |
||||
SPNG_ENOPLTE, |
||||
SPNG_ECHUNK_LIMITS, |
||||
SPNG_EZLIB_INIT, |
||||
SPNG_ECHUNK_STDLEN, |
||||
SPNG_EINTERNAL, |
||||
SPNG_ECTXTYPE, |
||||
SPNG_ENOSRC, |
||||
SPNG_ENODST, |
||||
SPNG_EOPSTATE, |
||||
SPNG_ENOTFINAL, |
||||
}; |
||||
|
||||
enum spng_text_type |
||||
{ |
||||
SPNG_TEXT = 1, |
||||
SPNG_ZTXT = 2, |
||||
SPNG_ITXT = 3 |
||||
}; |
||||
|
||||
enum spng_color_type |
||||
{ |
||||
SPNG_COLOR_TYPE_GRAYSCALE = 0, |
||||
SPNG_COLOR_TYPE_TRUECOLOR = 2, |
||||
SPNG_COLOR_TYPE_INDEXED = 3, |
||||
SPNG_COLOR_TYPE_GRAYSCALE_ALPHA = 4, |
||||
SPNG_COLOR_TYPE_TRUECOLOR_ALPHA = 6 |
||||
}; |
||||
|
||||
enum spng_filter |
||||
{ |
||||
SPNG_FILTER_NONE = 0, |
||||
SPNG_FILTER_SUB = 1, |
||||
SPNG_FILTER_UP = 2, |
||||
SPNG_FILTER_AVERAGE = 3, |
||||
SPNG_FILTER_PAETH = 4 |
||||
}; |
||||
|
||||
enum spng_filter_choice |
||||
{ |
||||
SPNG_DISABLE_FILTERING = 0, |
||||
SPNG_FILTER_CHOICE_NONE = 8, |
||||
SPNG_FILTER_CHOICE_SUB = 16, |
||||
SPNG_FILTER_CHOICE_UP = 32, |
||||
SPNG_FILTER_CHOICE_AVG = 64, |
||||
SPNG_FILTER_CHOICE_PAETH = 128, |
||||
SPNG_FILTER_CHOICE_ALL = (8|16|32|64|128) |
||||
}; |
||||
|
||||
enum spng_interlace_method |
||||
{ |
||||
SPNG_INTERLACE_NONE = 0, |
||||
SPNG_INTERLACE_ADAM7 = 1 |
||||
}; |
||||
|
||||
/* Channels are always in byte-order */ |
||||
enum spng_format |
||||
{ |
||||
SPNG_FMT_RGBA8 = 1, |
||||
SPNG_FMT_RGBA16 = 2, |
||||
SPNG_FMT_RGB8 = 4, |
||||
|
||||
/* Partially implemented, see documentation */ |
||||
SPNG_FMT_GA8 = 16, |
||||
SPNG_FMT_GA16 = 32, |
||||
SPNG_FMT_G8 = 64, |
||||
|
||||
/* No conversion or scaling */ |
||||
SPNG_FMT_PNG = 256, |
||||
SPNG_FMT_RAW = 512 /* big-endian (everything else is host-endian) */ |
||||
}; |
||||
|
||||
enum spng_ctx_flags |
||||
{ |
||||
SPNG_CTX_IGNORE_ADLER32 = 1, /* Ignore checksum in DEFLATE streams */ |
||||
SPNG_CTX_ENCODER = 2 /* Create an encoder context */ |
||||
}; |
||||
|
||||
enum spng_decode_flags |
||||
{ |
||||
SPNG_DECODE_USE_TRNS = 1, /* Deprecated */ |
||||
SPNG_DECODE_USE_GAMA = 2, /* Deprecated */ |
||||
SPNG_DECODE_USE_SBIT = 8, /* Undocumented */ |
||||
|
||||
SPNG_DECODE_TRNS = 1, /* Apply transparency */ |
||||
SPNG_DECODE_GAMMA = 2, /* Apply gamma correction */ |
||||
SPNG_DECODE_PROGRESSIVE = 256 /* Initialize for progressive reads */ |
||||
}; |
||||
|
||||
enum spng_crc_action |
||||
{ |
||||
/* Default for critical chunks */ |
||||
SPNG_CRC_ERROR = 0, |
||||
|
||||
/* Discard chunk, invalid for critical chunks.
|
||||
Since v0.6.2: default for ancillary chunks */ |
||||
SPNG_CRC_DISCARD = 1, |
||||
|
||||
/* Ignore and don't calculate checksum.
|
||||
Since v0.6.2: also ignores checksums in DEFLATE streams */ |
||||
SPNG_CRC_USE = 2 |
||||
}; |
||||
|
||||
enum spng_encode_flags |
||||
{ |
||||
SPNG_ENCODE_PROGRESSIVE = 1, /* Initialize for progressive writes */ |
||||
SPNG_ENCODE_FINALIZE = 2, /* Finalize PNG after encoding image */ |
||||
}; |
||||
|
||||
struct spng_ihdr |
||||
{ |
||||
uint32_t width; |
||||
uint32_t height; |
||||
uint8_t bit_depth; |
||||
uint8_t color_type; |
||||
uint8_t compression_method; |
||||
uint8_t filter_method; |
||||
uint8_t interlace_method; |
||||
}; |
||||
|
||||
struct spng_plte_entry |
||||
{ |
||||
uint8_t red; |
||||
uint8_t green; |
||||
uint8_t blue; |
||||
|
||||
uint8_t alpha; /* Reserved for internal use */ |
||||
}; |
||||
|
||||
struct spng_plte |
||||
{ |
||||
uint32_t n_entries; |
||||
struct spng_plte_entry entries[256]; |
||||
}; |
||||
|
||||
struct spng_trns |
||||
{ |
||||
uint16_t gray; |
||||
|
||||
uint16_t red; |
||||
uint16_t green; |
||||
uint16_t blue; |
||||
|
||||
uint32_t n_type3_entries; |
||||
uint8_t type3_alpha[256]; |
||||
}; |
||||
|
||||
struct spng_chrm_int |
||||
{ |
||||
uint32_t white_point_x; |
||||
uint32_t white_point_y; |
||||
uint32_t red_x; |
||||
uint32_t red_y; |
||||
uint32_t green_x; |
||||
uint32_t green_y; |
||||
uint32_t blue_x; |
||||
uint32_t blue_y; |
||||
}; |
||||
|
||||
struct spng_chrm |
||||
{ |
||||
double white_point_x; |
||||
double white_point_y; |
||||
double red_x; |
||||
double red_y; |
||||
double green_x; |
||||
double green_y; |
||||
double blue_x; |
||||
double blue_y; |
||||
}; |
||||
|
||||
struct spng_iccp |
||||
{ |
||||
char profile_name[80]; |
||||
size_t profile_len; |
||||
char *profile; |
||||
}; |
||||
|
||||
struct spng_sbit |
||||
{ |
||||
uint8_t grayscale_bits; |
||||
uint8_t red_bits; |
||||
uint8_t green_bits; |
||||
uint8_t blue_bits; |
||||
uint8_t alpha_bits; |
||||
}; |
||||
|
||||
struct spng_text |
||||
{ |
||||
char keyword[80]; |
||||
int type; |
||||
|
||||
size_t length; |
||||
char *text; |
||||
|
||||
uint8_t compression_flag; /* iTXt only */ |
||||
uint8_t compression_method; /* iTXt, ztXt only */ |
||||
char *language_tag; /* iTXt only */ |
||||
char *translated_keyword; /* iTXt only */ |
||||
}; |
||||
|
||||
struct spng_bkgd |
||||
{ |
||||
uint16_t gray; /* Only for gray/gray alpha */ |
||||
uint16_t red; |
||||
uint16_t green; |
||||
uint16_t blue; |
||||
uint16_t plte_index; /* Only for indexed color */ |
||||
}; |
||||
|
||||
struct spng_hist |
||||
{ |
||||
uint16_t frequency[256]; |
||||
}; |
||||
|
||||
struct spng_phys |
||||
{ |
||||
uint32_t ppu_x, ppu_y; |
||||
uint8_t unit_specifier; |
||||
}; |
||||
|
||||
struct spng_splt_entry |
||||
{ |
||||
uint16_t red; |
||||
uint16_t green; |
||||
uint16_t blue; |
||||
uint16_t alpha; |
||||
uint16_t frequency; |
||||
}; |
||||
|
||||
struct spng_splt |
||||
{ |
||||
char name[80]; |
||||
uint8_t sample_depth; |
||||
uint32_t n_entries; |
||||
struct spng_splt_entry *entries; |
||||
}; |
||||
|
||||
struct spng_time |
||||
{ |
||||
uint16_t year; |
||||
uint8_t month; |
||||
uint8_t day; |
||||
uint8_t hour; |
||||
uint8_t minute; |
||||
uint8_t second; |
||||
}; |
||||
|
||||
struct spng_offs |
||||
{ |
||||
int32_t x, y; |
||||
uint8_t unit_specifier; |
||||
}; |
||||
|
||||
struct spng_exif |
||||
{ |
||||
size_t length; |
||||
char *data; |
||||
}; |
||||
|
||||
struct spng_chunk |
||||
{ |
||||
size_t offset; |
||||
uint32_t length; |
||||
uint8_t type[4]; |
||||
uint32_t crc; |
||||
}; |
||||
|
||||
enum spng_location |
||||
{ |
||||
SPNG_AFTER_IHDR = 1, |
||||
SPNG_AFTER_PLTE = 2, |
||||
SPNG_AFTER_IDAT = 8, |
||||
}; |
||||
|
||||
struct spng_unknown_chunk |
||||
{ |
||||
uint8_t type[4]; |
||||
size_t length; |
||||
void *data; |
||||
enum spng_location location; |
||||
}; |
||||
|
||||
enum spng_option |
||||
{ |
||||
SPNG_KEEP_UNKNOWN_CHUNKS = 1, |
||||
|
||||
SPNG_IMG_COMPRESSION_LEVEL, |
||||
SPNG_IMG_WINDOW_BITS, |
||||
SPNG_IMG_MEM_LEVEL, |
||||
SPNG_IMG_COMPRESSION_STRATEGY, |
||||
|
||||
SPNG_TEXT_COMPRESSION_LEVEL, |
||||
SPNG_TEXT_WINDOW_BITS, |
||||
SPNG_TEXT_MEM_LEVEL, |
||||
SPNG_TEXT_COMPRESSION_STRATEGY, |
||||
|
||||
SPNG_FILTER_CHOICE, |
||||
SPNG_CHUNK_COUNT_LIMIT, |
||||
SPNG_ENCODE_TO_BUFFER, |
||||
}; |
||||
|
||||
typedef void* SPNG_CDECL spng_malloc_fn(size_t size); |
||||
typedef void* SPNG_CDECL spng_realloc_fn(void* ptr, size_t size); |
||||
typedef void* SPNG_CDECL spng_calloc_fn(size_t count, size_t size); |
||||
typedef void SPNG_CDECL spng_free_fn(void* ptr); |
||||
|
||||
struct spng_alloc |
||||
{ |
||||
spng_malloc_fn *malloc_fn; |
||||
spng_realloc_fn *realloc_fn; |
||||
spng_calloc_fn *calloc_fn; |
||||
spng_free_fn *free_fn; |
||||
}; |
||||
|
||||
struct spng_row_info |
||||
{ |
||||
uint32_t scanline_idx; |
||||
uint32_t row_num; /* deinterlaced row index */ |
||||
int pass; |
||||
uint8_t filter; |
||||
}; |
||||
|
||||
typedef struct spng_ctx spng_ctx; |
||||
|
||||
typedef int spng_read_fn(spng_ctx *ctx, void *user, void *dest, size_t length); |
||||
typedef int spng_write_fn(spng_ctx *ctx, void *user, void *src, size_t length); |
||||
|
||||
typedef int spng_rw_fn(spng_ctx *ctx, void *user, void *dst_src, size_t length); |
||||
|
||||
SPNG_API spng_ctx *spng_ctx_new(int flags); |
||||
SPNG_API spng_ctx *spng_ctx_new2(struct spng_alloc *alloc, int flags); |
||||
SPNG_API void spng_ctx_free(spng_ctx *ctx); |
||||
|
||||
SPNG_API int spng_set_png_buffer(spng_ctx *ctx, const void *buf, size_t size); |
||||
SPNG_API int spng_set_png_stream(spng_ctx *ctx, spng_rw_fn *rw_func, void *user); |
||||
SPNG_API int spng_set_png_file(spng_ctx *ctx, FILE *file); |
||||
|
||||
SPNG_API void *spng_get_png_buffer(spng_ctx *ctx, size_t *len, int *error); |
||||
|
||||
SPNG_API int spng_set_image_limits(spng_ctx *ctx, uint32_t width, uint32_t height); |
||||
SPNG_API int spng_get_image_limits(spng_ctx *ctx, uint32_t *width, uint32_t *height); |
||||
|
||||
SPNG_API int spng_set_chunk_limits(spng_ctx *ctx, size_t chunk_size, size_t cache_size); |
||||
SPNG_API int spng_get_chunk_limits(spng_ctx *ctx, size_t *chunk_size, size_t *cache_size); |
||||
|
||||
SPNG_API int spng_set_crc_action(spng_ctx *ctx, int critical, int ancillary); |
||||
|
||||
SPNG_API int spng_set_option(spng_ctx *ctx, enum spng_option option, int value); |
||||
SPNG_API int spng_get_option(spng_ctx *ctx, enum spng_option option, int *value); |
||||
|
||||
SPNG_API int spng_decoded_image_size(spng_ctx *ctx, int fmt, size_t *len); |
||||
|
||||
/* Decode */ |
||||
SPNG_API int spng_decode_image(spng_ctx *ctx, void *out, size_t len, int fmt, int flags); |
||||
|
||||
/* Progressive decode */ |
||||
SPNG_API int spng_decode_scanline(spng_ctx *ctx, void *out, size_t len); |
||||
SPNG_API int spng_decode_row(spng_ctx *ctx, void *out, size_t len); |
||||
SPNG_API int spng_decode_chunks(spng_ctx *ctx); |
||||
|
||||
/* Encode/decode */ |
||||
SPNG_API int spng_get_row_info(spng_ctx *ctx, struct spng_row_info *row_info); |
||||
|
||||
/* Encode */ |
||||
SPNG_API int spng_encode_image(spng_ctx *ctx, const void *img, size_t len, int fmt, int flags); |
||||
|
||||
/* Progressive encode */ |
||||
SPNG_API int spng_encode_scanline(spng_ctx *ctx, const void *scanline, size_t len); |
||||
SPNG_API int spng_encode_row(spng_ctx *ctx, const void *row, size_t len); |
||||
SPNG_API int spng_encode_chunks(spng_ctx *ctx); |
||||
|
||||
SPNG_API int spng_get_ihdr(spng_ctx *ctx, struct spng_ihdr *ihdr); |
||||
SPNG_API int spng_get_plte(spng_ctx *ctx, struct spng_plte *plte); |
||||
SPNG_API int spng_get_trns(spng_ctx *ctx, struct spng_trns *trns); |
||||
SPNG_API int spng_get_chrm(spng_ctx *ctx, struct spng_chrm *chrm); |
||||
SPNG_API int spng_get_chrm_int(spng_ctx *ctx, struct spng_chrm_int *chrm_int); |
||||
SPNG_API int spng_get_gama(spng_ctx *ctx, double *gamma); |
||||
SPNG_API int spng_get_gama_int(spng_ctx *ctx, uint32_t *gama_int); |
||||
SPNG_API int spng_get_iccp(spng_ctx *ctx, struct spng_iccp *iccp); |
||||
SPNG_API int spng_get_sbit(spng_ctx *ctx, struct spng_sbit *sbit); |
||||
SPNG_API int spng_get_srgb(spng_ctx *ctx, uint8_t *rendering_intent); |
||||
SPNG_API int spng_get_text(spng_ctx *ctx, struct spng_text *text, uint32_t *n_text); |
||||
SPNG_API int spng_get_bkgd(spng_ctx *ctx, struct spng_bkgd *bkgd); |
||||
SPNG_API int spng_get_hist(spng_ctx *ctx, struct spng_hist *hist); |
||||
SPNG_API int spng_get_phys(spng_ctx *ctx, struct spng_phys *phys); |
||||
SPNG_API int spng_get_splt(spng_ctx *ctx, struct spng_splt *splt, uint32_t *n_splt); |
||||
SPNG_API int spng_get_time(spng_ctx *ctx, struct spng_time *time); |
||||
SPNG_API int spng_get_unknown_chunks(spng_ctx *ctx, struct spng_unknown_chunk *chunks, uint32_t *n_chunks); |
||||
|
||||
/* Official extensions */ |
||||
SPNG_API int spng_get_offs(spng_ctx *ctx, struct spng_offs *offs); |
||||
SPNG_API int spng_get_exif(spng_ctx *ctx, struct spng_exif *exif); |
||||
|
||||
|
||||
SPNG_API int spng_set_ihdr(spng_ctx *ctx, struct spng_ihdr *ihdr); |
||||
SPNG_API int spng_set_plte(spng_ctx *ctx, struct spng_plte *plte); |
||||
SPNG_API int spng_set_trns(spng_ctx *ctx, struct spng_trns *trns); |
||||
SPNG_API int spng_set_chrm(spng_ctx *ctx, struct spng_chrm *chrm); |
||||
SPNG_API int spng_set_chrm_int(spng_ctx *ctx, struct spng_chrm_int *chrm_int); |
||||
SPNG_API int spng_set_gama(spng_ctx *ctx, double gamma); |
||||
SPNG_API int spng_set_gama_int(spng_ctx *ctx, uint32_t gamma); |
||||
SPNG_API int spng_set_iccp(spng_ctx *ctx, struct spng_iccp *iccp); |
||||
SPNG_API int spng_set_sbit(spng_ctx *ctx, struct spng_sbit *sbit); |
||||
SPNG_API int spng_set_srgb(spng_ctx *ctx, uint8_t rendering_intent); |
||||
SPNG_API int spng_set_text(spng_ctx *ctx, struct spng_text *text, uint32_t n_text); |
||||
SPNG_API int spng_set_bkgd(spng_ctx *ctx, struct spng_bkgd *bkgd); |
||||
SPNG_API int spng_set_hist(spng_ctx *ctx, struct spng_hist *hist); |
||||
SPNG_API int spng_set_phys(spng_ctx *ctx, struct spng_phys *phys); |
||||
SPNG_API int spng_set_splt(spng_ctx *ctx, struct spng_splt *splt, uint32_t n_splt); |
||||
SPNG_API int spng_set_time(spng_ctx *ctx, struct spng_time *time); |
||||
SPNG_API int spng_set_unknown_chunks(spng_ctx *ctx, struct spng_unknown_chunk *chunks, uint32_t n_chunks); |
||||
|
||||
/* Official extensions */ |
||||
SPNG_API int spng_set_offs(spng_ctx *ctx, struct spng_offs *offs); |
||||
SPNG_API int spng_set_exif(spng_ctx *ctx, struct spng_exif *exif); |
||||
|
||||
|
||||
SPNG_API const char *spng_strerror(int err); |
||||
SPNG_API const char *spng_version_string(void); |
||||
|
||||
#ifdef __cplusplus |
||||
} |
||||
#endif |
||||
|
||||
#endif /* SPNG_H */ |
@ -0,0 +1,41 @@ |
||||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html
|
||||
|
||||
#include "perf_precomp.hpp" |
||||
|
||||
namespace opencv_test |
||||
{ |
||||
using namespace perf; |
||||
|
||||
typedef perf::TestBaseWithParam<std::string> PNG; |
||||
|
||||
PERF_TEST(PNG, decode) |
||||
{ |
||||
String filename = getDataPath("perf/2560x1600.png"); |
||||
|
||||
FILE *f = fopen(filename.c_str(), "rb"); |
||||
fseek(f, 0, SEEK_END); |
||||
long len = ftell(f); |
||||
fseek(f, 0, SEEK_SET); |
||||
vector<uchar> file_buf((size_t)len); |
||||
EXPECT_EQ(len, (long)fread(&file_buf[0], 1, (size_t)len, f)); |
||||
fclose(f); f = NULL; |
||||
|
||||
TEST_CYCLE() imdecode(file_buf, IMREAD_UNCHANGED); |
||||
|
||||
SANITY_CHECK_NOTHING(); |
||||
} |
||||
|
||||
PERF_TEST(PNG, encode) |
||||
{ |
||||
String filename = getDataPath("perf/2560x1600.png"); |
||||
cv::Mat src = imread(filename); |
||||
|
||||
vector<uchar> buf; |
||||
TEST_CYCLE() imencode(".png", src, buf); |
||||
|
||||
SANITY_CHECK_NOTHING(); |
||||
} |
||||
|
||||
} // namespace
|
@ -0,0 +1,754 @@ |
||||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
|
||||
#include "precomp.hpp" |
||||
|
||||
#ifdef HAVE_SPNG |
||||
|
||||
/****************************************************************************************\
|
||||
This part of the file implements PNG codec on base of libspng library, |
||||
in particular, this code is based on example.c from libspng |
||||
(see 3rdparty/libspng/LICENSE for copyright notice) |
||||
\****************************************************************************************/ |
||||
|
||||
#ifndef _LFS64_LARGEFILE |
||||
#define _LFS64_LARGEFILE 0 |
||||
#endif |
||||
#ifndef _FILE_OFFSET_BITS |
||||
#define _FILE_OFFSET_BITS 0 |
||||
#endif |
||||
|
||||
#include <spng.h> |
||||
#include <zlib.h> |
||||
|
||||
#include "grfmt_spng.hpp" |
||||
|
||||
/*
|
||||
* libspng does not support RGB -> Gray conversion. In order to decode colorful images as grayscale |
||||
* we need conversion functions. In the previous png implementation(grfmt_png), the author was set |
||||
* to particular values for rgb coefficients. OpenCV icvCvt_BGR2Gray function values does not match |
||||
* with these values. (png_set_rgb_to_gray( png_ptr, 1, 0.299, 0.587 );) For this codec implementation, |
||||
* slightly modified versions are implemented in the below of this page. |
||||
*/ |
||||
void spngCvt_BGR2Gray_8u_C3C1R(const uchar *bgr, int bgr_step, |
||||
uchar *gray, int gray_step, |
||||
cv::Size size, int _swap_rb); |
||||
|
||||
void spngCvt_BGRA2Gray_8u_C4C1R(const uchar *bgra, int rgba_step, |
||||
uchar *gray, int gray_step, |
||||
cv::Size size, int _swap_rb); |
||||
|
||||
void spngCvt_BGRA2Gray_16u_CnC1R(const ushort *bgr, int bgr_step, |
||||
ushort *gray, int gray_step, |
||||
cv::Size size, int ncn, int _swap_rb); |
||||
|
||||
namespace cv |
||||
{ |
||||
|
||||
/////////////////////// SPngDecoder ///////////////////
|
||||
|
||||
SPngDecoder::SPngDecoder() |
||||
{ |
||||
m_signature = "\x89\x50\x4e\x47\xd\xa\x1a\xa"; |
||||
m_color_type = 0; |
||||
m_ctx = 0; |
||||
m_f = 0; |
||||
m_buf_supported = true; |
||||
m_buf_pos = 0; |
||||
m_bit_depth = 0; |
||||
} |
||||
|
||||
SPngDecoder::~SPngDecoder() |
||||
{ |
||||
close(); |
||||
} |
||||
|
||||
ImageDecoder SPngDecoder::newDecoder() const |
||||
{ |
||||
return makePtr<SPngDecoder>(); |
||||
} |
||||
|
||||
void SPngDecoder::close() |
||||
{ |
||||
if (m_f) |
||||
{ |
||||
fclose(m_f); |
||||
m_f = 0; |
||||
} |
||||
|
||||
if (m_ctx) |
||||
{ |
||||
struct spng_ctx *ctx = (struct spng_ctx *)m_ctx; |
||||
spng_ctx_free(ctx); |
||||
m_ctx = 0; |
||||
} |
||||
} |
||||
|
||||
int SPngDecoder::readDataFromBuf(void *sp_ctx, void *user, void *dst, size_t size) |
||||
{ |
||||
/*
|
||||
* typedef int spng_read_fn(spng_ctx *ctx, void *user, void *dest, size_t length) |
||||
* Type definition for callback passed to spng_set_png_stream() for decoders. |
||||
* A read callback function should copy length bytes to dest and return 0 or SPNG_IO_EOF/SPNG_IO_ERROR on error. |
||||
*/ |
||||
CV_UNUSED(sp_ctx); |
||||
SPngDecoder *decoder = (SPngDecoder *)(user); |
||||
CV_Assert(decoder); |
||||
|
||||
const Mat &buf = decoder->m_buf; |
||||
if (decoder->m_buf_pos + size > buf.cols * buf.rows * buf.elemSize()) |
||||
{ |
||||
return SPNG_IO_ERROR; |
||||
} |
||||
memcpy(dst, decoder->m_buf.ptr() + decoder->m_buf_pos, size); |
||||
decoder->m_buf_pos += size; |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
bool SPngDecoder::readHeader() |
||||
{ |
||||
volatile bool result = false; |
||||
close(); |
||||
|
||||
spng_ctx *ctx = spng_ctx_new(SPNG_CTX_IGNORE_ADLER32); |
||||
|
||||
if (!ctx) |
||||
{ |
||||
spng_ctx_free(ctx); |
||||
return false; |
||||
} |
||||
|
||||
m_ctx = ctx; |
||||
spng_set_crc_action(ctx, SPNG_CRC_USE, SPNG_CRC_USE); |
||||
|
||||
if (!m_buf.empty()) |
||||
spng_set_png_stream((struct spng_ctx *)m_ctx, (spng_rw_fn *)readDataFromBuf, this); |
||||
else |
||||
{ |
||||
m_f = fopen(m_filename.c_str(), "rb"); |
||||
if (m_f) |
||||
{ |
||||
spng_set_png_file(ctx, m_f); |
||||
} |
||||
} |
||||
|
||||
if (!m_buf.empty() || m_f) |
||||
{ |
||||
struct spng_ihdr ihdr; |
||||
int ret = spng_get_ihdr(ctx, &ihdr); |
||||
|
||||
if (ret == SPNG_OK) |
||||
{ |
||||
m_width = static_cast<int>(ihdr.width); |
||||
m_height = static_cast<int>(ihdr.height); |
||||
m_color_type = ihdr.color_type; |
||||
m_bit_depth = ihdr.bit_depth; |
||||
|
||||
if (ihdr.bit_depth <= 8 || ihdr.bit_depth == 16) |
||||
{ |
||||
int num_trans; |
||||
switch (ihdr.color_type) |
||||
{ |
||||
case SPNG_COLOR_TYPE_TRUECOLOR: |
||||
case SPNG_COLOR_TYPE_INDEXED: |
||||
struct spng_trns trns; |
||||
num_trans = !spng_get_trns(ctx, &trns); |
||||
if (num_trans > 0) |
||||
m_type = CV_8UC4; |
||||
else |
||||
m_type = CV_8UC3; |
||||
break; |
||||
case SPNG_COLOR_TYPE_GRAYSCALE_ALPHA: |
||||
case SPNG_COLOR_TYPE_TRUECOLOR_ALPHA: |
||||
m_type = CV_8UC4; |
||||
break; |
||||
default: |
||||
m_type = CV_8UC1; |
||||
} |
||||
if (ihdr.bit_depth == 16) |
||||
m_type = CV_MAKETYPE(CV_16U, CV_MAT_CN(m_type)); |
||||
result = true; |
||||
} |
||||
} |
||||
} |
||||
|
||||
return result; |
||||
} |
||||
|
||||
bool SPngDecoder::readData(Mat &img) |
||||
{ |
||||
volatile bool result = false; |
||||
bool color = img.channels() > 1; |
||||
|
||||
struct spng_ctx *png_ptr = (struct spng_ctx *)m_ctx; |
||||
|
||||
if (m_ctx && m_width && m_height) |
||||
{ |
||||
int fmt = SPNG_FMT_PNG; |
||||
|
||||
struct spng_trns trns; |
||||
int have_trns = spng_get_trns((struct spng_ctx *)m_ctx, &trns); |
||||
|
||||
int decode_flags = 0; |
||||
if (have_trns == SPNG_OK) |
||||
{ |
||||
decode_flags = SPNG_DECODE_TRNS; |
||||
} |
||||
if (img.channels() == 4) |
||||
{ |
||||
if (m_color_type == SPNG_COLOR_TYPE_TRUECOLOR || |
||||
m_color_type == SPNG_COLOR_TYPE_INDEXED || |
||||
m_color_type == SPNG_COLOR_TYPE_TRUECOLOR_ALPHA) |
||||
fmt = m_bit_depth == 16 ? SPNG_FMT_RGBA16 : SPNG_FMT_RGBA8; |
||||
else if (m_color_type == SPNG_COLOR_TYPE_GRAYSCALE) |
||||
fmt = m_bit_depth == 16 ? SPNG_FMT_GA16 : SPNG_FMT_GA8; |
||||
else if (m_color_type == SPNG_COLOR_TYPE_GRAYSCALE_ALPHA) |
||||
{ |
||||
fmt = m_bit_depth == 16 ? SPNG_FMT_RGBA16 : SPNG_FMT_RGBA8; |
||||
} |
||||
else |
||||
fmt = SPNG_FMT_RGBA8; |
||||
} |
||||
if (img.channels() == 3) |
||||
{ |
||||
fmt = SPNG_FMT_RGB8; |
||||
if ((m_color_type == SPNG_COLOR_TYPE_GRAYSCALE || m_color_type == SPNG_COLOR_TYPE_GRAYSCALE_ALPHA) && |
||||
m_bit_depth == 16) |
||||
fmt = SPNG_FMT_RGB8; |
||||
else if (m_bit_depth == 16) |
||||
fmt = SPNG_FMT_PNG; |
||||
} |
||||
else if (img.channels() == 1) |
||||
{ |
||||
if (m_color_type == SPNG_COLOR_TYPE_GRAYSCALE && m_bit_depth <= 8) |
||||
fmt = SPNG_FMT_G8; |
||||
else if (m_color_type == SPNG_COLOR_TYPE_GRAYSCALE && m_bit_depth == 16) |
||||
{ |
||||
if (img.depth() == CV_8U || img.depth() == CV_8S) |
||||
{ |
||||
fmt = SPNG_FMT_RGB8; |
||||
} |
||||
else |
||||
{ |
||||
fmt = SPNG_FMT_PNG; |
||||
} |
||||
} |
||||
else if (m_color_type == SPNG_COLOR_TYPE_INDEXED || |
||||
m_color_type == SPNG_COLOR_TYPE_TRUECOLOR) |
||||
{ |
||||
if (img.depth() == CV_8U || img.depth() == CV_8S) |
||||
{ |
||||
fmt = SPNG_FMT_RGB8; |
||||
} |
||||
else |
||||
{ |
||||
fmt = m_bit_depth == 16 ? SPNG_FMT_RGBA16 : SPNG_FMT_RGB8; |
||||
} |
||||
} |
||||
else if (m_color_type == SPNG_COLOR_TYPE_GRAYSCALE_ALPHA || fmt == SPNG_COLOR_TYPE_TRUECOLOR_ALPHA) |
||||
{ |
||||
if (img.depth() == CV_8U || img.depth() == CV_8S) |
||||
{ |
||||
fmt = SPNG_FMT_RGB8; |
||||
} |
||||
else |
||||
{ |
||||
fmt = m_bit_depth == 16 ? SPNG_FMT_RGBA16 : SPNG_FMT_RGBA8; |
||||
} |
||||
} |
||||
else |
||||
fmt = SPNG_FMT_RGB8; |
||||
} |
||||
|
||||
size_t image_width, image_size = 0; |
||||
int ret = spng_decoded_image_size(png_ptr, fmt, &image_size); |
||||
struct spng_ihdr ihdr; |
||||
spng_get_ihdr(png_ptr, &ihdr); |
||||
|
||||
if (ret == SPNG_OK) |
||||
{ |
||||
image_width = image_size / m_height; |
||||
|
||||
ret = spng_decode_image(png_ptr, nullptr, 0, fmt, SPNG_DECODE_PROGRESSIVE | decode_flags); |
||||
if (ret == SPNG_OK) |
||||
{ |
||||
struct spng_row_info row_info{}; |
||||
|
||||
// If user wants to read image as grayscale(IMREAD_GRAYSCALE), but image format is not
|
||||
// decode image then convert to grayscale
|
||||
if (!color && (fmt == SPNG_FMT_RGB8 || fmt == SPNG_FMT_RGBA8 || fmt == SPNG_FMT_RGBA16)) |
||||
{ |
||||
if (ihdr.interlace_method == 0) |
||||
{ |
||||
AutoBuffer<unsigned char> buffer; |
||||
buffer.allocate(image_width); |
||||
if (fmt == SPNG_FMT_RGB8) |
||||
{ |
||||
do |
||||
{ |
||||
ret = spng_get_row_info(png_ptr, &row_info); |
||||
if (ret) |
||||
break; |
||||
|
||||
ret = spng_decode_row(png_ptr, buffer.data(), image_width); |
||||
spngCvt_BGR2Gray_8u_C3C1R( |
||||
buffer.data(), |
||||
0, |
||||
img.data + row_info.row_num * img.step, |
||||
0, Size(m_width, 1), 2); |
||||
} while (ret == SPNG_OK); |
||||
} |
||||
else if (fmt == SPNG_FMT_RGBA8) |
||||
{ |
||||
do |
||||
{ |
||||
ret = spng_get_row_info(png_ptr, &row_info); |
||||
if (ret) |
||||
break; |
||||
|
||||
ret = spng_decode_row(png_ptr, buffer.data(), image_width); |
||||
spngCvt_BGRA2Gray_8u_C4C1R( |
||||
buffer.data(), |
||||
0, |
||||
img.data + row_info.row_num * img.step, |
||||
0, Size(m_width, 1), 2); |
||||
} while (ret == SPNG_OK); |
||||
} |
||||
else if (fmt == SPNG_FMT_RGBA16) |
||||
{ |
||||
do |
||||
{ |
||||
ret = spng_get_row_info(png_ptr, &row_info); |
||||
if (ret) |
||||
break; |
||||
|
||||
ret = spng_decode_row(png_ptr, buffer.data(), image_width); |
||||
spngCvt_BGRA2Gray_16u_CnC1R( |
||||
reinterpret_cast<const ushort *>(buffer.data()), 0, |
||||
reinterpret_cast<ushort *>(img.data + row_info.row_num * img.step), |
||||
0, Size(m_width, 1), |
||||
4, 2); |
||||
} while (ret == SPNG_OK); |
||||
} |
||||
} |
||||
else |
||||
{ |
||||
AutoBuffer<unsigned char> imageBuffer(image_size); |
||||
spng_decode_image(png_ptr, imageBuffer.data(), image_size, fmt, 0); |
||||
int step = m_width * img.channels(); |
||||
if (fmt == SPNG_FMT_RGB8) |
||||
{ |
||||
spngCvt_BGR2Gray_8u_C3C1R( |
||||
imageBuffer.data(), |
||||
step, |
||||
img.data, |
||||
step, Size(m_width, m_height), 2); |
||||
} |
||||
else if (fmt == SPNG_FMT_RGBA8) |
||||
{ |
||||
spngCvt_BGRA2Gray_8u_C4C1R( |
||||
imageBuffer.data(), |
||||
step, |
||||
img.data, |
||||
step, Size(m_width, m_height), 2); |
||||
} |
||||
else if (fmt == SPNG_FMT_RGBA16) |
||||
{ |
||||
spngCvt_BGRA2Gray_16u_CnC1R( |
||||
reinterpret_cast<const ushort *>(imageBuffer.data()), step / 3, |
||||
reinterpret_cast<ushort *>(img.data), |
||||
step / 3, Size(m_width, m_height), |
||||
4, 2); |
||||
} |
||||
} |
||||
} |
||||
else if (color) |
||||
{ // RGB -> BGR, convert row by row if png is non-interlaced, otherwise convert image as one
|
||||
int step = m_width * img.channels(); |
||||
AutoBuffer<uchar *> _buffer(m_height); |
||||
uchar **buffer = _buffer.data(); |
||||
for (int y = 0; y < m_height; y++) |
||||
{ |
||||
buffer[y] = img.data + y * img.step; |
||||
} |
||||
if (img.channels() == 4 && m_bit_depth == 16) |
||||
{ |
||||
do |
||||
{ |
||||
ret = spng_get_row_info(png_ptr, &row_info); |
||||
if (ret) |
||||
break; |
||||
|
||||
ret = spng_decode_row(png_ptr, buffer[row_info.row_num], image_width); |
||||
if (ihdr.interlace_method == 0) |
||||
{ |
||||
icvCvt_RGBA2BGRA_16u_C4R(reinterpret_cast<const ushort *>(buffer[row_info.row_num]), 0, |
||||
reinterpret_cast<ushort *>(buffer[row_info.row_num]), 0, |
||||
Size(m_width, 1)); |
||||
} |
||||
} while (ret == SPNG_OK); |
||||
if (ihdr.interlace_method) |
||||
{ |
||||
icvCvt_RGBA2BGRA_16u_C4R(reinterpret_cast<const ushort *>(img.data), step * 2, reinterpret_cast<ushort *>(img.data), step * 2, Size(m_width, m_height)); |
||||
} |
||||
} |
||||
else if (img.channels() == 4) |
||||
{ |
||||
do |
||||
{ |
||||
ret = spng_get_row_info(png_ptr, &row_info); |
||||
if (ret) |
||||
break; |
||||
|
||||
ret = spng_decode_row(png_ptr, buffer[row_info.row_num], image_width); |
||||
if (ihdr.interlace_method == 0) |
||||
{ |
||||
icvCvt_RGBA2BGRA_8u_C4R(buffer[row_info.row_num], 0, buffer[row_info.row_num], 0, Size(m_width, 1)); |
||||
} |
||||
} while (ret == SPNG_OK); |
||||
if (ihdr.interlace_method) |
||||
{ |
||||
icvCvt_RGBA2BGRA_8u_C4R(img.data, step, img.data, step, Size(m_width, m_height)); |
||||
} |
||||
} |
||||
else if (fmt == SPNG_FMT_PNG) |
||||
{ |
||||
do |
||||
{ |
||||
ret = spng_get_row_info(png_ptr, &row_info); |
||||
if (ret) |
||||
break; |
||||
|
||||
ret = spng_decode_row(png_ptr, buffer[row_info.row_num], image_width); |
||||
if (ihdr.interlace_method == 0) |
||||
{ |
||||
icvCvt_RGB2BGR_16u_C3R(reinterpret_cast<const ushort *>(buffer[row_info.row_num]), 0, |
||||
reinterpret_cast<ushort *>(buffer[row_info.row_num]), 0, Size(m_width, 1)); |
||||
} |
||||
} while (ret == SPNG_OK); |
||||
if (ihdr.interlace_method) |
||||
{ |
||||
icvCvt_RGB2BGR_16u_C3R(reinterpret_cast<const ushort *>(img.data), step, |
||||
reinterpret_cast<ushort *>(img.data), step, Size(m_width, m_height)); |
||||
} |
||||
} |
||||
else |
||||
{ |
||||
do |
||||
{ |
||||
ret = spng_get_row_info(png_ptr, &row_info); |
||||
if (ret) |
||||
break; |
||||
|
||||
ret = spng_decode_row(png_ptr, buffer[row_info.row_num], image_width); |
||||
if (ihdr.interlace_method == 0) |
||||
{ |
||||
icvCvt_RGB2BGR_8u_C3R(buffer[row_info.row_num], 0, buffer[row_info.row_num], 0, Size(m_width, 1)); |
||||
} |
||||
} while (ret == SPNG_OK); |
||||
if (ihdr.interlace_method) |
||||
{ |
||||
icvCvt_RGB2BGR_8u_C3R(img.data, step, img.data, step, Size(m_width, m_height)); |
||||
} |
||||
} |
||||
} |
||||
else |
||||
{ |
||||
do |
||||
{ |
||||
ret = spng_get_row_info(png_ptr, &row_info); |
||||
if (ret) |
||||
break; |
||||
|
||||
ret = spng_decode_row(png_ptr, img.data + row_info.row_num * image_width, image_width); |
||||
} while (ret == SPNG_OK); |
||||
} |
||||
} |
||||
|
||||
if (ret == SPNG_EOI) |
||||
{ |
||||
struct spng_exif exif_s{}; |
||||
ret = spng_get_exif(png_ptr, &exif_s); |
||||
if (ret == SPNG_OK) |
||||
{ |
||||
if (exif_s.data && exif_s.length > 0) |
||||
{ |
||||
m_exif.parseExif((unsigned char *)exif_s.data, exif_s.length); |
||||
} |
||||
} |
||||
result = true; |
||||
} |
||||
} |
||||
} |
||||
|
||||
return result; |
||||
} |
||||
|
||||
/////////////////////// SPngEncoder ///////////////////
|
||||
|
||||
SPngEncoder::SPngEncoder() |
||||
{ |
||||
m_description = "Portable Network Graphics files (*.png)"; |
||||
m_buf_supported = true; |
||||
} |
||||
|
||||
SPngEncoder::~SPngEncoder() |
||||
{ |
||||
} |
||||
|
||||
bool SPngEncoder::isFormatSupported(int depth) const |
||||
{ |
||||
return depth == CV_8U || depth == CV_16U; |
||||
} |
||||
|
||||
ImageEncoder SPngEncoder::newEncoder() const |
||||
{ |
||||
return makePtr<SPngEncoder>(); |
||||
} |
||||
|
||||
int SPngEncoder::writeDataToBuf(void *ctx, void *user, void *dst_src, size_t length) |
||||
{ |
||||
CV_UNUSED(ctx); |
||||
SPngEncoder *encoder = (SPngEncoder *)(user); |
||||
CV_Assert(encoder && encoder->m_buf); |
||||
size_t cursz = encoder->m_buf->size(); |
||||
encoder->m_buf->resize(cursz + length); |
||||
memcpy(&(*encoder->m_buf)[cursz], dst_src, length); |
||||
return 0; |
||||
} |
||||
|
||||
bool SPngEncoder::write(const Mat &img, const std::vector<int> ¶ms) |
||||
{ |
||||
int fmt; |
||||
spng_ctx *ctx = spng_ctx_new(SPNG_CTX_ENCODER); |
||||
FILE *volatile f = 0; |
||||
int width = img.cols, height = img.rows; |
||||
int depth = img.depth(), channels = img.channels(); |
||||
volatile bool result = false; |
||||
|
||||
if (depth != CV_8U && depth != CV_16U) |
||||
return false; |
||||
|
||||
if (ctx) |
||||
{ |
||||
struct spng_ihdr ihdr = {}; |
||||
ihdr.height = height; |
||||
ihdr.width = width; |
||||
int compression_level = -1; // Invalid value to allow setting 0-9 as valid
|
||||
int compression_strategy = IMWRITE_PNG_STRATEGY_RLE; // Default strategy
|
||||
bool isBilevel = false; |
||||
|
||||
for (size_t i = 0; i < params.size(); i += 2) |
||||
{ |
||||
if (params[i] == IMWRITE_PNG_COMPRESSION) |
||||
{ |
||||
compression_strategy = IMWRITE_PNG_STRATEGY_DEFAULT; // Default strategy
|
||||
compression_level = params[i + 1]; |
||||
compression_level = MIN(MAX(compression_level, 0), Z_BEST_COMPRESSION); |
||||
} |
||||
if (params[i] == IMWRITE_PNG_STRATEGY) |
||||
{ |
||||
compression_strategy = params[i + 1]; |
||||
compression_strategy = MIN(MAX(compression_strategy, 0), Z_FIXED); |
||||
} |
||||
if (params[i] == IMWRITE_PNG_BILEVEL) |
||||
{ |
||||
isBilevel = params[i + 1] != 0; |
||||
} |
||||
} |
||||
fmt = channels == 1 ? SPNG_COLOR_TYPE_GRAYSCALE : channels == 3 ? SPNG_COLOR_TYPE_TRUECOLOR |
||||
: SPNG_COLOR_TYPE_TRUECOLOR_ALPHA; |
||||
|
||||
ihdr.bit_depth = depth == CV_8U ? isBilevel ? 1 : 8 : 16; |
||||
ihdr.color_type = fmt; |
||||
ihdr.interlace_method = SPNG_INTERLACE_NONE; |
||||
ihdr.filter_method = SPNG_FILTER_NONE; |
||||
ihdr.compression_method = 0; |
||||
spng_set_ihdr(ctx, &ihdr); |
||||
|
||||
if (m_buf) |
||||
{ |
||||
spng_set_png_stream(ctx, (spng_rw_fn *)writeDataToBuf, this); |
||||
} |
||||
else |
||||
{ |
||||
f = fopen(m_filename.c_str(), "wb"); |
||||
if (f) |
||||
spng_set_png_file(ctx, f); |
||||
} |
||||
|
||||
if (m_buf || f) |
||||
{ |
||||
if (compression_level >= 0) |
||||
{ |
||||
spng_set_option(ctx, SPNG_IMG_COMPRESSION_LEVEL, compression_level); |
||||
} |
||||
else |
||||
{ |
||||
spng_set_option(ctx, SPNG_FILTER_CHOICE, SPNG_FILTER_CHOICE_SUB); |
||||
spng_set_option(ctx, SPNG_IMG_COMPRESSION_LEVEL, Z_BEST_SPEED); |
||||
} |
||||
spng_set_option(ctx, SPNG_IMG_COMPRESSION_STRATEGY, compression_strategy); |
||||
|
||||
int ret; |
||||
spng_encode_chunks(ctx); |
||||
ret = spng_encode_image(ctx, nullptr, 0, SPNG_FMT_PNG, SPNG_ENCODE_PROGRESSIVE); |
||||
if (channels > 1) |
||||
{ |
||||
int error; |
||||
if (ret == SPNG_OK) |
||||
{ |
||||
if (depth == CV_16U) |
||||
{ |
||||
AutoBuffer<ushort *> buff2; |
||||
buff2.allocate(height); |
||||
for (int y = 0; y < height; y++) |
||||
buff2[y] = reinterpret_cast<unsigned short *>(img.data + y * img.step); |
||||
|
||||
AutoBuffer<ushort> _buffer; |
||||
_buffer.allocate(width * channels * 2); |
||||
for (int y = 0; y < height; y++) |
||||
{ |
||||
if (channels == 3) |
||||
{ |
||||
icvCvt_BGR2RGB_16u_C3R(buff2[y], 0, |
||||
_buffer.data(), 0, Size(width, 1)); |
||||
} |
||||
else if (channels == 4) |
||||
{ |
||||
icvCvt_BGRA2RGBA_16u_C4R(buff2[y], 0, |
||||
_buffer.data(), 0, Size(width, 1)); |
||||
} |
||||
error = spng_encode_row(ctx, _buffer.data(), width * channels * 2); |
||||
if (error) |
||||
break; |
||||
} |
||||
} |
||||
else |
||||
{ |
||||
AutoBuffer<uchar *> buff; |
||||
buff.allocate(height); |
||||
for (int y = 0; y < height; y++) |
||||
buff[y] = img.data + y * img.step; |
||||
|
||||
AutoBuffer<uchar> _buffer; |
||||
_buffer.allocate(width * channels); |
||||
for (int y = 0; y < height; y++) |
||||
{ |
||||
if (channels == 3) |
||||
{ |
||||
icvCvt_BGR2RGB_8u_C3R(buff[y], 0, _buffer.data(), 0, Size(width, 1)); |
||||
} |
||||
else if (channels == 4) |
||||
{ |
||||
icvCvt_BGRA2RGBA_8u_C4R(buff[y], 0, _buffer.data(), 0, Size(width, 1)); |
||||
} |
||||
error = spng_encode_row(ctx, _buffer.data(), width * channels); |
||||
if (error) |
||||
break; |
||||
} |
||||
} |
||||
if (error == SPNG_EOI) |
||||
{ // success
|
||||
spng_encode_chunks(ctx); |
||||
ret = SPNG_OK; |
||||
} |
||||
} |
||||
} |
||||
else |
||||
{ |
||||
int error; |
||||
for (int y = 0; y < height; y++) |
||||
{ |
||||
error = spng_encode_row(ctx, img.data + y * img.step, width * channels * (depth == CV_16U ? 2 : 1)); |
||||
if (error) |
||||
break; |
||||
} |
||||
if (error == SPNG_EOI) |
||||
{ // success
|
||||
spng_encode_chunks(ctx); |
||||
ret = SPNG_OK; |
||||
} |
||||
} |
||||
if (ret == SPNG_OK) |
||||
result = true; |
||||
} |
||||
} |
||||
|
||||
spng_ctx_free(ctx); |
||||
if (f) |
||||
fclose((FILE *)f); |
||||
|
||||
return result; |
||||
} |
||||
|
||||
} |
||||
|
||||
void spngCvt_BGR2Gray_8u_C3C1R(const uchar *bgr, int bgr_step, |
||||
uchar *gray, int gray_step, |
||||
cv::Size size, int _swap_rb) |
||||
{ |
||||
int i; |
||||
for (; size.height--; gray += gray_step) |
||||
{ |
||||
double cBGR0 = 0.1140441895; |
||||
double cBGR2 = 0.2989807129; |
||||
if (_swap_rb) |
||||
std::swap(cBGR0, cBGR2); |
||||
for (i = 0; i < size.width; i++, bgr += 3) |
||||
{ |
||||
int t = static_cast<int>(cBGR0 * bgr[0] + 0.5869750977 * bgr[1] + cBGR2 * bgr[2]); |
||||
gray[i] = (uchar)t; |
||||
} |
||||
|
||||
bgr += bgr_step - size.width * 3; |
||||
} |
||||
} |
||||
|
||||
void spngCvt_BGRA2Gray_8u_C4C1R(const uchar *bgra, int rgba_step, |
||||
uchar *gray, int gray_step, |
||||
cv::Size size, int _swap_rb) |
||||
{ |
||||
int i; |
||||
for (; size.height--; gray += gray_step) |
||||
{ |
||||
double cBGR0 = 0.1140441895; |
||||
double cBGR2 = 0.2989807129; |
||||
if (_swap_rb) |
||||
std::swap(cBGR0, cBGR2); |
||||
for (i = 0; i < size.width; i++, bgra += 4) |
||||
{ |
||||
int t = cBGR0 * bgra[0] + 0.5869750977 * bgra[1] + cBGR2 * bgra[2]; |
||||
gray[i] = (uchar)t; |
||||
} |
||||
|
||||
bgra += rgba_step - size.width * 4; |
||||
} |
||||
} |
||||
|
||||
void spngCvt_BGRA2Gray_16u_CnC1R(const ushort *bgr, int bgr_step, |
||||
ushort *gray, int gray_step, |
||||
cv::Size size, int ncn, int _swap_rb) |
||||
{ |
||||
int i; |
||||
for (; size.height--; gray += gray_step) |
||||
{ |
||||
double cBGR0 = 0.1140441895; |
||||
double cBGR2 = 0.2989807129; |
||||
if (_swap_rb) |
||||
std::swap(cBGR0, cBGR2); |
||||
for (i = 0; i < size.width; i++, bgr += ncn) |
||||
{ |
||||
int t = cBGR0 * bgr[0] + 0.5869750977 * bgr[1] + cBGR2 * bgr[2]; |
||||
gray[i] = (ushort)t; |
||||
} |
||||
|
||||
bgr += bgr_step - size.width * ncn; |
||||
} |
||||
} |
||||
|
||||
#endif |
||||
|
||||
/* End of file. */ |
@ -0,0 +1,60 @@ |
||||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
|
||||
#ifndef _GRFMT_SPNG_H_ |
||||
#define _GRFMT_SPNG_H_ |
||||
|
||||
#ifdef HAVE_SPNG |
||||
|
||||
#include "grfmt_base.hpp" |
||||
#include "bitstrm.hpp" |
||||
|
||||
namespace cv |
||||
{ |
||||
|
||||
class SPngDecoder CV_FINAL : public BaseImageDecoder |
||||
{ |
||||
public: |
||||
|
||||
SPngDecoder(); |
||||
virtual ~SPngDecoder(); |
||||
|
||||
bool readData( Mat& img ) CV_OVERRIDE; |
||||
bool readHeader() CV_OVERRIDE; |
||||
void close(); |
||||
|
||||
ImageDecoder newDecoder() const CV_OVERRIDE; |
||||
|
||||
protected: |
||||
|
||||
static int readDataFromBuf(void* sp_ctx, void *user, void* dst, size_t size); |
||||
|
||||
int m_bit_depth; |
||||
void* m_ctx; |
||||
FILE* m_f; |
||||
int m_color_type; |
||||
size_t m_buf_pos; |
||||
}; |
||||
|
||||
|
||||
class SPngEncoder CV_FINAL : public BaseImageEncoder |
||||
{ |
||||
public: |
||||
SPngEncoder(); |
||||
virtual ~SPngEncoder(); |
||||
|
||||
bool isFormatSupported( int depth ) const CV_OVERRIDE; |
||||
bool write( const Mat& img, const std::vector<int>& params ) CV_OVERRIDE; |
||||
|
||||
ImageEncoder newEncoder() const CV_OVERRIDE; |
||||
|
||||
protected: |
||||
static int writeDataToBuf(void *ctx, void *user, void *dst_src, size_t length); |
||||
}; |
||||
|
||||
} |
||||
|
||||
#endif |
||||
|
||||
#endif/*_GRFMT_PNG_H_*/ |
Loading…
Reference in new issue