spng encoder/decoder added as optional png codec
This commit is contained in:
@@ -2155,7 +2155,7 @@ static void showSaveDialog(CvWindow& window)
|
||||
#endif
|
||||
ofn.hwndOwner = window.hwnd;
|
||||
ofn.lpstrFilter =
|
||||
#ifdef HAVE_PNG
|
||||
#if defined(HAVE_PNG) || defined(HAVE_SPNG)
|
||||
"Portable Network Graphics files (*.png)\0*.png\0"
|
||||
#endif
|
||||
"Windows bitmap (*.bmp;*.dib)\0*.bmp;*.dib\0"
|
||||
@@ -2181,7 +2181,7 @@ static void showSaveDialog(CvWindow& window)
|
||||
ofn.lpstrFile = szFileName;
|
||||
ofn.nMaxFile = MAX_PATH;
|
||||
ofn.Flags = OFN_EXPLORER | OFN_PATHMUSTEXIST | OFN_OVERWRITEPROMPT | OFN_NOREADONLYRETURN | OFN_NOCHANGEDIR;
|
||||
#ifdef HAVE_PNG
|
||||
#if defined(HAVE_PNG) || defined(HAVE_SPNG)
|
||||
ofn.lpstrDefExt = "png";
|
||||
#else
|
||||
ofn.lpstrDefExt = "bmp";
|
||||
|
||||
@@ -24,6 +24,12 @@ if(HAVE_WEBP)
|
||||
list(APPEND GRFMT_LIBS ${WEBP_LIBRARIES})
|
||||
endif()
|
||||
|
||||
if(HAVE_SPNG)
|
||||
add_definitions(${SPNG_DEFINITIONS})
|
||||
ocv_include_directories(${SPNG_INCLUDE_DIR})
|
||||
list(APPEND GRFMT_LIBS ${SPNG_LIBRARY})
|
||||
endif()
|
||||
|
||||
if(HAVE_PNG)
|
||||
add_definitions(${PNG_DEFINITIONS})
|
||||
ocv_include_directories(${PNG_INCLUDE_DIR})
|
||||
@@ -67,7 +73,7 @@ if(HAVE_OPENEXR)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(HAVE_PNG OR HAVE_TIFF OR HAVE_OPENEXR)
|
||||
if(HAVE_PNG OR HAVE_TIFF OR HAVE_OPENEXR OR HAVE_SPNG)
|
||||
ocv_include_directories(${ZLIB_INCLUDE_DIRS})
|
||||
list(APPEND GRFMT_LIBS ${ZLIB_LIBRARIES})
|
||||
endif()
|
||||
|
||||
@@ -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_*/
|
||||
@@ -49,6 +49,7 @@
|
||||
#include "grfmt_pxm.hpp"
|
||||
#include "grfmt_pfm.hpp"
|
||||
#include "grfmt_tiff.hpp"
|
||||
#include "grfmt_spng.hpp"
|
||||
#include "grfmt_png.hpp"
|
||||
#include "grfmt_jpeg2000.hpp"
|
||||
#include "grfmt_jpeg2000_openjpeg.hpp"
|
||||
|
||||
@@ -167,7 +167,10 @@ struct ImageCodecInitializer
|
||||
decoders.push_back( makePtr<TiffDecoder>() );
|
||||
encoders.push_back( makePtr<TiffEncoder>() );
|
||||
#endif
|
||||
#ifdef HAVE_PNG
|
||||
#ifdef HAVE_SPNG
|
||||
decoders.push_back( makePtr<SPngDecoder>() );
|
||||
encoders.push_back( makePtr<SPngEncoder>() );
|
||||
#elif defined(HAVE_PNG)
|
||||
decoders.push_back( makePtr<PngDecoder>() );
|
||||
encoders.push_back( makePtr<PngEncoder>() );
|
||||
#endif
|
||||
|
||||
@@ -211,7 +211,7 @@ TEST_P(Imgcodecs_ExtSize, write_imageseq)
|
||||
|
||||
const string all_exts[] =
|
||||
{
|
||||
#ifdef HAVE_PNG
|
||||
#if defined(HAVE_PNG) || defined(HAVE_SPNG)
|
||||
".png",
|
||||
#endif
|
||||
#ifdef HAVE_TIFF
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
namespace opencv_test { namespace {
|
||||
|
||||
#ifdef HAVE_PNG
|
||||
#if defined(HAVE_PNG) || defined(HAVE_SPNG)
|
||||
|
||||
TEST(Imgcodecs_Png, write_big)
|
||||
{
|
||||
@@ -186,6 +186,225 @@ const string exif_files[] =
|
||||
INSTANTIATE_TEST_CASE_P(ExifFiles, Imgcodecs_PNG_Exif,
|
||||
testing::ValuesIn(exif_files));
|
||||
|
||||
|
||||
typedef testing::TestWithParam<string> Imgcodecs_Png_PngSuite;
|
||||
|
||||
TEST_P(Imgcodecs_Png_PngSuite, decode)
|
||||
{
|
||||
const string root = cvtest::TS::ptr()->get_data_path();
|
||||
const string filename = root + "pngsuite/" + GetParam() + ".png";
|
||||
const string xml_filename = root + "pngsuite/" + GetParam() + ".xml";
|
||||
FileStorage fs(xml_filename, FileStorage::READ);
|
||||
EXPECT_TRUE(fs.isOpened());
|
||||
|
||||
Mat src = imread(filename, IMREAD_UNCHANGED);
|
||||
Mat gt;
|
||||
fs.getFirstTopLevelNode() >> gt;
|
||||
|
||||
EXPECT_PRED_FORMAT2(cvtest::MatComparator(0, 0), src, gt);
|
||||
}
|
||||
|
||||
const string pngsuite_files[] =
|
||||
{
|
||||
"basi0g01",
|
||||
"basi0g02",
|
||||
"basi0g04",
|
||||
"basi0g08",
|
||||
"basi0g16",
|
||||
"basi2c08",
|
||||
"basi2c16",
|
||||
"basi3p01",
|
||||
"basi3p02",
|
||||
"basi3p04",
|
||||
"basi3p08",
|
||||
"basi4a08",
|
||||
"basi4a16",
|
||||
"basi6a08",
|
||||
"basi6a16",
|
||||
"basn0g01",
|
||||
"basn0g02",
|
||||
"basn0g04",
|
||||
"basn0g08",
|
||||
"basn0g16",
|
||||
"basn2c08",
|
||||
"basn2c16",
|
||||
"basn3p01",
|
||||
"basn3p02",
|
||||
"basn3p04",
|
||||
"basn3p08",
|
||||
"basn4a08",
|
||||
"basn4a16",
|
||||
"basn6a08",
|
||||
"basn6a16",
|
||||
"bgai4a08",
|
||||
"bgai4a16",
|
||||
"bgan6a08",
|
||||
"bgan6a16",
|
||||
"bgbn4a08",
|
||||
"bggn4a16",
|
||||
"bgwn6a08",
|
||||
"bgyn6a16",
|
||||
"ccwn2c08",
|
||||
"ccwn3p08",
|
||||
"cdfn2c08",
|
||||
"cdhn2c08",
|
||||
"cdsn2c08",
|
||||
"cdun2c08",
|
||||
"ch1n3p04",
|
||||
"ch2n3p08",
|
||||
"cm0n0g04",
|
||||
"cm7n0g04",
|
||||
"cm9n0g04",
|
||||
"cs3n2c16",
|
||||
"cs3n3p08",
|
||||
"cs5n2c08",
|
||||
"cs5n3p08",
|
||||
"cs8n2c08",
|
||||
"cs8n3p08",
|
||||
"ct0n0g04",
|
||||
"ct1n0g04",
|
||||
"cten0g04",
|
||||
"ctfn0g04",
|
||||
"ctgn0g04",
|
||||
"cthn0g04",
|
||||
"ctjn0g04",
|
||||
"ctzn0g04",
|
||||
"exif2c08",
|
||||
"f00n0g08",
|
||||
"f00n2c08",
|
||||
"f01n0g08",
|
||||
"f01n2c08",
|
||||
"f02n0g08",
|
||||
"f02n2c08",
|
||||
"f03n0g08",
|
||||
"f03n2c08",
|
||||
"f04n0g08",
|
||||
"f04n2c08",
|
||||
"f99n0g04",
|
||||
"g03n0g16",
|
||||
"g03n2c08",
|
||||
"g03n3p04",
|
||||
"g04n0g16",
|
||||
"g04n2c08",
|
||||
"g04n3p04",
|
||||
"g05n0g16",
|
||||
"g05n2c08",
|
||||
"g05n3p04",
|
||||
"g07n0g16",
|
||||
"g07n2c08",
|
||||
"g07n3p04",
|
||||
"g10n0g16",
|
||||
"g10n2c08",
|
||||
"g10n3p04",
|
||||
"g25n0g16",
|
||||
"g25n2c08",
|
||||
"g25n3p04",
|
||||
"oi1n0g16",
|
||||
"oi1n2c16",
|
||||
"oi2n0g16",
|
||||
"oi2n2c16",
|
||||
"oi4n0g16",
|
||||
"oi4n2c16",
|
||||
"oi9n0g16",
|
||||
"oi9n2c16",
|
||||
"pp0n2c16",
|
||||
"pp0n6a08",
|
||||
"ps1n0g08",
|
||||
"ps1n2c16",
|
||||
"ps2n0g08",
|
||||
"ps2n2c16",
|
||||
"s01i3p01",
|
||||
"s01n3p01",
|
||||
"s02i3p01",
|
||||
"s02n3p01",
|
||||
"s03i3p01",
|
||||
"s03n3p01",
|
||||
"s04i3p01",
|
||||
"s04n3p01",
|
||||
"s05i3p02",
|
||||
"s05n3p02",
|
||||
"s06i3p02",
|
||||
"s06n3p02",
|
||||
"s07i3p02",
|
||||
"s07n3p02",
|
||||
"s08i3p02",
|
||||
"s08n3p02",
|
||||
"s09i3p02",
|
||||
"s09n3p02",
|
||||
"s32i3p04",
|
||||
"s32n3p04",
|
||||
"s33i3p04",
|
||||
"s33n3p04",
|
||||
"s34i3p04",
|
||||
"s34n3p04",
|
||||
"s35i3p04",
|
||||
"s35n3p04",
|
||||
"s36i3p04",
|
||||
"s36n3p04",
|
||||
"s37i3p04",
|
||||
"s37n3p04",
|
||||
"s38i3p04",
|
||||
"s38n3p04",
|
||||
"s39i3p04",
|
||||
"s39n3p04",
|
||||
"s40i3p04",
|
||||
"s40n3p04",
|
||||
"tbbn0g04",
|
||||
"tbbn2c16",
|
||||
"tbbn3p08",
|
||||
"tbgn2c16",
|
||||
"tbgn3p08",
|
||||
"tbrn2c08",
|
||||
"tbwn0g16",
|
||||
"tbwn3p08",
|
||||
"tbyn3p08",
|
||||
"tm3n3p02",
|
||||
"tp0n0g08",
|
||||
"tp0n2c08",
|
||||
"tp0n3p08",
|
||||
"tp1n3p08",
|
||||
"z00n2c08",
|
||||
"z03n2c08",
|
||||
"z06n2c08",
|
||||
"z09n2c08",
|
||||
};
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(/*nothing*/, Imgcodecs_Png_PngSuite,
|
||||
testing::ValuesIn(pngsuite_files));
|
||||
|
||||
typedef testing::TestWithParam<string> Imgcodecs_Png_PngSuite_Corrupted;
|
||||
|
||||
TEST_P(Imgcodecs_Png_PngSuite_Corrupted, decode)
|
||||
{
|
||||
const string root = cvtest::TS::ptr()->get_data_path();
|
||||
const string filename = root + "pngsuite/" + GetParam() + ".png";
|
||||
|
||||
Mat src = imread(filename, IMREAD_UNCHANGED);
|
||||
|
||||
// Corrupted files should not be read
|
||||
EXPECT_TRUE(src.empty());
|
||||
}
|
||||
|
||||
const string pngsuite_files_corrupted[] = {
|
||||
"xc1n0g08",
|
||||
"xc9n2c08",
|
||||
"xcrn0g04",
|
||||
"xcsn0g01",
|
||||
"xd0n2c08",
|
||||
"xd3n2c08",
|
||||
"xd9n2c08",
|
||||
"xdtn0g01",
|
||||
"xhdn0g08",
|
||||
"xlfn0g04",
|
||||
"xs1n0g01",
|
||||
"xs2n0g01",
|
||||
"xs4n0g01",
|
||||
"xs7n0g01",
|
||||
};
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(/*nothing*/, Imgcodecs_Png_PngSuite_Corrupted,
|
||||
testing::ValuesIn(pngsuite_files_corrupted));
|
||||
|
||||
#endif // HAVE_PNG
|
||||
|
||||
}} // namespace
|
||||
|
||||
@@ -28,7 +28,7 @@ const tuple<string, Size> images[] =
|
||||
#ifdef HAVE_JPEG
|
||||
make_tuple<string, Size>("../cv/imgproc/stuff.jpg", Size(640, 480)),
|
||||
#endif
|
||||
#ifdef HAVE_PNG
|
||||
#if defined(HAVE_PNG) || defined(HAVE_SPNG)
|
||||
make_tuple<string, Size>("../cv/shared/pic1.png", Size(400, 300)),
|
||||
#endif
|
||||
make_tuple<string, Size>("../highgui/readwrite/ordinary.bmp", Size(480, 272)),
|
||||
@@ -148,7 +148,7 @@ typedef string Ext;
|
||||
typedef testing::TestWithParam<Ext> Imgcodecs_Image;
|
||||
|
||||
const string exts[] = {
|
||||
#ifdef HAVE_PNG
|
||||
#if defined(HAVE_PNG) || defined(HAVE_SPNG)
|
||||
"png",
|
||||
#endif
|
||||
#ifdef HAVE_TIFF
|
||||
|
||||
@@ -71,7 +71,7 @@ void CV_DrawingTest::run( int )
|
||||
{
|
||||
//imwrite( filename, testImg );
|
||||
ts->printf( ts->LOG, "test image can not be read");
|
||||
#ifdef HAVE_PNG
|
||||
#if defined(HAVE_PNG) || defined(HAVE_SPNG)
|
||||
ts->set_failed_test_info(cvtest::TS::FAIL_INVALID_TEST_DATA);
|
||||
#else
|
||||
ts->printf( ts->LOG, "PNG image support is not available");
|
||||
|
||||
Reference in New Issue
Block a user