lms-video/Gem/plugins/imageTIFF/imageTIFF.cpp
Santi Noreña e85d191b46 - Reestructuración de ficheros y directorios general
- merge v0.01 --> Añadido fileselector
- Añadidas fuentes de Gem y Pure Data
- pix2jpg incluído en Gem. Archivos de construcción de Gem modificados.
- Añadido fichero ompiling.txt con instrucciones de compilación
2013-02-04 18:00:17 +01:00

375 lines
11 KiB
C++

////////////////////////////////////////////////////////
//
// GEM - Graphics Environment for Multimedia
//
// zmoelnig@iem.kug.ac.at
//
// Implementation file
//
// Copyright (c) 1997-1999 Mark Danks.
// Copyright (c) Günther Geiger.
// Copyright (c) 2001-2011 IOhannes m zmölnig. forum::für::umläute. IEM. zmoelnig@iem.at
// For information on usage and redistribution, and for a DISCLAIMER OF ALL
// WARRANTIES, see the file, "GEM.LICENSE.TERMS" in this distribution.
//
/////////////////////////////////////////////////////////
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#ifdef HAVE_LIBTIFF
extern "C"
{
# include "tiffio.h"
}
#include <string.h>
#include "imageTIFF.h"
#include "plugins/PluginFactory.h"
#include "Gem/RTE.h"
using namespace gem::plugins;
REGISTER_IMAGELOADERFACTORY("tiff", imageTIFF);
REGISTER_IMAGESAVERFACTORY("tiff", imageTIFF);
#ifdef _MSC_VER
# define vsnprintf _vsnprintf
#endif
namespace {
static void imageTIFF_verbosehandler(const int verbosity, const char*module, const char*fmt, va_list ap) {
std::string result=module;
result+=": ";
char buf[MAXPDSTRING];
vsnprintf(buf, MAXPDSTRING, fmt, ap);
buf[MAXPDSTRING-1]=0;
result+=buf;
verbose(verbosity, "%s", result.c_str());
}
static void imageTIFF_errorhandler(const char*module, const char*fmt, va_list ap) {
imageTIFF_verbosehandler(2, module, fmt, ap);
}
static void imageTIFF_warnhandler(const char*module, const char*fmt, va_list ap) {
imageTIFF_verbosehandler(3, module, fmt, ap);
}
};
/////////////////////////////////////////////////////////
//
// imageTIFF
//
/////////////////////////////////////////////////////////
// Constructor
//
/////////////////////////////////////////////////////////
imageTIFF :: imageTIFF(void)
{
//post("imageTIFF");
bool firsttime=true;
if(firsttime) {
TIFFSetErrorHandler(imageTIFF_errorhandler);
TIFFSetWarningHandler(imageTIFF_warnhandler);
}
firsttime=false;
}
imageTIFF :: ~imageTIFF(void)
{
//post("~imageTIFF");
}
/////////////////////////////////////////////////////////
// really open the file ! (OS dependent)
//
/////////////////////////////////////////////////////////
bool imageTIFF :: load(std::string filename, imageStruct&result, gem::Properties&props)
{
::verbose(2, "reading '%s' with libTIFF", filename.c_str());
TIFF *tif = TIFFOpen(filename.c_str(), "r");
if (tif == NULL) {
return(NULL);
}
uint32 width, height;
short bits, samps;
TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &width);
TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &height);
TIFFGetField(tif, TIFFTAG_BITSPERSAMPLE, &bits);
TIFFGetField(tif, TIFFTAG_SAMPLESPERPIXEL, &samps);
int npixels = width * height;
result.xsize=width;
result.ysize=height;
result.upsidedown=true;
result.type=GL_UNSIGNED_BYTE; //?
bool knownFormat = false;
// Is it a gray8 image?
if (bits == 8 && samps == 1)
{
result.setCsizeByFormat(GL_LUMINANCE);
knownFormat = true;
}
// Is it an RGB image?
else if (bits == 8 && samps == 3)
{
result.setCsizeByFormat(GL_RGBA);
knownFormat = true;
}
// Is it an RGBA image?
else if (bits == 8 && samps == 4)
{
result.setCsizeByFormat(GL_RGBA);
knownFormat = true;
}
// can we handle the raw data?
if (knownFormat) {
unsigned char *buf = new unsigned char [TIFFScanlineSize(tif)];
if (buf == NULL) {
error("GemImageLoad(TIFF): can't allocate memory for scanline buffer: %s", filename.c_str());
TIFFClose(tif);
return(false);
}
result.reallocate();
unsigned char *dstLine = result.data;
int yStride = result.xsize * result.csize;
for (uint32 row = 0; row < height; row++)
{
unsigned char *pixels = dstLine;
if (TIFFReadScanline(tif, buf, row, 0) < 0) {
error("GemImageLoad(TIFF): bad image data read on line: %d: %s", row, filename.c_str());
TIFFClose(tif);
return false;
}
unsigned char *inp = buf;
if (samps == 1) {
for (uint32 i = 0; i < width; i++) {
*pixels++ = *inp++; // Gray8
}
}
else if (samps == 3) {
for (uint32 i = 0; i < width; i++) {
pixels[chRed] = inp[0]; // Red
pixels[chGreen] = inp[1]; // Green
pixels[chBlue] = inp[2]; // Blue
pixels[chAlpha] = 255; // Alpha
pixels += 4;
inp += 3;
}
} else {
for (uint32 i = 0; i < width; i++) {
pixels[chRed] = inp[0]; // Red
pixels[chGreen] = inp[1]; // Green
pixels[chBlue] = inp[2]; // Blue
pixels[chAlpha] = inp[3]; // Alpha
pixels += 4;
inp += 4;
}
}
dstLine += yStride;
}
delete [] buf;
}
// nope, so use the automatic conversion
else {
char emsg[1024];
TIFFRGBAImage img;
if (TIFFRGBAImageBegin(&img, tif, 0, emsg) == 0) {
//error("GemImageLoad(TIFF): Error reading in image file: %s : %s", filename, emsg);
TIFFClose(tif);
return(false);
}
uint32*raster = reinterpret_cast<uint32*>(_TIFFmalloc(npixels * sizeof(uint32)));
if (raster == NULL) {
error("GemImageLoad(TIFF): Unable to allocate memory for image: %s", filename.c_str());
TIFFClose(tif);
return(false);
}
if (TIFFRGBAImageGet(&img, raster, width, height) == 0) {
//error("GemImageLoad(TIFF): Error getting image data in file: %s, %s", filename, emsg);
_TIFFfree(raster);
TIFFClose(tif);
return(false);
}
TIFFRGBAImageEnd(&img);
result.setCsizeByFormat(GL_RGBA);
result.reallocate();
unsigned char *dstLine = result.data;
int yStride = result.xsize * result.csize;
// transfer everything over
int k = 0;
for (uint32 i = 0; i < height; i++) {
unsigned char *pixels = dstLine;
for (uint32 j = 0; j < width; j++) {
pixels[chRed] = static_cast<unsigned char>(TIFFGetR(raster[k])); // Red
pixels[chGreen] = static_cast<unsigned char>(TIFFGetG(raster[k])); // Green
pixels[chBlue] = static_cast<unsigned char>(TIFFGetB(raster[k])); // Blue
pixels[chAlpha] = static_cast<unsigned char>(TIFFGetA(raster[k])); // Alpha
k++;
pixels += 4;
}
dstLine += yStride;
}
_TIFFfree(raster);
}
double value_d;
short value_i16;
char value_s[MAXPDSTRING];
if(TIFFGetField(tif, TIFFTAG_XRESOLUTION, &value_d)) props.set("xresolution", value_d);
if(TIFFGetField(tif, TIFFTAG_YRESOLUTION, &value_d)) props.set("yresolution", value_d);
if(TIFFGetField(tif, TIFFTAG_XRESOLUTION, &value_d)) props.set("xresolution", value_d);
if(TIFFGetField(tif, TIFFTAG_RESOLUTIONUNIT, &value_i16)) {
std::string resunit;
switch(value_i16) {
case RESUNIT_INCH:
resunit="inch";
break;
case RESUNIT_CENTIMETER:
resunit="centimeter";
break;
default:
resunit="none";
break;
}
props.set("resolutionunit", resunit);
}
if(TIFFGetField(tif, TIFFTAG_SOFTWARE, &value_s)) props.set("software", std::string(value_s));
if(TIFFGetField(tif, TIFFTAG_ARTIST, &value_s)) props.set("artist", std::string(value_s));
if(TIFFGetField(tif, TIFFTAG_HOSTCOMPUTER, &value_s)) props.set("hostcomputer", std::string(value_s));
TIFFClose(tif);
return true;
}
bool imageTIFF::save(const imageStruct&constimage, const std::string&filename, const std::string&mimetype, const gem::Properties&props) {
TIFF *tif = NULL;
if(GL_YUV422_GEM==constimage.format) {
error("don't know how to write YUV-images with libTIFF");
return false;
}
tif=TIFFOpen(filename.c_str(), "w");
if (tif == NULL) {
return false;
}
imageStruct image; constimage.copy2Image(&image);
image.fixUpDown();
uint32 width=image.xsize, height = image.ysize;
short bits=8, samps=image.csize;
int npixels = width * height;
//int planar_conf = PLANARCONFIG_CONTIG;
std::string software = "PD/GEM";
std::string artist;
std::string hostcomputer;
double xresolution = 72., yresolution=72.;
short resunit = RESUNIT_INCH;
props.get("xresolution", xresolution);
props.get("yresolution", yresolution);
std::string resunit_s;
if(props.get("resolutionunit", resunit_s)) {
if(("inch"==resunit_s) || ("english"==resunit_s) || ("imperial"==resunit_s))
resunit=RESUNIT_INCH;
else if(("centimeter"==resunit_s) || ("metric"==resunit_s))
resunit=RESUNIT_CENTIMETER;
else
resunit=RESUNIT_NONE;
}
props.get("software", software);
props.get("artist", artist);
props.get("hostcomputer", hostcomputer);
TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, width);
TIFFSetField(tif, TIFFTAG_IMAGELENGTH, height);
TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, bits);
TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, samps);
TIFFSetField(tif, TIFFTAG_PLANARCONFIG, 1);
TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);
TIFFSetField(tif, TIFFTAG_XRESOLUTION, xresolution); // RATIONAL
TIFFSetField(tif, TIFFTAG_YRESOLUTION, yresolution); // RATIONAL
TIFFSetField(tif, TIFFTAG_RESOLUTIONUNIT, resunit);
if(!software.empty())
TIFFSetField(tif, TIFFTAG_SOFTWARE, software.c_str());
if(!artist.empty())
TIFFSetField(tif, TIFFTAG_ARTIST, artist.c_str());
if(!hostcomputer.empty())
TIFFSetField(tif, TIFFTAG_HOSTCOMPUTER, hostcomputer.c_str());
int yStride = image.xsize * image.csize;
unsigned char *srcLine = &(image.data[npixels * image.csize]);
srcLine -= yStride;
for (uint32 row = 0; row < height; row++) {
unsigned char *buf = srcLine;
if (TIFFWriteScanline(tif, buf, row, 0) < 0)
{
error("GEM: could not write line %d to image %s", row, filename.c_str());
TIFFClose(tif);
delete [] buf;
return(false);
}
srcLine -= yStride;
}
TIFFClose(tif);
return true;
}
float imageTIFF::estimateSave(const imageStruct&img, const std::string&filename, const std::string&mimetype, const gem::Properties&props) {
float result=0;
if(mimetype == "image/tiff" || mimetype == "image/x-tiff")
result += 100;
if(gem::Properties::UNSET != props.type("xresolution"))result+=1.;
if(gem::Properties::UNSET != props.type("yresolution"))result+=1.;
if(gem::Properties::UNSET != props.type("resolutionunit"))result+=1.;
if(gem::Properties::UNSET != props.type("software"))result+=1.;
if(gem::Properties::UNSET != props.type("artist"))result+=1.;
if(gem::Properties::UNSET != props.type("hostcomputer"))result+=1.;
return result;
}
void imageTIFF::getWriteCapabilities(std::vector<std::string>&mimetypes, gem::Properties&props) {
mimetypes.clear();
props.clear();
mimetypes.push_back("image/tiff");
mimetypes.push_back("image/x-tiff");
gem::any value;
value=72.f;
props.set("xresolution", value);
props.set("yresolution", value);
value=std::string("inch");
props.set("resolutionunit", value);
value=std::string("PD/GEM");
props.set("software", value);
value=std::string("");
props.set("artist", value);
props.set("hostcomputer", value);
}
#endif