v01
This commit is contained in:
177
thirdparty/Pangolin/src/image/image_io.cpp
vendored
Normal file
177
thirdparty/Pangolin/src/image/image_io.cpp
vendored
Normal file
@@ -0,0 +1,177 @@
|
||||
/* This file is part of the Pangolin Project.
|
||||
* http://github.com/stevenlovegrove/Pangolin
|
||||
*
|
||||
* Copyright (c) 2013 Steven Lovegrove
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation
|
||||
* files (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following
|
||||
* conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <pangolin/image/image_io.h>
|
||||
|
||||
#include <fstream>
|
||||
|
||||
namespace pangolin {
|
||||
|
||||
// PNG
|
||||
TypedImage LoadPng(std::istream& in);
|
||||
void SavePng(const Image<unsigned char>& image, const pangolin::PixelFormat& fmt, std::ostream& out, bool top_line_first, int zlib_compression_level );
|
||||
|
||||
// JPG
|
||||
TypedImage LoadJpg(std::istream& in);
|
||||
void SaveJpg(const Image<unsigned char>& image, const pangolin::PixelFormat& fmt, std::ostream& out, float quality);
|
||||
|
||||
// PPM
|
||||
TypedImage LoadPpm(std::istream& in);
|
||||
void SavePpm(const Image<unsigned char>& image, const pangolin::PixelFormat& fmt, std::ostream& out, bool top_line_first);
|
||||
|
||||
// TGA
|
||||
TypedImage LoadTga(std::istream& in);
|
||||
|
||||
// Pango
|
||||
TypedImage LoadPango(const std::string& filename);
|
||||
void SavePango(const Image<unsigned char>& image, const pangolin::PixelFormat& fmt, const std::string& filename, bool top_line_first);
|
||||
|
||||
// EXR
|
||||
TypedImage LoadExr(std::istream& source);
|
||||
void SaveExr(const Image<unsigned char>& image, const pangolin::PixelFormat& fmt, const std::string& filename, bool top_line_first);
|
||||
|
||||
// ZSTD (https://github.com/facebook/zstd)
|
||||
TypedImage LoadZstd(std::istream& in);
|
||||
void SaveZstd(const Image<unsigned char>& image, const pangolin::PixelFormat& fmt, std::ostream& out, int compression_level);
|
||||
|
||||
// https://github.com/lz4/lz4
|
||||
TypedImage LoadLz4(std::istream& in);
|
||||
void SaveLz4(const Image<unsigned char>& image, const pangolin::PixelFormat& fmt, std::ostream& out, int compression_level);
|
||||
|
||||
// packed 12 bit image (obtained from unpacked 16bit)
|
||||
TypedImage LoadPacked12bit(std::istream& in);
|
||||
void SavePacked12bit(const Image<unsigned char>& image, const pangolin::PixelFormat& fmt, std::ostream& out, int compression_level);
|
||||
|
||||
TypedImage LoadImage(std::istream& in, ImageFileType file_type)
|
||||
{
|
||||
switch (file_type) {
|
||||
case ImageFileTypePng:
|
||||
return LoadPng(in);
|
||||
case ImageFileTypeJpg:
|
||||
return LoadJpg(in);
|
||||
case ImageFileTypePpm:
|
||||
return LoadPpm(in);
|
||||
case ImageFileTypeTga:
|
||||
return LoadTga(in);
|
||||
case ImageFileTypeZstd:
|
||||
return LoadZstd(in);
|
||||
case ImageFileTypeLz4:
|
||||
return LoadLz4(in);
|
||||
case ImageFileTypeP12b:
|
||||
return LoadPacked12bit(in);
|
||||
case ImageFileTypeExr:
|
||||
return LoadExr(in);
|
||||
default:
|
||||
throw std::runtime_error("Unable to load image file-type through std::istream");
|
||||
}
|
||||
}
|
||||
|
||||
TypedImage LoadImage(const std::string& filename, ImageFileType file_type)
|
||||
{
|
||||
switch (file_type) {
|
||||
case ImageFileTypePng:
|
||||
case ImageFileTypeJpg:
|
||||
case ImageFileTypePpm:
|
||||
case ImageFileTypeTga:
|
||||
case ImageFileTypeZstd:
|
||||
case ImageFileTypeLz4:
|
||||
case ImageFileTypeP12b:
|
||||
case ImageFileTypeExr:
|
||||
{
|
||||
std::ifstream ifs(filename, std::ios_base::in|std::ios_base::binary);
|
||||
return LoadImage(ifs, file_type);
|
||||
}
|
||||
case ImageFileTypePango:
|
||||
return LoadPango(filename);
|
||||
default:
|
||||
throw std::runtime_error("Unsupported image file type, '" + filename + "'");
|
||||
}
|
||||
}
|
||||
|
||||
TypedImage LoadImage(const std::string& filename)
|
||||
{
|
||||
ImageFileType file_type = FileType(filename);
|
||||
return LoadImage( filename, file_type );
|
||||
}
|
||||
|
||||
void SaveImage(const Image<unsigned char>& image, const pangolin::PixelFormat& fmt, std::ostream& out, ImageFileType file_type, bool top_line_first, float quality)
|
||||
{
|
||||
switch (file_type) {
|
||||
case ImageFileTypePng:
|
||||
// map quality [0..100] to PNG compression levels [0..9]
|
||||
return SavePng(image, fmt, out, top_line_first, int(quality*0.09));
|
||||
case ImageFileTypeJpg:
|
||||
return SaveJpg(image, fmt, out, quality);
|
||||
case ImageFileTypePpm:
|
||||
return SavePpm(image,fmt,out,top_line_first);
|
||||
case ImageFileTypeZstd:
|
||||
return SaveZstd(image,fmt,out, quality);
|
||||
case ImageFileTypeLz4:
|
||||
return SaveLz4(image,fmt,out, quality);
|
||||
case ImageFileTypeP12b:
|
||||
return SavePacked12bit(image,fmt,out, quality);
|
||||
default:
|
||||
throw std::runtime_error("Unable to save image file-type through std::istream");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void SaveImage(const Image<unsigned char>& image, const pangolin::PixelFormat& fmt, const std::string& filename, ImageFileType file_type, bool top_line_first, float quality)
|
||||
{
|
||||
switch (file_type) {
|
||||
case ImageFileTypePng:
|
||||
case ImageFileTypeJpg:
|
||||
case ImageFileTypePpm:
|
||||
case ImageFileTypeZstd:
|
||||
case ImageFileTypeLz4:
|
||||
case ImageFileTypeP12b:
|
||||
{
|
||||
std::ofstream ofs(filename, std::ios_base::binary);
|
||||
return SaveImage(image, fmt, ofs, file_type, top_line_first, quality);
|
||||
}
|
||||
case ImageFileTypeExr:
|
||||
return SaveExr(image, fmt, filename, top_line_first);
|
||||
case ImageFileTypePango:
|
||||
return SavePango(image, fmt, filename, top_line_first);
|
||||
default:
|
||||
throw std::runtime_error("Unsupported image file type, '" + filename + "'");
|
||||
}
|
||||
}
|
||||
|
||||
void SaveImage(const Image<unsigned char>& image, const pangolin::PixelFormat& fmt, const std::string& filename, bool top_line_first, float quality)
|
||||
{
|
||||
const std::string ext = FileLowercaseExtention(filename);
|
||||
const ImageFileType file_type = FileTypeExtension(ext);
|
||||
SaveImage(image, fmt, filename,file_type, top_line_first, quality);
|
||||
}
|
||||
|
||||
void SaveImage(const TypedImage& image, const std::string& filename, bool top_line_first, float quality)
|
||||
{
|
||||
SaveImage(image, image.fmt, filename, top_line_first, quality);
|
||||
}
|
||||
|
||||
}
|
||||
188
thirdparty/Pangolin/src/image/image_io_exr.cpp
vendored
Normal file
188
thirdparty/Pangolin/src/image/image_io_exr.cpp
vendored
Normal file
@@ -0,0 +1,188 @@
|
||||
#include <pangolin/platform.h>
|
||||
|
||||
#include <fstream>
|
||||
#include <pangolin/image/typed_image.h>
|
||||
|
||||
#ifdef HAVE_OPENEXR
|
||||
#include <ImfChannelList.h>
|
||||
#include <ImfInputFile.h>
|
||||
#include <ImfOutputFile.h>
|
||||
#include <ImfIO.h>
|
||||
#endif // HAVE_OPENEXR
|
||||
|
||||
namespace pangolin {
|
||||
|
||||
#ifdef HAVE_OPENEXR
|
||||
Imf::PixelType OpenEXRPixelType(int channel_bits)
|
||||
{
|
||||
if( channel_bits == 16 ) {
|
||||
return Imf::PixelType::HALF;
|
||||
}else if( channel_bits == 32 ) {
|
||||
return Imf::PixelType::FLOAT;
|
||||
}else{
|
||||
throw std::runtime_error("Unsupported OpenEXR Pixel Type.");
|
||||
}
|
||||
}
|
||||
|
||||
void SetOpenEXRChannels(Imf::ChannelList& ch, const pangolin::PixelFormat& fmt)
|
||||
{
|
||||
const char* CHANNEL_NAMES[] = {"R","G","B","A"};
|
||||
for(size_t c=0; c < fmt.channels; ++c) {
|
||||
ch.insert( CHANNEL_NAMES[c], Imf::Channel(OpenEXRPixelType(fmt.channel_bits[c])) );
|
||||
}
|
||||
}
|
||||
|
||||
class StdIStream: public Imf::IStream
|
||||
{
|
||||
public:
|
||||
StdIStream (std::istream &is):
|
||||
Imf::IStream ("stream"),
|
||||
_is (&is)
|
||||
{
|
||||
}
|
||||
|
||||
virtual bool read (char c[/*n*/], int n)
|
||||
{
|
||||
if (!*_is)
|
||||
throw std::runtime_error("Unexpected end of file.");
|
||||
_is->read (c, n);
|
||||
if (_is->gcount() < n)
|
||||
{
|
||||
throw std::runtime_error("Early end of file");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual Imf::Int64 tellg ()
|
||||
{
|
||||
return std::streamoff (_is->tellg());
|
||||
}
|
||||
|
||||
virtual void seekg (Imf::Int64 pos)
|
||||
{
|
||||
_is->seekg (pos);
|
||||
}
|
||||
|
||||
virtual void clear ()
|
||||
{
|
||||
_is->clear();
|
||||
}
|
||||
|
||||
private:
|
||||
std::istream * _is;
|
||||
};
|
||||
|
||||
PixelFormat GetPixelFormat(const Imf::Header& header)
|
||||
{
|
||||
const Imf::ChannelList &channels = header.channels();
|
||||
size_t count = 0;
|
||||
for (Imf::ChannelList::ConstIterator i = channels.begin(); i != channels.end(); ++i){
|
||||
const Imf::Channel& channel = i.channel();
|
||||
if (channel.type != Imf::FLOAT){
|
||||
throw std::invalid_argument("Currently, only 32-bit float OpenEXR files are supported.");
|
||||
}
|
||||
count += 1;
|
||||
}
|
||||
|
||||
switch (count) {
|
||||
case 1: return PixelFormatFromString("GRAY32F");
|
||||
case 3: return PixelFormatFromString("RGB96F");
|
||||
case 4: return PixelFormatFromString("RGBA128F");
|
||||
default: throw std::invalid_argument("Currently, only 1, 3 or 4-channel OpenEXR files are supported.");
|
||||
}
|
||||
}
|
||||
|
||||
#endif //HAVE_OPENEXR
|
||||
|
||||
TypedImage LoadExr(std::istream& source)
|
||||
{
|
||||
#ifdef HAVE_OPENEXR
|
||||
StdIStream istream(source);
|
||||
Imf::InputFile file(istream);
|
||||
PANGO_ENSURE(file.isComplete());
|
||||
|
||||
Imath::Box2i dw = file.header().dataWindow();
|
||||
int width = dw.max.x - dw.min.x + 1;
|
||||
int height = dw.max.y - dw.min.y + 1;
|
||||
|
||||
PixelFormat format = GetPixelFormat(file.header());
|
||||
TypedImage img(width, height, format);
|
||||
|
||||
char *imgBase = (char *) img.ptr - (dw.min.x + dw.min.y * width) * sizeof(float) * format.channels;
|
||||
Imf::FrameBuffer fb;
|
||||
|
||||
const Imf::ChannelList &channels = file.header().channels();
|
||||
size_t c = 0;
|
||||
for (Imf::ChannelList::ConstIterator i = channels.begin(); i != channels.end(); ++i){
|
||||
fb.insert(i.name(), Imf::Slice(
|
||||
Imf::FLOAT, imgBase + sizeof(float) * c++,
|
||||
sizeof(float) * format.channels,
|
||||
sizeof(float) * format.channels * size_t(width),
|
||||
1, 1,
|
||||
0.0));
|
||||
}
|
||||
|
||||
file.setFrameBuffer(fb);
|
||||
file.readPixels(dw.min.y, dw.max.y);
|
||||
|
||||
return img;
|
||||
#else
|
||||
PANGOLIN_UNUSED(source);
|
||||
throw std::runtime_error("Rebuild Pangolin for EXR support.");
|
||||
#endif //HAVE_OPENEXR
|
||||
}
|
||||
|
||||
void SaveExr(const Image<unsigned char>& image_in, const pangolin::PixelFormat& fmt, const std::string& filename, bool top_line_first)
|
||||
{
|
||||
#ifdef HAVE_OPENEXR
|
||||
ManagedImage<unsigned char> flip_image;
|
||||
Image<unsigned char> image;
|
||||
|
||||
if(top_line_first) {
|
||||
image = image_in;
|
||||
}else{
|
||||
flip_image.Reinitialise(image_in.pitch,image_in.h);
|
||||
for(size_t y=0; y<image_in.h; ++y) {
|
||||
std::memcpy(flip_image.RowPtr(y), image_in.RowPtr(y), image_in.pitch);
|
||||
}
|
||||
image = flip_image;
|
||||
}
|
||||
|
||||
|
||||
Imf::Header header (image.w, image.h);
|
||||
SetOpenEXRChannels(header.channels(), fmt);
|
||||
|
||||
Imf::OutputFile file (filename.c_str(), header);
|
||||
Imf::FrameBuffer frameBuffer;
|
||||
|
||||
int ch=0;
|
||||
size_t ch_bits = 0;
|
||||
for(Imf::ChannelList::Iterator it = header.channels().begin(); it != header.channels().end(); ++it)
|
||||
{
|
||||
frameBuffer.insert(
|
||||
it.name(),
|
||||
Imf::Slice(
|
||||
it.channel().type,
|
||||
(char*)image.ptr + ch_bits/8,
|
||||
fmt.channel_bits[ch]/8,
|
||||
image.pitch
|
||||
)
|
||||
);
|
||||
|
||||
ch_bits += fmt.channel_bits[ch++];
|
||||
}
|
||||
|
||||
file.setFrameBuffer(frameBuffer);
|
||||
file.writePixels(image.h);
|
||||
|
||||
#else
|
||||
PANGOLIN_UNUSED(image_in);
|
||||
PANGOLIN_UNUSED(fmt);
|
||||
PANGOLIN_UNUSED(filename);
|
||||
PANGOLIN_UNUSED(top_line_first);
|
||||
throw std::runtime_error("EXR Support not enabled. Please rebuild Pangolin.");
|
||||
#endif // HAVE_OPENEXR
|
||||
}
|
||||
|
||||
}
|
||||
263
thirdparty/Pangolin/src/image/image_io_jpg.cpp
vendored
Normal file
263
thirdparty/Pangolin/src/image/image_io_jpg.cpp
vendored
Normal file
@@ -0,0 +1,263 @@
|
||||
#include <algorithm>
|
||||
#include <fstream>
|
||||
|
||||
|
||||
#include <pangolin/platform.h>
|
||||
|
||||
#include <pangolin/image/typed_image.h>
|
||||
|
||||
#ifdef HAVE_JPEG
|
||||
# include <jpeglib.h>
|
||||
# ifdef _WIN_
|
||||
// Undef windows Macro polution from jpeglib.h
|
||||
# undef LoadImage
|
||||
# endif
|
||||
#endif // HAVE_JPEG
|
||||
|
||||
|
||||
// Inspired by https://cs.stanford.edu/~acoates/jpegAndIOS.txt
|
||||
|
||||
namespace pangolin {
|
||||
|
||||
#ifdef HAVE_JPEG
|
||||
|
||||
void error_handler(j_common_ptr cinfo) {
|
||||
char msg[JMSG_LENGTH_MAX];
|
||||
(*(cinfo->err->format_message)) (cinfo, msg);
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
|
||||
const static size_t PANGO_JPEG_BUF_SIZE = 16384;
|
||||
|
||||
struct pango_jpeg_source_mgr {
|
||||
struct jpeg_source_mgr pub;
|
||||
std::istream* is;
|
||||
JOCTET* buffer;
|
||||
};
|
||||
|
||||
static void pango_jpeg_init_source(j_decompress_ptr /*cinfo*/) {
|
||||
}
|
||||
|
||||
static boolean pango_jpeg_fill_input_buffer(j_decompress_ptr cinfo) {
|
||||
pango_jpeg_source_mgr* src = (pango_jpeg_source_mgr*)cinfo->src;
|
||||
|
||||
src->is->read((char*)src->buffer, PANGO_JPEG_BUF_SIZE);
|
||||
size_t bytes = src->is->gcount();
|
||||
if (bytes == 0) {
|
||||
/* Insert a fake EOI marker */
|
||||
src->buffer[0] = (JOCTET) 0xFF;
|
||||
src->buffer[1] = (JOCTET) JPEG_EOI;
|
||||
bytes = 2;
|
||||
}
|
||||
src->pub.next_input_byte = src->buffer;
|
||||
src->pub.bytes_in_buffer = bytes;
|
||||
return TRUE;
|
||||
}
|
||||
static void pango_jpeg_skip_input_data(j_decompress_ptr cinfo, long num_bytes) {
|
||||
pango_jpeg_source_mgr* src = (pango_jpeg_source_mgr*)cinfo->src;
|
||||
if (num_bytes > 0) {
|
||||
while (num_bytes > (long)src->pub.bytes_in_buffer) {
|
||||
num_bytes -= (long)src->pub.bytes_in_buffer;
|
||||
pango_jpeg_fill_input_buffer(cinfo);
|
||||
}
|
||||
src->pub.next_input_byte += num_bytes;
|
||||
src->pub.bytes_in_buffer -= num_bytes;
|
||||
}
|
||||
}
|
||||
static void pango_jpeg_term_source(j_decompress_ptr cinfo) {
|
||||
// must seek backward so that future reads will start at correct place.
|
||||
pango_jpeg_source_mgr* src = (pango_jpeg_source_mgr*)cinfo->src;
|
||||
src->is->clear();
|
||||
src->is->seekg( src->is->tellg() - (std::streampos)src->pub.bytes_in_buffer );
|
||||
}
|
||||
|
||||
static void pango_jpeg_set_source_mgr(j_decompress_ptr cinfo, std::istream& is) {
|
||||
pango_jpeg_source_mgr* src = nullptr;
|
||||
|
||||
if (cinfo->src == 0)
|
||||
{
|
||||
cinfo->src = (struct jpeg_source_mgr *)(*cinfo->mem->alloc_small)
|
||||
((j_common_ptr) cinfo, JPOOL_PERMANENT, sizeof(pango_jpeg_source_mgr));
|
||||
|
||||
src = (pango_jpeg_source_mgr*) cinfo->src;
|
||||
src->buffer = (JOCTET *)(*cinfo->mem->alloc_small)
|
||||
((j_common_ptr) cinfo, JPOOL_PERMANENT, PANGO_JPEG_BUF_SIZE*sizeof(JOCTET));
|
||||
}else{
|
||||
src = (pango_jpeg_source_mgr*) cinfo->src;
|
||||
}
|
||||
|
||||
src->is = &is;
|
||||
src->pub.init_source = pango_jpeg_init_source;
|
||||
src->pub.fill_input_buffer = pango_jpeg_fill_input_buffer;
|
||||
src->pub.skip_input_data = pango_jpeg_skip_input_data;
|
||||
src->pub.resync_to_restart = jpeg_resync_to_restart; /* use default method */
|
||||
src->pub.term_source = pango_jpeg_term_source;
|
||||
src->pub.bytes_in_buffer = 0;
|
||||
src->pub.next_input_byte = 0;
|
||||
}
|
||||
|
||||
struct pango_jpeg_destination_mgr {
|
||||
struct jpeg_destination_mgr pub; /* public fields */
|
||||
std::ostream* os; /* target stream */
|
||||
JOCTET * buffer; /* start of buffer */
|
||||
};
|
||||
|
||||
void pango_jpeg_init_destination (j_compress_ptr cinfo) {
|
||||
pango_jpeg_destination_mgr* dest = (pango_jpeg_destination_mgr*) cinfo->dest;
|
||||
dest->buffer = (JOCTET *)(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
|
||||
PANGO_JPEG_BUF_SIZE * sizeof(JOCTET));
|
||||
dest->pub.next_output_byte = dest->buffer;
|
||||
dest->pub.free_in_buffer = PANGO_JPEG_BUF_SIZE;
|
||||
}
|
||||
|
||||
boolean pango_jpeg_empty_output_buffer(j_compress_ptr cinfo) {
|
||||
pango_jpeg_destination_mgr* dest = (pango_jpeg_destination_mgr*)cinfo->dest;
|
||||
|
||||
dest->os->write((const char*)dest->buffer, PANGO_JPEG_BUF_SIZE);
|
||||
|
||||
if (dest->os->fail()) {
|
||||
throw std::runtime_error("Couldn't write entire jpeg buffer to stream.");
|
||||
}
|
||||
|
||||
dest->pub.next_output_byte = dest->buffer;
|
||||
dest->pub.free_in_buffer = PANGO_JPEG_BUF_SIZE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void pango_jpeg_term_destination (j_compress_ptr cinfo) {
|
||||
pango_jpeg_destination_mgr* dest = (pango_jpeg_destination_mgr*) cinfo->dest;
|
||||
size_t datacount = PANGO_JPEG_BUF_SIZE - dest->pub.free_in_buffer;
|
||||
|
||||
/* Write any data remaining in the buffer */
|
||||
if (datacount > 0) {
|
||||
dest->os->write((const char*)dest->buffer, datacount);
|
||||
if (dest->os->fail()) {
|
||||
throw std::runtime_error("Couldn't write remaining jpeg data to stream.");
|
||||
}
|
||||
}
|
||||
dest->os->flush();
|
||||
}
|
||||
|
||||
void pango_jpeg_set_dest_mgr(j_compress_ptr cinfo, std::ostream& os) {
|
||||
pango_jpeg_destination_mgr* dest;
|
||||
|
||||
if (cinfo->dest == NULL) { /* first time for this JPEG object? */
|
||||
cinfo->dest = (struct jpeg_destination_mgr *)
|
||||
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
|
||||
sizeof(pango_jpeg_destination_mgr));
|
||||
}
|
||||
|
||||
dest = (pango_jpeg_destination_mgr*)cinfo->dest;
|
||||
dest->pub.init_destination = pango_jpeg_init_destination;
|
||||
dest->pub.empty_output_buffer = pango_jpeg_empty_output_buffer;
|
||||
dest->pub.term_destination = pango_jpeg_term_destination;
|
||||
dest->os = &os;
|
||||
}
|
||||
|
||||
#endif // HAVE_JPEG
|
||||
|
||||
TypedImage LoadJpg(std::istream& is) {
|
||||
#ifdef HAVE_JPEG
|
||||
TypedImage image;
|
||||
|
||||
struct jpeg_decompress_struct cinfo;
|
||||
struct jpeg_error_mgr jerr;
|
||||
|
||||
// Setup decompression structure
|
||||
cinfo.err = jpeg_std_error(&jerr);
|
||||
jerr.error_exit = error_handler;
|
||||
jpeg_create_decompress(&cinfo);
|
||||
pango_jpeg_set_source_mgr(&cinfo, is);
|
||||
|
||||
// read info from header.
|
||||
int r = jpeg_read_header(&cinfo, TRUE);
|
||||
if (r != JPEG_HEADER_OK) {
|
||||
throw std::runtime_error("Failed to read JPEG header.");
|
||||
} else if (cinfo.num_components != 3 && cinfo.num_components != 1) {
|
||||
throw std::runtime_error("Unsupported number of color components");
|
||||
} else {
|
||||
jpeg_start_decompress(&cinfo);
|
||||
// resize storage if necessary
|
||||
PixelFormat fmt = PixelFormatFromString(cinfo.output_components == 3 ? "RGB24" : "GRAY8");
|
||||
image.Reinitialise(cinfo.output_width, cinfo.output_height, fmt);
|
||||
JSAMPARRAY imageBuffer = (*cinfo.mem->alloc_sarray)((j_common_ptr)&cinfo, JPOOL_IMAGE,
|
||||
cinfo.output_width*cinfo.output_components, 1);
|
||||
for (size_t y = 0; y < cinfo.output_height; y++) {
|
||||
jpeg_read_scanlines(&cinfo, imageBuffer, 1);
|
||||
uint8_t* dstRow = (uint8_t*)image.RowPtr(y);
|
||||
memcpy(dstRow, imageBuffer[0], cinfo.output_width*cinfo.output_components);
|
||||
}
|
||||
jpeg_finish_decompress(&cinfo);
|
||||
}
|
||||
|
||||
// clean up.
|
||||
jpeg_destroy_decompress(&cinfo);
|
||||
|
||||
return image;
|
||||
#else
|
||||
PANGOLIN_UNUSED(is);
|
||||
throw std::runtime_error("Rebuild Pangolin for JPEG support.");
|
||||
#endif // HAVE_JPEG
|
||||
|
||||
}
|
||||
|
||||
TypedImage LoadJpg(const std::string& filename) {
|
||||
std::ifstream f(filename);
|
||||
return LoadJpg(f);
|
||||
}
|
||||
|
||||
void SaveJpg(const Image<unsigned char>& img, const PixelFormat& fmt, std::ostream& os, float quality) {
|
||||
#ifdef HAVE_JPEG
|
||||
const int iquality = (int)std::max(std::min(quality, 100.0f),0.0f);
|
||||
|
||||
struct jpeg_compress_struct cinfo;
|
||||
struct jpeg_error_mgr jerr;
|
||||
|
||||
if (fmt.channels != 1 && fmt.channels != 3) {
|
||||
throw std::runtime_error("Unsupported number of image channels.");
|
||||
}
|
||||
if (fmt.bpp != 8 && fmt.bpp != 24) {
|
||||
throw std::runtime_error("Unsupported image depth.");
|
||||
}
|
||||
|
||||
// set up compression structure
|
||||
cinfo.err = jpeg_std_error(&jerr);
|
||||
jpeg_create_compress(&cinfo);
|
||||
pango_jpeg_set_dest_mgr(&cinfo, os);
|
||||
|
||||
cinfo.image_width = img.w;
|
||||
cinfo.image_height = img.h;
|
||||
cinfo.input_components = fmt.channels;
|
||||
if (fmt.channels == 3) {
|
||||
cinfo.in_color_space = JCS_RGB;
|
||||
} else {
|
||||
cinfo.in_color_space = JCS_GRAYSCALE;
|
||||
}
|
||||
|
||||
jpeg_set_defaults(&cinfo);
|
||||
jpeg_set_quality(&cinfo, iquality, (boolean)true);
|
||||
jpeg_start_compress(&cinfo, (boolean)true);
|
||||
|
||||
JSAMPROW row;
|
||||
while (cinfo.next_scanline < cinfo.image_height) {
|
||||
row = (JSAMPROW)((char*)img.RowPtr(cinfo.next_scanline));
|
||||
jpeg_write_scanlines(&cinfo, &row, 1);
|
||||
}
|
||||
|
||||
jpeg_finish_compress(&cinfo);
|
||||
jpeg_destroy_compress(&cinfo);
|
||||
#else
|
||||
PANGOLIN_UNUSED(img);
|
||||
PANGOLIN_UNUSED(fmt);
|
||||
PANGOLIN_UNUSED(os);
|
||||
PANGOLIN_UNUSED(quality);
|
||||
throw std::runtime_error("Rebuild Pangolin for JPEG support.");
|
||||
#endif // HAVE_JPEG
|
||||
}
|
||||
|
||||
void SaveJpg(const Image<unsigned char>& img, const PixelFormat& fmt, const std::string& filename, float quality) {
|
||||
std::ofstream f(filename);
|
||||
SaveJpg(img, fmt, f, quality);
|
||||
}
|
||||
|
||||
}
|
||||
86
thirdparty/Pangolin/src/image/image_io_lz4.cpp
vendored
Normal file
86
thirdparty/Pangolin/src/image/image_io_lz4.cpp
vendored
Normal file
@@ -0,0 +1,86 @@
|
||||
#include <fstream>
|
||||
#include <memory>
|
||||
|
||||
#include <pangolin/image/typed_image.h>
|
||||
|
||||
#ifdef HAVE_LZ4
|
||||
# include <lz4.h>
|
||||
#endif
|
||||
|
||||
namespace pangolin {
|
||||
|
||||
#pragma pack(push, 1)
|
||||
struct lz4_image_header
|
||||
{
|
||||
char magic[3];
|
||||
char fmt[16];
|
||||
size_t w, h;
|
||||
int64_t compressed_size;
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
void SaveLz4(const Image<unsigned char>& image, const pangolin::PixelFormat& fmt, std::ostream& out, int compression_level)
|
||||
{
|
||||
#ifdef HAVE_LZ4
|
||||
const int64_t src_size = image.SizeBytes();
|
||||
const int64_t max_dst_size = LZ4_compressBound(src_size);
|
||||
std::unique_ptr<char[]> output_buffer(new char[max_dst_size]);
|
||||
|
||||
// Same as LZ4_compress_default(), but allows to select an "acceleration" factor.
|
||||
// The larger the acceleration value, the faster the algorithm, but also the lesser the compression.
|
||||
// It's a trade-off. It can be fine tuned, with each successive value providing roughly +~3% to speed.
|
||||
// An acceleration value of "1" is the same as regular LZ4_compress_default()
|
||||
// Values <= 0 will be replaced by ACCELERATION_DEFAULT (see lz4.c), which is 1.
|
||||
const int64_t compressed_data_size = LZ4_compress_fast((char*)image.ptr, output_buffer.get(), src_size, max_dst_size, compression_level);
|
||||
|
||||
if (compressed_data_size < 0)
|
||||
throw std::runtime_error("A negative result from LZ4_compress_default indicates a failure trying to compress the data.");
|
||||
if (compressed_data_size == 0)
|
||||
throw std::runtime_error("A result of 0 for LZ4 means compression worked, but was stopped because the destination buffer couldn't hold all the information.");
|
||||
|
||||
lz4_image_header header;
|
||||
strncpy(header.magic,"LZ4",3);
|
||||
strncpy(header.fmt, fmt.format.c_str(), sizeof(header.fmt));
|
||||
header.w = image.w;
|
||||
header.h = image.h;
|
||||
header.compressed_size = compressed_data_size;
|
||||
out.write((char*)&header, sizeof(header));
|
||||
|
||||
out.write(output_buffer.get(), compressed_data_size);
|
||||
|
||||
#else
|
||||
PANGOLIN_UNUSED(image);
|
||||
PANGOLIN_UNUSED(fmt);
|
||||
PANGOLIN_UNUSED(out);
|
||||
PANGOLIN_UNUSED(compression_level);
|
||||
throw std::runtime_error("Rebuild Pangolin for LZ4 support.");
|
||||
#endif // HAVE_LZ4
|
||||
}
|
||||
|
||||
TypedImage LoadLz4(std::istream& in)
|
||||
{
|
||||
#ifdef HAVE_LZ4
|
||||
// Read in header, uncompressed
|
||||
lz4_image_header header;
|
||||
in.read( (char*)&header, sizeof(header));
|
||||
|
||||
TypedImage img(header.w, header.h, PixelFormatFromString(header.fmt));
|
||||
std::unique_ptr<char[]> input_buffer(new char[header.compressed_size]);
|
||||
|
||||
in.read(input_buffer.get(), header.compressed_size);
|
||||
const int decompressed_size = LZ4_decompress_safe(input_buffer.get(), (char*)img.ptr, header.compressed_size, img.SizeBytes());
|
||||
if (decompressed_size < 0)
|
||||
throw std::runtime_error(FormatString("A negative result from LZ4_decompress_safe indicates a failure trying to decompress the data. See exit code (%) for value returned.", decompressed_size));
|
||||
if (decompressed_size == 0)
|
||||
throw std::runtime_error("I'm not sure this function can ever return 0. Documentation in lz4.h doesn't indicate so.");
|
||||
if (decompressed_size != (int)img.SizeBytes())
|
||||
throw std::runtime_error(FormatString("decompressed size % is not equal to predicted size %", decompressed_size, img.SizeBytes()));
|
||||
|
||||
return img;
|
||||
#else
|
||||
PANGOLIN_UNUSED(in);
|
||||
throw std::runtime_error("Rebuild Pangolin for LZ4 support.");
|
||||
#endif // HAVE_LZ4
|
||||
}
|
||||
|
||||
}
|
||||
85
thirdparty/Pangolin/src/image/image_io_packed12bit.cpp
vendored
Normal file
85
thirdparty/Pangolin/src/image/image_io_packed12bit.cpp
vendored
Normal file
@@ -0,0 +1,85 @@
|
||||
#include <fstream>
|
||||
#include <memory>
|
||||
|
||||
#include <pangolin/image/typed_image.h>
|
||||
|
||||
namespace pangolin {
|
||||
|
||||
#pragma pack(push, 1)
|
||||
struct packed12bit_image_header
|
||||
{
|
||||
char magic[4];
|
||||
char fmt[16];
|
||||
size_t w, h;
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
void SavePacked12bit(const Image<uint8_t>& image, const pangolin::PixelFormat& fmt, std::ostream& out, int /*compression_level*/)
|
||||
{
|
||||
|
||||
if (fmt.bpp != 16) {
|
||||
throw std::runtime_error("packed12bit currently only supported with 16bit input image");
|
||||
}
|
||||
|
||||
const size_t dest_pitch = (image.w*12)/ 8 + ((image.w*12) % 8 > 0? 1 : 0);
|
||||
const size_t dest_size = image.h*dest_pitch;
|
||||
std::unique_ptr<uint8_t[]> output_buffer(new uint8_t[dest_size]);
|
||||
|
||||
for(size_t r=0; r<image.h; ++r) {
|
||||
uint8_t* pout = output_buffer.get() + r*dest_pitch;
|
||||
uint16_t* pin = (uint16_t*)(image.ptr + r*image.pitch);
|
||||
const uint16_t* pin_end = (uint16_t*)(image.ptr + (r+1)*image.pitch);
|
||||
while(pin < pin_end) {
|
||||
uint32_t val = (*(pin++) & 0x00000FFF);
|
||||
val |= uint32_t(*(pin++) & 0x00000FFF) << 12;
|
||||
*(pout++) = uint8_t( val & 0x000000FF);
|
||||
*(pout++) = uint8_t((val & 0x0000FF00) >> 8);
|
||||
*(pout++) = uint8_t((val & 0x00FF0000) >> 16);
|
||||
}
|
||||
}
|
||||
|
||||
packed12bit_image_header header;
|
||||
strncpy(header.magic,"P12B",4);
|
||||
strncpy(header.fmt, fmt.format.c_str(), sizeof(header.fmt));
|
||||
header.w = image.w;
|
||||
header.h = image.h;
|
||||
out.write((char*)&header, sizeof(header));
|
||||
out.write((char*)output_buffer.get(), dest_size);
|
||||
|
||||
}
|
||||
|
||||
TypedImage LoadPacked12bit(std::istream& in)
|
||||
{
|
||||
// Read in header, uncompressed
|
||||
packed12bit_image_header header;
|
||||
in.read((char*)&header, sizeof(header));
|
||||
|
||||
TypedImage img(header.w, header.h, PixelFormatFromString(header.fmt));
|
||||
|
||||
if (img.fmt.bpp != 16) {
|
||||
throw std::runtime_error("packed12bit currently only supported with 16bit input image");
|
||||
}
|
||||
|
||||
const size_t input_pitch = (img.w*12)/ 8 + ((img.w*12) % 8 > 0? 1 : 0);
|
||||
const size_t input_size = img.h*input_pitch;
|
||||
std::unique_ptr<uint8_t[]> input_buffer(new uint8_t[input_size]);
|
||||
|
||||
in.read((char*)input_buffer.get(), input_size);
|
||||
|
||||
for(size_t r=0; r<img.h; ++r) {
|
||||
uint16_t* pout = (uint16_t*)(img.ptr + r*img.pitch);
|
||||
uint8_t* pin = input_buffer.get() + r*input_pitch;
|
||||
const uint8_t* pin_end = input_buffer.get() + (r+1)*input_pitch;
|
||||
while(pin < pin_end) {
|
||||
uint32_t val = *(pin++);
|
||||
val |= uint32_t(*(pin++)) << 8;
|
||||
val |= uint32_t(*(pin++)) << 16;
|
||||
*(pout++) = uint16_t( val & 0x000FFF);
|
||||
*(pout++) = uint16_t((val & 0xFFF000) >> 12);
|
||||
}
|
||||
}
|
||||
|
||||
return img;
|
||||
}
|
||||
|
||||
}
|
||||
62
thirdparty/Pangolin/src/image/image_io_pango.cpp
vendored
Normal file
62
thirdparty/Pangolin/src/image/image_io_pango.cpp
vendored
Normal file
@@ -0,0 +1,62 @@
|
||||
#include <pangolin/platform.h>
|
||||
|
||||
#include <pangolin/image/typed_image.h>
|
||||
|
||||
#ifdef BUILD_PANGOLIN_VIDEO
|
||||
# include <pangolin/video/drivers/pango.h>
|
||||
# include <pangolin/video/drivers/pango_video_output.h>
|
||||
#endif
|
||||
|
||||
namespace pangolin {
|
||||
|
||||
TypedImage LoadPango(const std::string& uri)
|
||||
{
|
||||
PANGOLIN_UNUSED(uri);
|
||||
|
||||
#ifdef BUILD_PANGOLIN_VIDEO
|
||||
std::unique_ptr<VideoInterface> video = OpenVideo(uri);
|
||||
if(!video || video->Streams().size() != 1) {
|
||||
throw pangolin::VideoException("Wrong number of streams: exactly one expected.");
|
||||
}
|
||||
|
||||
std::unique_ptr<uint8_t[]> buffer( new uint8_t[video->SizeBytes()] );
|
||||
const StreamInfo& stream_info = video->Streams()[0];
|
||||
|
||||
// Grab first image from video
|
||||
if(!video->GrabNext(buffer.get(), true)) {
|
||||
throw pangolin::VideoException("Failed to grab image from stream");
|
||||
}
|
||||
|
||||
// Allocate storage for user image to return
|
||||
TypedImage image(stream_info.Width(), stream_info.Height(), stream_info.PixFormat());
|
||||
|
||||
// Copy image data into user buffer.
|
||||
const Image<unsigned char> img = stream_info.StreamImage(buffer.get());
|
||||
PANGO_ENSURE(image.pitch <= img.pitch);
|
||||
for(size_t y=0; y < image.h; ++y) {
|
||||
std::memcpy(image.RowPtr(y), img.RowPtr(y), image.pitch);
|
||||
}
|
||||
|
||||
return image;
|
||||
#else
|
||||
throw std::runtime_error("Video Support not enabled. Please rebuild Pangolin.");
|
||||
#endif
|
||||
}
|
||||
|
||||
void SavePango(const Image<unsigned char>& image, const pangolin::PixelFormat& fmt, const std::string& uri, bool /*top_line_first*/)
|
||||
{
|
||||
PANGOLIN_UNUSED(image);
|
||||
PANGOLIN_UNUSED(fmt);
|
||||
PANGOLIN_UNUSED(uri);
|
||||
|
||||
#ifdef BUILD_PANGOLIN_VIDEO
|
||||
std::unique_ptr<VideoOutputInterface> video = OpenVideoOutput(uri);
|
||||
StreamInfo stream(fmt, image.w, image.h, image.pitch);
|
||||
video->SetStreams({stream});
|
||||
video->WriteStreams(image.ptr);
|
||||
#else
|
||||
throw std::runtime_error("Video Support not enabled. Please rebuild Pangolin.");
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
234
thirdparty/Pangolin/src/image/image_io_png.cpp
vendored
Normal file
234
thirdparty/Pangolin/src/image/image_io_png.cpp
vendored
Normal file
@@ -0,0 +1,234 @@
|
||||
#include <pangolin/platform.h>
|
||||
|
||||
#include <fstream>
|
||||
#include <pangolin/image/image_io.h>
|
||||
#include <vector>
|
||||
|
||||
#ifdef HAVE_PNG
|
||||
# include <png.h>
|
||||
#endif // HAVE_PNG
|
||||
|
||||
namespace pangolin {
|
||||
|
||||
#ifdef HAVE_PNG
|
||||
|
||||
PixelFormat PngFormat(png_structp png_ptr, png_infop info_ptr )
|
||||
{
|
||||
const png_byte colour = png_get_color_type(png_ptr, info_ptr);
|
||||
const png_byte depth = png_get_bit_depth(png_ptr, info_ptr);
|
||||
|
||||
if( depth == 8 ) {
|
||||
if( colour == PNG_COLOR_MASK_COLOR ) {
|
||||
return PixelFormatFromString("RGB24");
|
||||
} else if( colour == (PNG_COLOR_MASK_COLOR | PNG_COLOR_MASK_ALPHA) ) {
|
||||
return PixelFormatFromString("RGBA32");
|
||||
} else if( colour == PNG_COLOR_MASK_ALPHA ) {
|
||||
return PixelFormatFromString("Y400A");
|
||||
} else {
|
||||
return PixelFormatFromString("GRAY8");
|
||||
}
|
||||
}else if( depth == 16 ) {
|
||||
if( colour == 0 ) {
|
||||
return PixelFormatFromString("GRAY16LE");
|
||||
}
|
||||
}
|
||||
|
||||
throw std::runtime_error("Unsupported PNG format");
|
||||
}
|
||||
|
||||
void PNGAPI PngWarningsCallback(png_structp /*png_ptr*/, png_const_charp /*warning_message*/)
|
||||
{
|
||||
// Override default behaviour - don't do anything.
|
||||
}
|
||||
|
||||
#define PNGSIGSIZE 8
|
||||
bool pango_png_validate(std::istream& source)
|
||||
{
|
||||
png_byte pngsig[PNGSIGSIZE];
|
||||
source.read((char*)pngsig, PNGSIGSIZE);
|
||||
return source.good() && png_sig_cmp(pngsig, 0, PNGSIGSIZE) == 0;
|
||||
}
|
||||
|
||||
void pango_png_stream_read(png_structp pngPtr, png_bytep data, png_size_t length) {
|
||||
std::istream* s = (std::istream*)png_get_io_ptr(pngPtr);
|
||||
PANGO_ASSERT(s);
|
||||
s->read((char*)data, length);
|
||||
}
|
||||
|
||||
void pango_png_stream_write(png_structp pngPtr, png_bytep data, png_size_t length) {
|
||||
std::ostream* s = (std::ostream*)png_get_io_ptr(pngPtr);
|
||||
PANGO_ASSERT(s);
|
||||
s->write((char*)data, length);
|
||||
}
|
||||
|
||||
void pango_png_stream_write_flush(png_structp pngPtr)
|
||||
{
|
||||
std::ostream* s = (std::ostream*)png_get_io_ptr(pngPtr);
|
||||
PANGO_ASSERT(s);
|
||||
s->flush();
|
||||
}
|
||||
|
||||
#endif // HAVE_PNG
|
||||
|
||||
|
||||
TypedImage LoadPng(std::istream& source)
|
||||
{
|
||||
#ifdef HAVE_PNG
|
||||
//so First, we validate our stream with the validate function I just mentioned
|
||||
if (!pango_png_validate(source)) {
|
||||
throw std::runtime_error("Not valid PNG header");
|
||||
}
|
||||
|
||||
//set up initial png structs
|
||||
png_structp png_ptr = png_create_read_struct( PNG_LIBPNG_VER_STRING, (png_voidp)NULL, NULL, &PngWarningsCallback);
|
||||
if (!png_ptr) {
|
||||
throw std::runtime_error( "PNG Init error 1" );
|
||||
}
|
||||
|
||||
png_infop info_ptr = png_create_info_struct(png_ptr);
|
||||
if (!info_ptr) {
|
||||
png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
|
||||
throw std::runtime_error( "PNG Init error 2" );
|
||||
}
|
||||
|
||||
png_infop end_info = png_create_info_struct(png_ptr);
|
||||
if (!end_info) {
|
||||
png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
|
||||
throw std::runtime_error( "PNG Init error 3" );
|
||||
}
|
||||
|
||||
png_set_read_fn(png_ptr,(png_voidp)&source, pango_png_stream_read);
|
||||
|
||||
png_set_sig_bytes(png_ptr, PNGSIGSIZE);
|
||||
|
||||
// Setup transformation options
|
||||
if( png_get_bit_depth(png_ptr, info_ptr) == 1) {
|
||||
//Unpack bools to bytes to ease loading.
|
||||
png_set_packing(png_ptr);
|
||||
} else if( png_get_bit_depth(png_ptr, info_ptr) < 8) {
|
||||
//Expand nonbool colour depths up to 8bpp
|
||||
png_set_expand_gray_1_2_4_to_8(png_ptr);
|
||||
}
|
||||
|
||||
//Get rid of palette, by transforming it to RGB
|
||||
if(png_get_color_type(png_ptr, info_ptr) == PNG_COLOR_TYPE_PALETTE) {
|
||||
png_set_palette_to_rgb(png_ptr);
|
||||
}
|
||||
|
||||
//read the file
|
||||
png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_SWAP_ENDIAN, NULL);
|
||||
|
||||
if( png_get_interlace_type(png_ptr,info_ptr) != PNG_INTERLACE_NONE) {
|
||||
throw std::runtime_error( "Interlace not yet supported" );
|
||||
}
|
||||
|
||||
const size_t w = png_get_image_width(png_ptr,info_ptr);
|
||||
const size_t h = png_get_image_height(png_ptr,info_ptr);
|
||||
const size_t pitch = png_get_rowbytes(png_ptr, info_ptr);
|
||||
|
||||
TypedImage img(w, h, PngFormat(png_ptr, info_ptr), pitch);
|
||||
|
||||
png_bytepp rows = png_get_rows(png_ptr, info_ptr);
|
||||
for( unsigned int r = 0; r < h; r++) {
|
||||
memcpy( img.ptr + pitch*r, rows[r], pitch );
|
||||
}
|
||||
png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
|
||||
|
||||
return img;
|
||||
#else
|
||||
PANGOLIN_UNUSED(source);
|
||||
throw std::runtime_error("Rebuild Pangolin for PNG support.");
|
||||
#endif // HAVE_PNG
|
||||
}
|
||||
|
||||
TypedImage LoadPng(const std::string& filename)
|
||||
{
|
||||
std::ifstream f(filename);
|
||||
return LoadPng(f);
|
||||
}
|
||||
|
||||
void SavePng(const Image<unsigned char>& image, const pangolin::PixelFormat& fmt, std::ostream& stream, bool top_line_first, int zlib_compression_level)
|
||||
{
|
||||
#ifdef HAVE_PNG
|
||||
// Check image has supported bit depth
|
||||
for(unsigned int i=1; i < fmt.channels; ++i) {
|
||||
if( fmt.channel_bits[i] != fmt.channel_bits[0] ) {
|
||||
throw std::runtime_error("PNG Saving only supported for images where each channel has the same bit depth.");
|
||||
}
|
||||
}
|
||||
|
||||
png_structp png_ptr;
|
||||
png_infop info_ptr;
|
||||
|
||||
// Initialize write structure
|
||||
png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
|
||||
if (png_ptr == NULL) {
|
||||
throw std::runtime_error( "PNG Error: Could not allocate write struct." );
|
||||
}
|
||||
|
||||
// Initialize info structure
|
||||
info_ptr = png_create_info_struct(png_ptr);
|
||||
if (info_ptr == NULL) {
|
||||
png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
|
||||
throw std::runtime_error( "PNG Error: Could not allocate info struct." );
|
||||
}
|
||||
|
||||
// Setup Exception handling
|
||||
if (setjmp(png_jmpbuf(png_ptr))) {
|
||||
png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1);
|
||||
png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
|
||||
throw std::runtime_error( "PNG Error: Error during png creation." );
|
||||
}
|
||||
|
||||
png_set_compression_level(png_ptr, zlib_compression_level);
|
||||
|
||||
png_set_write_fn(png_ptr,(png_voidp)&stream, pango_png_stream_write, pango_png_stream_write_flush);
|
||||
|
||||
const int bit_depth = fmt.channel_bits[0];
|
||||
|
||||
int colour_type;
|
||||
switch (fmt.channels) {
|
||||
case 1: colour_type = PNG_COLOR_TYPE_GRAY; break;
|
||||
case 2: colour_type = PNG_COLOR_TYPE_GRAY_ALPHA; break;
|
||||
case 3: colour_type = PNG_COLOR_TYPE_RGB; break;
|
||||
case 4: colour_type = PNG_COLOR_TYPE_RGBA; break;
|
||||
default:
|
||||
throw std::runtime_error( "PNG Error: unexpected image channel number");
|
||||
}
|
||||
|
||||
// Write header
|
||||
png_set_IHDR(
|
||||
png_ptr, info_ptr, (png_uint_32)image.w, (png_uint_32)image.h, bit_depth, colour_type,
|
||||
PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT
|
||||
);
|
||||
|
||||
// Setup rows to write:
|
||||
std::vector<png_bytep> rows(image.h);
|
||||
if(top_line_first) {
|
||||
for (unsigned int y = 0; y< image.h; y++) {
|
||||
rows[y] = image.ptr + y*image.pitch;
|
||||
}
|
||||
}else{
|
||||
for (unsigned int y = 0; y< image.h; y++) {
|
||||
rows[y] = image.ptr + (image.h-1-y)*image.pitch;
|
||||
}
|
||||
}
|
||||
png_set_rows(png_ptr,info_ptr, &rows[0]);
|
||||
|
||||
// Write image data: switch to little-endian byte order, to match host.
|
||||
png_write_png(png_ptr,info_ptr, PNG_TRANSFORM_SWAP_ENDIAN, 0);
|
||||
|
||||
// Free resources
|
||||
png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1);
|
||||
png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
|
||||
#else
|
||||
PANGOLIN_UNUSED(image);
|
||||
PANGOLIN_UNUSED(fmt);
|
||||
PANGOLIN_UNUSED(stream);
|
||||
PANGOLIN_UNUSED(top_line_first);
|
||||
PANGOLIN_UNUSED(zlib_compression_level);
|
||||
throw std::runtime_error("Rebuild Pangolin for PNG support.");
|
||||
#endif // HAVE_PNG
|
||||
}
|
||||
|
||||
}
|
||||
104
thirdparty/Pangolin/src/image/image_io_ppm.cpp
vendored
Normal file
104
thirdparty/Pangolin/src/image/image_io_ppm.cpp
vendored
Normal file
@@ -0,0 +1,104 @@
|
||||
#include <fstream>
|
||||
#include <pangolin/image/typed_image.h>
|
||||
|
||||
namespace pangolin {
|
||||
|
||||
PixelFormat PpmFormat(const std::string& strType, int num_colours)
|
||||
{
|
||||
if(strType == "P5") {
|
||||
if(num_colours < 256) {
|
||||
return PixelFormatFromString("GRAY8");
|
||||
} else {
|
||||
return PixelFormatFromString("GRAY16LE");
|
||||
}
|
||||
}else if(strType == "P6") {
|
||||
return PixelFormatFromString("RGB24");
|
||||
}else{
|
||||
throw std::runtime_error("Unsupported PPM/PGM format");
|
||||
}
|
||||
}
|
||||
|
||||
void PpmConsumeWhitespaceAndComments(std::istream& in)
|
||||
{
|
||||
// TODO: Make a little more general / more efficient
|
||||
while( in.peek() == ' ' ) in.get();
|
||||
while( in.peek() == '\n' ) in.get();
|
||||
while( in.peek() == '#' ) in.ignore(4096, '\n');
|
||||
}
|
||||
|
||||
TypedImage LoadPpm(std::istream& in)
|
||||
{
|
||||
// Parse header
|
||||
std::string ppm_type = "";
|
||||
int num_colors = 0;
|
||||
int w = 0;
|
||||
int h = 0;
|
||||
|
||||
in >> ppm_type;
|
||||
PpmConsumeWhitespaceAndComments(in);
|
||||
in >> w;
|
||||
PpmConsumeWhitespaceAndComments(in);
|
||||
in >> h;
|
||||
PpmConsumeWhitespaceAndComments(in);
|
||||
in >> num_colors;
|
||||
in.ignore(1,'\n');
|
||||
|
||||
if(!in.fail() && w > 0 && h > 0) {
|
||||
TypedImage img(w, h, PpmFormat(ppm_type, num_colors) );
|
||||
|
||||
// Read in data
|
||||
for(size_t r=0; r<img.h; ++r) {
|
||||
in.read( (char*)img.ptr + r*img.pitch, img.pitch );
|
||||
}
|
||||
if(!in.fail()) {
|
||||
return img;
|
||||
}
|
||||
}
|
||||
|
||||
throw std::runtime_error("Unable to load PPM file.");
|
||||
}
|
||||
|
||||
void SavePpm(const Image<unsigned char>& image, const pangolin::PixelFormat& fmt, std::ostream& out, bool top_line_first)
|
||||
{
|
||||
// Setup header variables
|
||||
std::string ppm_type = "";
|
||||
int num_colors = 0;
|
||||
int w = (int)image.w;
|
||||
int h = (int)image.h;
|
||||
|
||||
if(fmt.format == "GRAY8") {
|
||||
ppm_type = "P5";
|
||||
num_colors = 255;
|
||||
}else if(fmt.format == "GRAY16LE") {
|
||||
ppm_type = "P5";
|
||||
num_colors = 65535;
|
||||
}else if(fmt.format == "RGB24") {
|
||||
ppm_type = "P6";
|
||||
num_colors = 255;
|
||||
}else{
|
||||
throw std::runtime_error("Unsupported pixel format");
|
||||
}
|
||||
|
||||
// Write header
|
||||
out << ppm_type;
|
||||
out << " ";
|
||||
out << w;
|
||||
out << " ";
|
||||
out << h;
|
||||
out << " ";
|
||||
out << num_colors;
|
||||
out << "\n";
|
||||
|
||||
// Write out data
|
||||
if(top_line_first) {
|
||||
for(size_t r=0; r<image.h; ++r) {
|
||||
out.write( (char*)image.ptr + r*image.pitch, image.pitch );
|
||||
}
|
||||
}else{
|
||||
for(size_t r=0; r<image.h; ++r) {
|
||||
out.write( (char*)image.ptr + (image.h-1-r)*image.pitch, image.pitch );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
25
thirdparty/Pangolin/src/image/image_io_raw.cpp
vendored
Normal file
25
thirdparty/Pangolin/src/image/image_io_raw.cpp
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
#include <fstream>
|
||||
#include <pangolin/image/typed_image.h>
|
||||
|
||||
namespace pangolin {
|
||||
|
||||
TypedImage LoadImage(
|
||||
const std::string& filename,
|
||||
const PixelFormat& raw_fmt,
|
||||
size_t raw_width, size_t raw_height, size_t raw_pitch
|
||||
) {
|
||||
TypedImage img(raw_width, raw_height, raw_fmt, raw_pitch);
|
||||
|
||||
// Read from file, row at a time.
|
||||
std::ifstream bFile( filename.c_str(), std::ios::in | std::ios::binary );
|
||||
for(size_t r=0; r<img.h; ++r) {
|
||||
bFile.read( (char*)img.ptr + r*img.pitch, img.pitch );
|
||||
if(bFile.fail()) {
|
||||
pango_print_warn("Unable to read raw image file to completion.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
return img;
|
||||
}
|
||||
|
||||
}
|
||||
53
thirdparty/Pangolin/src/image/image_io_tga.cpp
vendored
Normal file
53
thirdparty/Pangolin/src/image/image_io_tga.cpp
vendored
Normal file
@@ -0,0 +1,53 @@
|
||||
#include <pangolin/platform.h>
|
||||
|
||||
#include <pangolin/image/image_io.h>
|
||||
|
||||
namespace pangolin {
|
||||
|
||||
PixelFormat TgaFormat(int depth, int color_type, int color_map)
|
||||
{
|
||||
if(color_map == 0) {
|
||||
if(color_type == 2) {
|
||||
// Colour
|
||||
if(depth == 24) {
|
||||
return PixelFormatFromString("RGB24");
|
||||
}else if(depth == 32) {
|
||||
return PixelFormatFromString("RGBA32");
|
||||
}
|
||||
}else if(color_type == 3){
|
||||
// Greyscale
|
||||
if(depth == 8) {
|
||||
return PixelFormatFromString("GRAY8");
|
||||
}else if(depth == 16) {
|
||||
return PixelFormatFromString("Y400A");
|
||||
}
|
||||
}
|
||||
}
|
||||
throw std::runtime_error("Unsupported TGA format");
|
||||
}
|
||||
|
||||
TypedImage LoadTga(std::istream& in)
|
||||
{
|
||||
unsigned char type[4];
|
||||
unsigned char info[6];
|
||||
|
||||
in.read((char*)type, 3*sizeof(char));
|
||||
in.seekg(12);
|
||||
in.read((char*)info,6*sizeof(char));
|
||||
|
||||
const int width = info[0] + (info[1] * 256);
|
||||
const int height = info[2] + (info[3] * 256);
|
||||
|
||||
if(in.good()) {
|
||||
TypedImage img(width, height, TgaFormat(info[4], type[2], type[1]) );
|
||||
|
||||
//read in image data
|
||||
const size_t data_size = img.h * img.pitch;
|
||||
in.read((char*)img.ptr, sizeof(char)*data_size);
|
||||
return img;
|
||||
}
|
||||
|
||||
throw std::runtime_error("Unable to load TGA file");
|
||||
}
|
||||
|
||||
}
|
||||
125
thirdparty/Pangolin/src/image/image_io_zstd.cpp
vendored
Normal file
125
thirdparty/Pangolin/src/image/image_io_zstd.cpp
vendored
Normal file
@@ -0,0 +1,125 @@
|
||||
|
||||
#include <fstream>
|
||||
#include <memory>
|
||||
|
||||
#include <pangolin/image/typed_image.h>
|
||||
|
||||
#ifdef HAVE_ZSTD
|
||||
# include <zstd.h>
|
||||
#endif
|
||||
|
||||
namespace pangolin {
|
||||
|
||||
#pragma pack(push, 1)
|
||||
struct zstd_image_header
|
||||
{
|
||||
char magic[4];
|
||||
char fmt[16];
|
||||
size_t w, h;
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
void SaveZstd(const Image<unsigned char>& image, const pangolin::PixelFormat& fmt, std::ostream& out, int compression_level)
|
||||
{
|
||||
#ifdef HAVE_ZSTD
|
||||
// Write out header, uncompressed
|
||||
zstd_image_header header;
|
||||
strncpy(header.magic,"ZSTD",4);
|
||||
strncpy(header.fmt, fmt.format.c_str(), sizeof(header.fmt));
|
||||
header.w = image.w;
|
||||
header.h = image.h;
|
||||
out.write((char*)&header, sizeof(header));
|
||||
|
||||
// Write out image data
|
||||
const size_t output_buffer_size = ZSTD_CStreamOutSize();
|
||||
std::unique_ptr<char[]> output_buffer(new char[output_buffer_size]);
|
||||
|
||||
ZSTD_CStream* const cstream = ZSTD_createCStream();
|
||||
if (cstream==nullptr) {
|
||||
throw std::runtime_error("ZSTD_createCStream() error");
|
||||
}
|
||||
|
||||
size_t const initResult = ZSTD_initCStream(cstream, compression_level);
|
||||
if (ZSTD_isError(initResult)) {
|
||||
throw std::runtime_error(FormatString("ZSTD_initCStream() error : %", ZSTD_getErrorName(initResult)));
|
||||
}
|
||||
|
||||
const size_t row_size_bytes = (fmt.bpp * image.w)/8;
|
||||
|
||||
for(size_t y=0; y < image.h; ++y) {
|
||||
ZSTD_inBuffer input = { image.RowPtr(y), row_size_bytes, 0 };
|
||||
|
||||
while (input.pos < input.size) {
|
||||
ZSTD_outBuffer output = { output_buffer.get(), output_buffer_size, 0 };
|
||||
size_t left_to_read = ZSTD_compressStream(cstream, &output , &input);
|
||||
if (ZSTD_isError(left_to_read)) {
|
||||
throw std::runtime_error(FormatString("ZSTD_compressStream() error : %", ZSTD_getErrorName(left_to_read)));
|
||||
}
|
||||
out.write(output_buffer.get(), output.pos);
|
||||
}
|
||||
}
|
||||
|
||||
ZSTD_outBuffer output = { output_buffer.get(), output_buffer_size, 0 };
|
||||
size_t const remainingToFlush = ZSTD_endStream(cstream, &output); /* close frame */
|
||||
if (remainingToFlush) {
|
||||
throw std::runtime_error("not fully flushed");
|
||||
}
|
||||
out.write(output_buffer.get(), output.pos);
|
||||
|
||||
ZSTD_freeCStream(cstream);
|
||||
#else
|
||||
PANGOLIN_UNUSED(image);
|
||||
PANGOLIN_UNUSED(fmt);
|
||||
PANGOLIN_UNUSED(out);
|
||||
PANGOLIN_UNUSED(compression_level);
|
||||
throw std::runtime_error("Rebuild Pangolin for ZSTD support.");
|
||||
#endif // HAVE_ZSTD
|
||||
}
|
||||
|
||||
TypedImage LoadZstd(std::istream& in)
|
||||
{
|
||||
#ifdef HAVE_ZSTD
|
||||
// Read in header, uncompressed
|
||||
zstd_image_header header;
|
||||
in.read( (char*)&header, sizeof(header));
|
||||
|
||||
TypedImage img(header.w, header.h, PixelFormatFromString(header.fmt));
|
||||
|
||||
const size_t input_buffer_size = ZSTD_DStreamInSize();
|
||||
std::unique_ptr<char[]> input_buffer(new char[input_buffer_size]);
|
||||
|
||||
ZSTD_DStream* dstream = ZSTD_createDStream();
|
||||
if(!dstream) {
|
||||
throw std::runtime_error("ZSTD_createDStream() error");
|
||||
}
|
||||
|
||||
size_t read_size_hint = ZSTD_initDStream(dstream);
|
||||
if (ZSTD_isError(read_size_hint)) {
|
||||
throw std::runtime_error(FormatString("ZSTD_initDStream() error : % \n", ZSTD_getErrorName(read_size_hint)));
|
||||
}
|
||||
|
||||
// Image represents our fixed buffer.
|
||||
ZSTD_outBuffer output = { img.ptr, img.SizeBytes(), 0 };
|
||||
|
||||
while(read_size_hint)
|
||||
{
|
||||
const size_t read = in.readsome(input_buffer.get(), read_size_hint);
|
||||
ZSTD_inBuffer input = { input_buffer.get(), read, 0 };
|
||||
while (input.pos < input.size) {
|
||||
read_size_hint = ZSTD_decompressStream(dstream, &output , &input);
|
||||
if (ZSTD_isError(read_size_hint)) {
|
||||
throw std::runtime_error(FormatString("ZSTD_decompressStream() error : %", ZSTD_getErrorName(read_size_hint)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ZSTD_freeDStream(dstream);
|
||||
|
||||
return img;
|
||||
#else
|
||||
PANGOLIN_UNUSED(in);
|
||||
throw std::runtime_error("Rebuild Pangolin for ZSTD support.");
|
||||
#endif // HAVE_ZSTD
|
||||
}
|
||||
|
||||
}
|
||||
70
thirdparty/Pangolin/src/image/pixel_format.cpp
vendored
Normal file
70
thirdparty/Pangolin/src/image/pixel_format.cpp
vendored
Normal file
@@ -0,0 +1,70 @@
|
||||
/* This file is part of the Pangolin Project.
|
||||
* http://github.com/stevenlovegrove/Pangolin
|
||||
*
|
||||
* Copyright (c) 2011 Steven Lovegrove
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation
|
||||
* files (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following
|
||||
* conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <pangolin/image/pixel_format.h>
|
||||
|
||||
#include <stdexcept>
|
||||
#include <vector>
|
||||
|
||||
namespace pangolin
|
||||
{
|
||||
|
||||
// Not to exceed 8 byte Format code.
|
||||
const PixelFormat SupportedPixelFormats[] =
|
||||
{
|
||||
{"GRAY8", 1, {8}, 8, 8, false},
|
||||
{"GRAY10", 1, {10}, 10, 10, false},
|
||||
{"GRAY12", 1, {12}, 12, 12, false},
|
||||
{"GRAY16LE", 1, {16}, 16, 16, false},
|
||||
{"GRAY32", 1, {32}, 32, 32, false},
|
||||
{"Y400A", 2, {8,8}, 16, 8, false},
|
||||
{"RGB24", 3, {8,8,8}, 24, 8, false},
|
||||
{"BGR24", 3, {8,8,8}, 24, 8, false},
|
||||
{"RGB48", 3, {16,16,16}, 48, 16, false},
|
||||
{"BGR48", 3, {16,16,16}, 48, 16, false},
|
||||
{"YUYV422", 3, {4,2,2}, 16, 8, false},
|
||||
{"UYVY422", 3, {4,2,2}, 16, 8, false},
|
||||
{"RGBA32", 4, {8,8,8,8}, 32, 8, false},
|
||||
{"BGRA32", 4, {8,8,8,8}, 32, 8, false},
|
||||
{"RGBA64", 4, {16,16,16,16}, 64, 16, false},
|
||||
{"BGRA64", 4, {16,16,16,16}, 64, 16, false},
|
||||
{"GRAY32F", 1, {32}, 32, 32, false},
|
||||
{"GRAY64F", 1, {64}, 64, 64, false},
|
||||
{"RGB96F", 3, {32,32,32}, 96, 32, false},
|
||||
{"RGBA128F", 4, {32,32,32,32}, 128, 32, false},
|
||||
{"",0,{0,0,0,0},0,0,0}
|
||||
};
|
||||
|
||||
PixelFormat PixelFormatFromString(const std::string& format)
|
||||
{
|
||||
for(int i=0; !SupportedPixelFormats[i].format.empty(); ++i)
|
||||
if(!format.compare(SupportedPixelFormats[i].format))
|
||||
return SupportedPixelFormats[i];
|
||||
throw std::runtime_error( std::string("Unknown Format: ") + format);
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user