Is there a way in LibTiff how I can read a file from Memory and save it to Memory?
I don't want to save the image to the disc first, before opening it with an other library...
Thanks so much!
Is there a way in LibTiff how I can read a file from Memory and save it to Memory?
I don't want to save the image to the disc first, before opening it with an other library...
Thanks so much!
I know this is an old question, but I am going to post an easier, more up-to-date answer for those like myself who need this information for more recent versions of libtiff. In the newest version of libtiff (4.0.2), and even the past few versions I believe (check for your specific version number), there is an include file called tiffio.hxx. It has two extern functions for reading/writing to streams in memory:
extern TIFF* TIFFStreamOpen(const char*, std::ostream *);
extern TIFF* TIFFStreamOpen(const char*, std::istream *);
You can just include this file and read or write to memory.
Writing example:
#include <tiffio.h>
#include <tiffio.hxx>
#include <sstream>
std::ostringstream output_TIFF_stream;
//Note: because this is an in memory TIFF, just use whatever you want for the name - we
//aren't using it to read from a file
TIFF* mem_TIFF = TIFFStreamOpen("MemTIFF", &output_TIFF_stream);
//perform normal operations on mem_TIFF here like setting fields
//...
//Write image data to the TIFF
//..
TIFFClose(mem_TIFF);
//Now output_TIFF_stream has all of my image data. I can do whatever I need to with it.
Reading is very similar:
#include <tiffio.h>
#include <tiffio.hxx>
#include <sstream>
std::istringstream input_TIFF_stream;
//Populate input_TIFF_stream with TIFF image data
//...
TIFF* mem_TIFF = TIFFStreamOpen("MemTIFF", &input_TIFF_stream);
//perform normal operations on mem_TIFF here reading fields
//...
TIFFClose(mem_TIFF);
These are very simple examples, but you can see that by using TIFFStreamOpen you don't have to override those functions and pass them to TIFFClientOpen.
You should create your own read/write/etc. functions and pass them to TIFFClientOpen
(not TIFFOpen
) function when creating your TIFF
.
Example:
TIFF* tif = TIFFClientOpen(
"Memory", "w", (thandle_t)something_you_will_use_later,
tiff_Read, tiff_Write, tiff_Seek, tiff_Close, tiff_Size,
tiff_Map, tiff_Unmap);
And you should also implement following functions (st
passed to these functions is the something_you_will_use_later
passed to TIFFClientOpen
:
tsize_t tiff_Read(thandle_t st,tdata_t buffer,tsize_t size)
{
...
};
tsize_t tiff_Write(thandle_t st,tdata_t buffer,tsize_t size)
{
...
};
int tiff_Close(thandle_t)
{
return 0;
};
toff_t tiff_Seek(thandle_t st,toff_t pos, int whence)
{
if (pos == 0xFFFFFFFF)
return 0xFFFFFFFF;
...
};
toff_t tiff_Size(thandle_t st)
{
...
};
int tiff_Map(thandle_t, tdata_t*, toff_t*)
{
return 0;
};
void tiff_Unmap(thandle_t, tdata_t, toff_t)
{
return;
};
What I'm using...:
#define MALLOC(ptr,type,number,action) {\
if (((ptr) = (type*) malloc ((number)*sizeof(type))) == NULL) {\
(void) fprintf (stderr, "[%s: #%04d] ERROR : malloc of %lu bytes failed !\n", __FILE__, __LINE__, number*sizeof(type));\
perror ("Operating system message");\
action;}}
#define REALLOC(ptr,type,number,action) {\
if (((ptr) = (type*) realloc ((ptr), (number)*sizeof(type))) == NULL) {\
(void) fprintf (stderr, "[%s: #%04d] ERROR : realloc of %lu bytes failed!\n", __FILE__, __LINE__, number*sizeof(type));\
perror ("Operating system message");\
action;}}
#define FREE(ptr) { if (ptr != NULL) free (ptr); ptr = NULL; }
extern "C" {
typedef struct _memtiff {
unsigned char *data;
tsize_t size;
tsize_t incsiz;
tsize_t flen;
toff_t fptr;
} MEMTIFF;
static MEMTIFF *memTiffOpen(tsize_t incsiz = 10240, tsize_t initsiz = 10240)
{
MEMTIFF *memtif;
MALLOC(memtif, MEMTIFF, 1, exit(-1));
memtif->incsiz = incsiz;
if (initsiz == 0) initsiz = incsiz;
MALLOC(memtif->data, unsigned char, initsiz, exit(-1));
memtif->size = initsiz;
memtif->flen = 0;
memtif->fptr = 0;
return memtif;
}
/*===========================================================================*/
static tsize_t memTiffReadProc(thandle_t handle, tdata_t buf, tsize_t size)
{
MEMTIFF *memtif = (MEMTIFF *) handle;
tsize_t n;
if (((tsize_t) memtif->fptr + size) <= memtif->flen) {
n = size;
}
else {
n = memtif->flen - memtif->fptr;
}
memcpy(buf, memtif->data + memtif->fptr, n);
memtif->fptr += n;
return n;
}
/*===========================================================================*/
static tsize_t memTiffWriteProc(thandle_t handle, tdata_t buf, tsize_t size)
{
MEMTIFF *memtif = (MEMTIFF *) handle;
if (((tsize_t) memtif->fptr + size) > memtif->size) {
memtif->data = (unsigned char *) realloc(memtif->data, memtif->fptr + memtif->incsiz + size);
memtif->size = memtif->fptr + memtif->incsiz + size;
}
memcpy (memtif->data + memtif->fptr, buf, size);
memtif->fptr += size;
if (memtif->fptr > memtif->flen) memtif->flen = memtif->fptr;
return size;
}
/*===========================================================================*/
static toff_t memTiffSeekProc(thandle_t handle, toff_t off, int whence)
{
MEMTIFF *memtif = (MEMTIFF *) handle;
switch (whence) {
case SEEK_SET: {
if ((tsize_t) off > memtif->size) {
memtif->data = (unsigned char *) realloc(memtif->data, memtif->size + memtif->incsiz + off);
memtif->size = memtif->size + memtif->incsiz + off;
}
memtif->fptr = off;
break;
}
case SEEK_CUR: {
if ((tsize_t)(memtif->fptr + off) > memtif->size) {
memtif->data = (unsigned char *) realloc(memtif->data, memtif->fptr + memtif->incsiz + off);
memtif->size = memtif->fptr + memtif->incsiz + off;
}
memtif->fptr += off;
break;
}
case SEEK_END: {
if ((tsize_t) (memtif->size + off) > memtif->size) {
memtif->data = (unsigned char *) realloc(memtif->data, memtif->size + memtif->incsiz + off);
memtif->size = memtif->size + memtif->incsiz + off;
}
memtif->fptr = memtif->size + off;
break;
}
}
if (memtif->fptr > memtif->flen) memtif->flen = memtif->fptr;
return memtif->fptr;
}
/*===========================================================================*/
static int memTiffCloseProc(thandle_t handle)
{
MEMTIFF *memtif = (MEMTIFF *) handle;
memtif->fptr = 0;
return 0;
}
/*===========================================================================*/
static toff_t memTiffSizeProc(thandle_t handle)
{
MEMTIFF *memtif = (MEMTIFF *) handle;
return memtif->flen;
}
/*===========================================================================*/
static int memTiffMapProc(thandle_t handle, tdata_t* base, toff_t* psize)
{
MEMTIFF *memtif = (MEMTIFF *) handle;
*base = memtif->data;
*psize = memtif->flen;
return (1);
}
/*===========================================================================*/
static void memTiffUnmapProc(thandle_t handle, tdata_t base, toff_t size)
{
return;
}
/*===========================================================================*/
static void memTiffFree(MEMTIFF *memtif)
{
FREE(memtif->data);
FREE(memtif);
return;
}
/*===========================================================================*/
}
And then:
if ((filepath == "-") || (filepath == "HTTP")) {
memtif = memTiffOpen();
tif = TIFFClientOpen("MEMTIFF", "wb", (thandle_t) memtif,
memTiffReadProc,
memTiffWriteProc,
memTiffSeekProc,
memTiffCloseProc,
memTiffSizeProc,
memTiffMapProc,
memTiffUnmapProc
);
}
else {
if ((tif = TIFFOpen (filepath.c_str(), "wb")) == NULL) {
if (memtif != NULL) memTiffFree(memtif);
string msg = "TIFFopen of \"" + filepath + "\" failed!";
throw SipiError(__file__, __LINE__, msg);
}
}
In order to use the in-memry buffer:
if (filepath == "-") {
size_t n = 0;
while (n < memtif->flen) {
n += fwrite (&(memtif->data[n]), 1, memtif->flen - n > 10240 ? 10240 : memtif->flen - n, stdout);
}
fflush(stdout);
memTiffFree(memtif);
}
I'm experiencing the same problem: saving TIFF as a temporary file and rereading it works, while reading the same file in memory and trying to save or create cv::Mat fails. The reason is that reading file normally goes through _tiffReadProc that consumes 8 bytes ("II*\0\b\0\0\0" in my case) and returns them as a valid header, while reading from memory goes through _tiffisReadProc that reads only 3 bytes and fails with invalid header. Don't know how to make it work. Populating std::istringstream is easy: std::istringstream input_TIFF_stream(mem); where "mem" is a char array.
Another user posted that TIFFStreamOpen
does not write data correctly, and I can confirm that. Only the header is written. Reading works correctly. Tested version 4.5.1 with C++ Builder.
I implemented writing to std::string
by using TIFFClientOpen
, which might be easier to understand than the code in another answer:
namespace WriteImpl {
struct client_data {
std::string *buffer;
size_t position;
};
tsize_t writeproc(thandle_t fd, tdata_t buf, tsize_t size)
{
auto data = reinterpret_cast<client_data*>(fd);
const size_t finalSize = data->position + size;
if (data->buffer->size() < finalSize) {
data->buffer->resize(finalSize);
}
auto srcIt = reinterpret_cast<const uint8_t*>(buf);
auto dstIt = data->buffer->begin() + data->position;
std::copy(srcIt, srcIt + size, dstIt);
return size;
}
toff_t seekproc(thandle_t fd, toff_t off, int whence)
{
auto data = reinterpret_cast<client_data*>(fd);
switch (whence) {
case SEEK_SET:
data->position = static_cast<size_t>(off);
break;
case SEEK_CUR:
data->position = data->position + static_cast<size_t>(off);
break;
case SEEK_END:
// Since toff_t is unsigned, we cannot seek backwards from the end
if (off == 0) {
data->position = data->buffer->size();
}
else {
return static_cast<toff_t>(-1);
}
break;
}
const size_t minSize = data->position;
if (data->buffer->size() < minSize) {
data->buffer->resize(minSize);
}
return data->position;
}
toff_t sizeproc(thandle_t fd)
{
auto data = reinterpret_cast<client_data*>(fd);
return data->buffer->size();
}
tsize_t readproc(thandle_t, tdata_t, tsize_t) { return 0; }
int closeproc(thandle_t) { return 0; }
int mapproc(thandle_t, tdata_t*, toff_t*) { return 0; }
void unmapproc(thandle_t, tdata_t, toff_t) {}
} // namespace WriteImpl
std::string write_stream(/* data */)
{
using namespace WriteImpl;
std::string buffer;
auto clientData = std::make_unique<client_data>(client_data{&buffer, 0});
const std::string filename = "Memory-mapped file";
auto tiff_raw = TIFFClientOpen(filename.c_str(), "wm",
reinterpret_cast<thandle_t>(clientData.get()),
readproc, writeproc, seekproc, closeproc, sizeproc,
mapproc, unmapproc);
if (!tiff_raw) {
throw std::runtime_error("Failed");
}
std::shared_ptr<TIFF> tiff(tiff_raw, &TIFFClose);
// Write the data here
// ...
return buffer;
}