Merge branch 'tiff32float' into dev
This commit is contained in:
@@ -330,50 +330,50 @@ Image16::tofloat()
|
|||||||
return imgfloat;
|
return imgfloat;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parallized transformation; create transform with cmsFLAGS_NOCACHE!
|
// // Parallized transformation; create transform with cmsFLAGS_NOCACHE!
|
||||||
void Image16::ExecCMSTransform(cmsHTRANSFORM hTransform, const LabImage &labImage, int cx, int cy)
|
// void Image16::ExecCMSTransform(cmsHTRANSFORM hTransform, const LabImage &labImage, int cx, int cy)
|
||||||
{
|
// {
|
||||||
// LittleCMS cannot parallelize planar Lab float images
|
// // LittleCMS cannot parallelize planar Lab float images
|
||||||
// so build temporary buffers to allow multi processor execution
|
// // so build temporary buffers to allow multi processor execution
|
||||||
#ifdef _OPENMP
|
// #ifdef _OPENMP
|
||||||
#pragma omp parallel
|
// #pragma omp parallel
|
||||||
#endif
|
// #endif
|
||||||
{
|
// {
|
||||||
AlignedBuffer<float> bufferLab(width * 3);
|
// AlignedBuffer<float> bufferLab(width * 3);
|
||||||
AlignedBuffer<unsigned short> bufferRGB(width * 3);
|
// AlignedBuffer<unsigned short> bufferRGB(width * 3);
|
||||||
|
|
||||||
#ifdef _OPENMP
|
// #ifdef _OPENMP
|
||||||
#pragma omp for schedule(static)
|
// #pragma omp for schedule(static)
|
||||||
#endif
|
// #endif
|
||||||
|
|
||||||
for (int y = cy; y < cy + height; y++)
|
// for (int y = cy; y < cy + height; y++)
|
||||||
{
|
// {
|
||||||
unsigned short *pRGB, *pR, *pG, *pB;
|
// unsigned short *pRGB, *pR, *pG, *pB;
|
||||||
float *pLab, *pL, *pa, *pb;
|
// float *pLab, *pL, *pa, *pb;
|
||||||
|
|
||||||
pLab= bufferLab.data;
|
// pLab= bufferLab.data;
|
||||||
pL = labImage.L[y] + cx;
|
// pL = labImage.L[y] + cx;
|
||||||
pa = labImage.a[y] + cx;
|
// pa = labImage.a[y] + cx;
|
||||||
pb = labImage.b[y] + cx;
|
// pb = labImage.b[y] + cx;
|
||||||
|
|
||||||
for (int x = 0; x < width; x++) {
|
// for (int x = 0; x < width; x++) {
|
||||||
*(pLab++) = *(pL++) / 327.68f;
|
// *(pLab++) = *(pL++) / 327.68f;
|
||||||
*(pLab++) = *(pa++) / 327.68f;
|
// *(pLab++) = *(pa++) / 327.68f;
|
||||||
*(pLab++) = *(pb++) / 327.68f;
|
// *(pLab++) = *(pb++) / 327.68f;
|
||||||
}
|
// }
|
||||||
|
|
||||||
cmsDoTransform (hTransform, bufferLab.data, bufferRGB.data, width);
|
// cmsDoTransform (hTransform, bufferLab.data, bufferRGB.data, width);
|
||||||
|
|
||||||
pRGB = bufferRGB.data;
|
// pRGB = bufferRGB.data;
|
||||||
pR = r(y - cy);
|
// pR = r(y - cy);
|
||||||
pG = g(y - cy);
|
// pG = g(y - cy);
|
||||||
pB = b(y - cy);
|
// pB = b(y - cy);
|
||||||
|
|
||||||
for (int x = 0; x < width; x++) {
|
// for (int x = 0; x < width; x++) {
|
||||||
*(pR++) = *(pRGB++);
|
// *(pR++) = *(pRGB++);
|
||||||
*(pG++) = *(pRGB++);
|
// *(pG++) = *(pRGB++);
|
||||||
*(pB++) = *(pRGB++);
|
// *(pB++) = *(pRGB++);
|
||||||
}
|
// }
|
||||||
} // End of parallelization
|
// } // End of parallelization
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
@@ -96,7 +96,7 @@ public:
|
|||||||
delete this;
|
delete this;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ExecCMSTransform(cmsHTRANSFORM hTransform, const LabImage &labImage, int cx, int cy);
|
/* void ExecCMSTransform(cmsHTRANSFORM hTransform, const LabImage &labImage, int cx, int cy); */
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -154,11 +154,25 @@ void Imagefloat::getScanline (int row, unsigned char* buffer, int bps)
|
|||||||
int ix = 0;
|
int ix = 0;
|
||||||
float* sbuffer = (float*) buffer;
|
float* sbuffer = (float*) buffer;
|
||||||
|
|
||||||
|
// agriggio -- assume the image is normalized to [0, 65535]
|
||||||
for (int i = 0; i < width; i++) {
|
for (int i = 0; i < width; i++) {
|
||||||
|
sbuffer[ix++] = r(row, i) / 65535.f;
|
||||||
|
sbuffer[ix++] = g(row, i) / 65535.f;
|
||||||
|
sbuffer[ix++] = b(row, i) / 65535.f;
|
||||||
|
}
|
||||||
|
} else if (bps == 16) {
|
||||||
|
unsigned short *sbuffer = (unsigned short *)buffer;
|
||||||
|
for (int i = 0, ix = 0; i < width; i++) {
|
||||||
sbuffer[ix++] = r(row, i);
|
sbuffer[ix++] = r(row, i);
|
||||||
sbuffer[ix++] = g(row, i);
|
sbuffer[ix++] = g(row, i);
|
||||||
sbuffer[ix++] = b(row, i);
|
sbuffer[ix++] = b(row, i);
|
||||||
}
|
}
|
||||||
|
} else if (bps == 8) {
|
||||||
|
for (int i = 0, ix = 0; i < width; i++) {
|
||||||
|
buffer[ix++] = rtengine::uint16ToUint8Rounded(r(row, i));
|
||||||
|
buffer[ix++] = rtengine::uint16ToUint8Rounded(g(row, i));
|
||||||
|
buffer[ix++] = rtengine::uint16ToUint8Rounded(b(row, i));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -516,3 +530,51 @@ void Imagefloat::ExecCMSTransform(cmsHTRANSFORM hTransform)
|
|||||||
} // End of parallelization
|
} // End of parallelization
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Parallized transformation; create transform with cmsFLAGS_NOCACHE!
|
||||||
|
void Imagefloat::ExecCMSTransform(cmsHTRANSFORM hTransform, const LabImage &labImage, int cx, int cy)
|
||||||
|
{
|
||||||
|
// LittleCMS cannot parallelize planar Lab float images
|
||||||
|
// so build temporary buffers to allow multi processor execution
|
||||||
|
#ifdef _OPENMP
|
||||||
|
#pragma omp parallel
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
AlignedBuffer<float> bufferLab(width * 3);
|
||||||
|
AlignedBuffer<float> bufferRGB(width * 3);
|
||||||
|
|
||||||
|
#ifdef _OPENMP
|
||||||
|
#pragma omp for schedule(static)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
for (int y = cy; y < cy + height; y++)
|
||||||
|
{
|
||||||
|
float *pRGB, *pR, *pG, *pB;
|
||||||
|
float *pLab, *pL, *pa, *pb;
|
||||||
|
|
||||||
|
pLab= bufferLab.data;
|
||||||
|
pL = labImage.L[y] + cx;
|
||||||
|
pa = labImage.a[y] + cx;
|
||||||
|
pb = labImage.b[y] + cx;
|
||||||
|
|
||||||
|
for (int x = 0; x < width; x++) {
|
||||||
|
*(pLab++) = *(pL++) / 327.68f;
|
||||||
|
*(pLab++) = *(pa++) / 327.68f;
|
||||||
|
*(pLab++) = *(pb++) / 327.68f;
|
||||||
|
}
|
||||||
|
|
||||||
|
cmsDoTransform (hTransform, bufferLab.data, bufferRGB.data, width);
|
||||||
|
|
||||||
|
pRGB = bufferRGB.data;
|
||||||
|
pR = r(y - cy);
|
||||||
|
pG = g(y - cy);
|
||||||
|
pB = b(y - cy);
|
||||||
|
|
||||||
|
for (int x = 0; x < width; x++) {
|
||||||
|
*(pR++) = *(pRGB++);
|
||||||
|
*(pG++) = *(pRGB++);
|
||||||
|
*(pB++) = *(pRGB++);
|
||||||
|
}
|
||||||
|
} // End of parallelization
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@@ -106,6 +106,7 @@ public:
|
|||||||
void calcCroppedHistogram(const ProcParams ¶ms, float scale, LUTu & hist);
|
void calcCroppedHistogram(const ProcParams ¶ms, float scale, LUTu & hist);
|
||||||
|
|
||||||
void ExecCMSTransform(cmsHTRANSFORM hTransform);
|
void ExecCMSTransform(cmsHTRANSFORM hTransform);
|
||||||
|
void ExecCMSTransform(cmsHTRANSFORM hTransform, const LabImage &labImage, int cx, int cy);
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -75,15 +75,6 @@ FILE* g_fopen_withBinaryAndLock(const Glib::ustring& fname)
|
|||||||
return f;
|
return f;
|
||||||
}
|
}
|
||||||
|
|
||||||
Glib::ustring to_utf8 (const std::string& str)
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
return Glib::locale_to_utf8 (str);
|
|
||||||
} catch (Glib::Error&) {
|
|
||||||
return Glib::convert_with_fallback (str, "UTF-8", "ISO-8859-1", "?");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Glib::ustring ImageIO::errorMsg[6] = {"Success", "Cannot read file.", "Invalid header.", "Error while reading header.", "File reading error", "Image format not supported."};
|
Glib::ustring ImageIO::errorMsg[6] = {"Success", "Cannot read file.", "Invalid header.", "Error while reading header.", "File reading error", "Image format not supported."};
|
||||||
@@ -136,13 +127,19 @@ void ImageIO::setMetadata (const rtexif::TagDirectory* eroot, const rtengine::pr
|
|||||||
|
|
||||||
iptc = iptc_data_new ();
|
iptc = iptc_data_new ();
|
||||||
|
|
||||||
|
const unsigned char utf8Esc[] = {0x1B, '%', 'G'};
|
||||||
|
IptcDataSet * ds = iptc_dataset_new ();
|
||||||
|
iptc_dataset_set_tag (ds, IPTC_RECORD_OBJECT_ENV, IPTC_TAG_CHARACTER_SET);
|
||||||
|
iptc_dataset_set_data (ds, utf8Esc, 3, IPTC_DONT_VALIDATE);
|
||||||
|
iptc_data_add_dataset (iptc, ds);
|
||||||
|
iptc_dataset_unref (ds);
|
||||||
|
|
||||||
for (rtengine::procparams::IPTCPairs::const_iterator i = iptcc.begin(); i != iptcc.end(); ++i) {
|
for (rtengine::procparams::IPTCPairs::const_iterator i = iptcc.begin(); i != iptcc.end(); ++i) {
|
||||||
if (i->first == "Keywords" && !(i->second.empty())) {
|
if (i->first == "Keywords" && !(i->second.empty())) {
|
||||||
for (unsigned int j = 0; j < i->second.size(); j++) {
|
for (unsigned int j = 0; j < i->second.size(); j++) {
|
||||||
IptcDataSet * ds = iptc_dataset_new ();
|
IptcDataSet * ds = iptc_dataset_new ();
|
||||||
iptc_dataset_set_tag (ds, IPTC_RECORD_APP_2, IPTC_TAG_KEYWORDS);
|
iptc_dataset_set_tag (ds, IPTC_RECORD_APP_2, IPTC_TAG_KEYWORDS);
|
||||||
std::string loc = to_utf8(i->second.at(j));
|
iptc_dataset_set_data (ds, (unsigned char*)i->second.at(j).c_str(), min(static_cast<size_t>(64), i->second.at(j).bytes()), IPTC_DONT_VALIDATE);
|
||||||
iptc_dataset_set_data (ds, (unsigned char*)loc.c_str(), min(static_cast<size_t>(64), loc.size()), IPTC_DONT_VALIDATE);
|
|
||||||
iptc_data_add_dataset (iptc, ds);
|
iptc_data_add_dataset (iptc, ds);
|
||||||
iptc_dataset_unref (ds);
|
iptc_dataset_unref (ds);
|
||||||
}
|
}
|
||||||
@@ -152,8 +149,7 @@ void ImageIO::setMetadata (const rtexif::TagDirectory* eroot, const rtengine::pr
|
|||||||
for (unsigned int j = 0; j < i->second.size(); j++) {
|
for (unsigned int j = 0; j < i->second.size(); j++) {
|
||||||
IptcDataSet * ds = iptc_dataset_new ();
|
IptcDataSet * ds = iptc_dataset_new ();
|
||||||
iptc_dataset_set_tag (ds, IPTC_RECORD_APP_2, IPTC_TAG_SUPPL_CATEGORY);
|
iptc_dataset_set_tag (ds, IPTC_RECORD_APP_2, IPTC_TAG_SUPPL_CATEGORY);
|
||||||
std::string loc = to_utf8(i->second.at(j));
|
iptc_dataset_set_data (ds, (unsigned char*)i->second.at(j).c_str(), min(static_cast<size_t>(32), i->second.at(j).bytes()), IPTC_DONT_VALIDATE);
|
||||||
iptc_dataset_set_data (ds, (unsigned char*)loc.c_str(), min(static_cast<size_t>(32), loc.size()), IPTC_DONT_VALIDATE);
|
|
||||||
iptc_data_add_dataset (iptc, ds);
|
iptc_data_add_dataset (iptc, ds);
|
||||||
iptc_dataset_unref (ds);
|
iptc_dataset_unref (ds);
|
||||||
}
|
}
|
||||||
@@ -165,8 +161,7 @@ void ImageIO::setMetadata (const rtexif::TagDirectory* eroot, const rtengine::pr
|
|||||||
if (i->first == strTags[j].field && !(i->second.empty())) {
|
if (i->first == strTags[j].field && !(i->second.empty())) {
|
||||||
IptcDataSet * ds = iptc_dataset_new ();
|
IptcDataSet * ds = iptc_dataset_new ();
|
||||||
iptc_dataset_set_tag (ds, IPTC_RECORD_APP_2, strTags[j].tag);
|
iptc_dataset_set_tag (ds, IPTC_RECORD_APP_2, strTags[j].tag);
|
||||||
std::string loc = to_utf8(i->second.at(0));
|
iptc_dataset_set_data (ds, (unsigned char*)i->second.at(0).c_str(), min(strTags[j].size, i->second.at(0).bytes()), IPTC_DONT_VALIDATE);
|
||||||
iptc_dataset_set_data (ds, (unsigned char*)loc.c_str(), min(strTags[j].size, loc.size()), IPTC_DONT_VALIDATE);
|
|
||||||
iptc_data_add_dataset (iptc, ds);
|
iptc_data_add_dataset (iptc, ds);
|
||||||
iptc_dataset_unref (ds);
|
iptc_dataset_unref (ds);
|
||||||
}
|
}
|
||||||
@@ -1250,13 +1245,13 @@ int ImageIO::saveJPEG (Glib::ustring fname, int quality, int subSamp)
|
|||||||
int bytes = 0;
|
int bytes = 0;
|
||||||
|
|
||||||
if (!error && (bytes = iptc_jpeg_ps3_save_iptc (nullptr, 0, iptcdata, size, buffer, 65532)) < 0) {
|
if (!error && (bytes = iptc_jpeg_ps3_save_iptc (nullptr, 0, iptcdata, size, buffer, 65532)) < 0) {
|
||||||
if (iptcdata) {
|
|
||||||
iptc_data_free_buf (iptc, iptcdata);
|
|
||||||
}
|
|
||||||
|
|
||||||
error = true;
|
error = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (iptcdata) {
|
||||||
|
iptc_data_free_buf (iptc, iptcdata);
|
||||||
|
}
|
||||||
|
|
||||||
if (!error) {
|
if (!error) {
|
||||||
jpeg_write_marker(&cinfo, JPEG_APP0 + 13, buffer, bytes);
|
jpeg_write_marker(&cinfo, JPEG_APP0 + 13, buffer, bytes);
|
||||||
}
|
}
|
||||||
@@ -1341,189 +1336,198 @@ int ImageIO::saveTIFF (Glib::ustring fname, int bps, bool uncompressed)
|
|||||||
int lineWidth = width * 3 * bps / 8;
|
int lineWidth = width * 3 * bps / 8;
|
||||||
unsigned char* linebuffer = new unsigned char[lineWidth];
|
unsigned char* linebuffer = new unsigned char[lineWidth];
|
||||||
|
|
||||||
// TODO the following needs to be looked into - do we really need two ways to write a Tiff file ?
|
// little hack to get libTiff to use proper byte order (see TIFFClienOpen()):
|
||||||
if (exifRoot && uncompressed) {
|
const char *mode = !exifRoot ? "w" : (exifRoot->getOrder() == rtexif::INTEL ? "wl" : "wb");
|
||||||
FILE *file = g_fopen_withBinaryAndLock (fname);
|
#ifdef WIN32
|
||||||
|
FILE *file = g_fopen_withBinaryAndLock (fname);
|
||||||
|
int fileno = _fileno(file);
|
||||||
|
int osfileno = _get_osfhandle(fileno);
|
||||||
|
TIFF* out = TIFFFdOpen (osfileno, fname.c_str(), mode);
|
||||||
|
#else
|
||||||
|
TIFF* out = TIFFOpen(fname.c_str(), mode);
|
||||||
|
int fileno = TIFFFileno (out);
|
||||||
|
#endif
|
||||||
|
|
||||||
if (!file) {
|
if (!out) {
|
||||||
delete [] linebuffer;
|
delete [] linebuffer;
|
||||||
return IMIO_CANNOTWRITEFILE;
|
return IMIO_CANNOTWRITEFILE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pl) {
|
||||||
|
pl->setProgressStr ("PROGRESSBAR_SAVETIFF");
|
||||||
|
pl->setProgress (0.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (exifRoot) {
|
||||||
|
rtexif::TagDirectory* cl = (const_cast<rtexif::TagDirectory*> (exifRoot))->clone (nullptr);
|
||||||
|
|
||||||
|
// ------------------ remove some unknown top level tags which produce warnings when opening a tiff (might be useless) -----------------
|
||||||
|
|
||||||
|
rtexif::Tag *removeTag = cl->getTag (0x9003);
|
||||||
|
|
||||||
|
if (removeTag) {
|
||||||
|
removeTag->setKeep (false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pl) {
|
removeTag = cl->getTag (0x9211);
|
||||||
pl->setProgressStr ("PROGRESSBAR_SAVETIFF");
|
|
||||||
pl->setProgress (0.0);
|
if (removeTag) {
|
||||||
|
removeTag->setKeep (false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// buffer for the exif and iptc
|
// ------------------ Apply list of change -----------------
|
||||||
unsigned int bufferSize;
|
|
||||||
unsigned char* buffer = nullptr; // buffer will be allocated in createTIFFHeader
|
|
||||||
unsigned char* iptcdata = nullptr;
|
|
||||||
unsigned int iptclen = 0;
|
|
||||||
|
|
||||||
if (iptc && iptc_data_save (iptc, &iptcdata, &iptclen) && iptcdata) {
|
for (auto currExifChange : exifChange) {
|
||||||
|
cl->applyChange (currExifChange.first, currExifChange.second);
|
||||||
|
}
|
||||||
|
|
||||||
|
rtexif::Tag *tag = cl->getTag (TIFFTAG_EXIFIFD);
|
||||||
|
|
||||||
|
if (tag && tag->isDirectory()) {
|
||||||
|
rtexif::TagDirectory *exif = tag->getDirectory();
|
||||||
|
|
||||||
|
if (exif) {
|
||||||
|
int exif_size = exif->calculateSize();
|
||||||
|
unsigned char *buffer = new unsigned char[exif_size + 8];
|
||||||
|
// TIFFOpen writes out the header and sets file pointer at position 8
|
||||||
|
|
||||||
|
exif->write (8, buffer);
|
||||||
|
|
||||||
|
write (fileno, buffer + 8, exif_size);
|
||||||
|
|
||||||
|
delete [] buffer;
|
||||||
|
// let libtiff know that scanlines or any other following stuff should go
|
||||||
|
// at a different offset:
|
||||||
|
TIFFSetWriteOffset (out, exif_size + 8);
|
||||||
|
TIFFSetField (out, TIFFTAG_EXIFIFD, 8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO Even though we are saving EXIF IFD - MakerNote still comes out screwed.
|
||||||
|
|
||||||
|
if ((tag = cl->getTag (TIFFTAG_MODEL)) != nullptr) {
|
||||||
|
TIFFSetField (out, TIFFTAG_MODEL, tag->getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((tag = cl->getTag (TIFFTAG_MAKE)) != nullptr) {
|
||||||
|
TIFFSetField (out, TIFFTAG_MAKE, tag->getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((tag = cl->getTag (TIFFTAG_DATETIME)) != nullptr) {
|
||||||
|
TIFFSetField (out, TIFFTAG_DATETIME, tag->getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((tag = cl->getTag (TIFFTAG_ARTIST)) != nullptr) {
|
||||||
|
TIFFSetField (out, TIFFTAG_ARTIST, tag->getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((tag = cl->getTag (TIFFTAG_COPYRIGHT)) != nullptr) {
|
||||||
|
TIFFSetField (out, TIFFTAG_COPYRIGHT, tag->getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
delete cl;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char* iptcdata = nullptr;
|
||||||
|
unsigned int iptclen = 0;
|
||||||
|
|
||||||
|
if (iptc && iptc_data_save (iptc, &iptcdata, &iptclen)) {
|
||||||
|
if (iptcdata) {
|
||||||
iptc_data_free_buf (iptc, iptcdata);
|
iptc_data_free_buf (iptc, iptcdata);
|
||||||
iptcdata = nullptr;
|
iptcdata = nullptr;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int size = rtexif::ExifManager::createTIFFHeader (exifRoot, exifChange, width, height, bps, profileData, profileLength, (char*)iptcdata, iptclen, buffer, bufferSize);
|
if (iptcdata) {
|
||||||
|
rtexif::Tag* iptcTag = new rtexif::Tag (nullptr, rtexif::lookupAttrib (rtexif::ifdAttribs, "IPTCData"));
|
||||||
if (iptcdata) {
|
iptcTag->initLongArray((char*)iptcdata, iptclen);
|
||||||
iptc_data_free_buf (iptc, iptcdata);
|
#if __BYTE_ORDER__==__ORDER_LITTLE_ENDIAN__
|
||||||
|
bool needsReverse = exifRoot && exifRoot->getOrder() == rtexif::MOTOROLA;
|
||||||
|
#else
|
||||||
|
bool needsReverse = exifRoot && exifRoot->getOrder() == rtexif::INTEL;
|
||||||
|
#endif
|
||||||
|
if (needsReverse) {
|
||||||
|
unsigned char *ptr = iptcTag->getValue();
|
||||||
|
for (int a = 0; a < iptcTag->getCount(); ++a) {
|
||||||
|
unsigned char cc;
|
||||||
|
cc = ptr[3];
|
||||||
|
ptr[3] = ptr[0];
|
||||||
|
ptr[0] = cc;
|
||||||
|
cc = ptr[2];
|
||||||
|
ptr[2] = ptr[1];
|
||||||
|
ptr[1] = cc;
|
||||||
|
ptr += 4;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
TIFFSetField (out, TIFFTAG_RICHTIFFIPTC, iptcTag->getCount(), (long*)iptcTag->getValue());
|
||||||
|
iptc_data_free_buf (iptc, iptcdata);
|
||||||
|
}
|
||||||
|
|
||||||
// The maximum lenght is strangely not the same than for the JPEG file...
|
TIFFSetField (out, TIFFTAG_SOFTWARE, "RawTherapee " RTVERSION);
|
||||||
// Which maximum length is the good one ?
|
TIFFSetField (out, TIFFTAG_IMAGEWIDTH, width);
|
||||||
if (size > 0 && size <= static_cast<int>(bufferSize)) {
|
TIFFSetField (out, TIFFTAG_IMAGELENGTH, height);
|
||||||
fwrite (buffer, size, 1, file);
|
TIFFSetField (out, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
|
||||||
}
|
TIFFSetField (out, TIFFTAG_SAMPLESPERPIXEL, 3);
|
||||||
|
TIFFSetField (out, TIFFTAG_ROWSPERSTRIP, height);
|
||||||
|
TIFFSetField (out, TIFFTAG_BITSPERSAMPLE, bps);
|
||||||
|
TIFFSetField (out, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
|
||||||
|
TIFFSetField (out, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_UINT);
|
||||||
|
TIFFSetField (out, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);
|
||||||
|
TIFFSetField (out, TIFFTAG_COMPRESSION, uncompressed ? COMPRESSION_NONE : COMPRESSION_DEFLATE);
|
||||||
|
TIFFSetField (out, TIFFTAG_SAMPLEFORMAT, bps == 32 ? SAMPLEFORMAT_IEEEFP : SAMPLEFORMAT_UINT);
|
||||||
|
|
||||||
|
if (!uncompressed) {
|
||||||
|
TIFFSetField (out, TIFFTAG_PREDICTOR, bps == 32 ? PREDICTOR_FLOATINGPOINT : PREDICTOR_HORIZONTAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (profileData) {
|
||||||
|
TIFFSetField (out, TIFFTAG_ICCPROFILE, profileLength, profileData);
|
||||||
|
}
|
||||||
|
|
||||||
#if __BYTE_ORDER__==__ORDER_LITTLE_ENDIAN__
|
#if __BYTE_ORDER__==__ORDER_LITTLE_ENDIAN__
|
||||||
bool needsReverse = bps == 16 && exifRoot->getOrder() == rtexif::MOTOROLA;
|
bool needsReverse = (bps == 16 || bps == 32) && exifRoot->getOrder() == rtexif::MOTOROLA;
|
||||||
#else
|
#else
|
||||||
bool needsReverse = bps == 16 && exifRoot->getOrder() == rtexif::INTEL;
|
bool needsReverse = (bps == 16 || bps == 32) && exifRoot->getOrder() == rtexif::INTEL;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
for (int i = 0; i < height; i++) {
|
for (int row = 0; row < height; row++) {
|
||||||
getScanline (i, linebuffer, bps);
|
getScanline (row, linebuffer, bps);
|
||||||
|
|
||||||
if (needsReverse)
|
if (needsReverse) {
|
||||||
|
if (bps == 16) {
|
||||||
for (int i = 0; i < lineWidth; i += 2) {
|
for (int i = 0; i < lineWidth; i += 2) {
|
||||||
char c = linebuffer[i];
|
char c = linebuffer[i];
|
||||||
linebuffer[i] = linebuffer[i + 1];
|
linebuffer[i] = linebuffer[i + 1];
|
||||||
linebuffer[i + 1] = c;
|
linebuffer[i + 1] = c;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
fwrite (linebuffer, lineWidth, 1, file);
|
for (int i = 0; i < lineWidth; i += 4) {
|
||||||
|
std::swap(linebuffer[i], linebuffer[i+3]);
|
||||||
if (pl && !(i % 100)) {
|
std::swap(linebuffer[i+1], linebuffer[i+2]);
|
||||||
pl->setProgress ((double)(i + 1) / height);
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(buffer) {
|
if (TIFFWriteScanline (out, linebuffer, row, 0) < 0) {
|
||||||
delete [] buffer;
|
TIFFClose (out);
|
||||||
}
|
|
||||||
|
|
||||||
if (ferror(file)) {
|
|
||||||
writeOk = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
fclose (file);
|
|
||||||
} else {
|
|
||||||
// little hack to get libTiff to use proper byte order (see TIFFClienOpen()):
|
|
||||||
const char *mode = !exifRoot ? "w" : (exifRoot->getOrder() == rtexif::INTEL ? "wl" : "wb");
|
|
||||||
#ifdef WIN32
|
|
||||||
FILE *file = g_fopen_withBinaryAndLock (fname);
|
|
||||||
int fileno = _fileno(file);
|
|
||||||
int osfileno = _get_osfhandle(fileno);
|
|
||||||
TIFF* out = TIFFFdOpen (osfileno, fname.c_str(), mode);
|
|
||||||
#else
|
|
||||||
TIFF* out = TIFFOpen(fname.c_str(), mode);
|
|
||||||
int fileno = TIFFFileno (out);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (!out) {
|
|
||||||
delete [] linebuffer;
|
delete [] linebuffer;
|
||||||
return IMIO_CANNOTWRITEFILE;
|
return IMIO_CANNOTWRITEFILE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pl) {
|
if (pl && !(row % 100)) {
|
||||||
pl->setProgressStr ("PROGRESSBAR_SAVETIFF");
|
pl->setProgress ((double)(row + 1) / height);
|
||||||
pl->setProgress (0.0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (exifRoot) {
|
|
||||||
rtexif::Tag *tag = exifRoot->getTag (TIFFTAG_EXIFIFD);
|
|
||||||
|
|
||||||
if (tag && tag->isDirectory()) {
|
|
||||||
rtexif::TagDirectory *exif = tag->getDirectory();
|
|
||||||
|
|
||||||
if (exif) {
|
|
||||||
int exif_size = exif->calculateSize();
|
|
||||||
unsigned char *buffer = new unsigned char[exif_size + 8];
|
|
||||||
// TIFFOpen writes out the header and sets file pointer at position 8
|
|
||||||
|
|
||||||
exif->write (8, buffer);
|
|
||||||
|
|
||||||
write (fileno, buffer + 8, exif_size);
|
|
||||||
|
|
||||||
delete [] buffer;
|
|
||||||
// let libtiff know that scanlines or any other following stuff should go
|
|
||||||
// at a different offset:
|
|
||||||
TIFFSetWriteOffset (out, exif_size + 8);
|
|
||||||
TIFFSetField (out, TIFFTAG_EXIFIFD, 8);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//TODO Even though we are saving EXIF IFD - MakerNote still comes out screwed.
|
|
||||||
|
|
||||||
if ((tag = exifRoot->getTag (TIFFTAG_MODEL)) != nullptr) {
|
|
||||||
TIFFSetField (out, TIFFTAG_MODEL, tag->getValue());
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((tag = exifRoot->getTag (TIFFTAG_MAKE)) != nullptr) {
|
|
||||||
TIFFSetField (out, TIFFTAG_MAKE, tag->getValue());
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((tag = exifRoot->getTag (TIFFTAG_DATETIME)) != nullptr) {
|
|
||||||
TIFFSetField (out, TIFFTAG_DATETIME, tag->getValue());
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((tag = exifRoot->getTag (TIFFTAG_ARTIST)) != nullptr) {
|
|
||||||
TIFFSetField (out, TIFFTAG_ARTIST, tag->getValue());
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((tag = exifRoot->getTag (TIFFTAG_COPYRIGHT)) != nullptr) {
|
|
||||||
TIFFSetField (out, TIFFTAG_COPYRIGHT, tag->getValue());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
TIFFSetField (out, TIFFTAG_SOFTWARE, "RawTherapee " RTVERSION);
|
|
||||||
TIFFSetField (out, TIFFTAG_IMAGEWIDTH, width);
|
|
||||||
TIFFSetField (out, TIFFTAG_IMAGELENGTH, height);
|
|
||||||
TIFFSetField (out, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
|
|
||||||
TIFFSetField (out, TIFFTAG_SAMPLESPERPIXEL, 3);
|
|
||||||
TIFFSetField (out, TIFFTAG_ROWSPERSTRIP, height);
|
|
||||||
TIFFSetField (out, TIFFTAG_BITSPERSAMPLE, bps);
|
|
||||||
TIFFSetField (out, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
|
|
||||||
TIFFSetField (out, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_UINT);
|
|
||||||
TIFFSetField (out, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);
|
|
||||||
TIFFSetField (out, TIFFTAG_COMPRESSION, uncompressed ? COMPRESSION_NONE : COMPRESSION_DEFLATE);
|
|
||||||
|
|
||||||
if (!uncompressed) {
|
|
||||||
TIFFSetField (out, TIFFTAG_PREDICTOR, PREDICTOR_NONE);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (profileData) {
|
|
||||||
TIFFSetField (out, TIFFTAG_ICCPROFILE, profileLength, profileData);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int row = 0; row < height; row++) {
|
|
||||||
getScanline (row, linebuffer, bps);
|
|
||||||
|
|
||||||
if (TIFFWriteScanline (out, linebuffer, row, 0) < 0) {
|
|
||||||
TIFFClose (out);
|
|
||||||
delete [] linebuffer;
|
|
||||||
return IMIO_CANNOTWRITEFILE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pl && !(row % 100)) {
|
|
||||||
pl->setProgress ((double)(row + 1) / height);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (TIFFFlush(out) != 1) {
|
|
||||||
writeOk = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
TIFFClose (out);
|
|
||||||
#ifdef WIN32
|
|
||||||
fclose (file);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (TIFFFlush(out) != 1) {
|
||||||
|
writeOk = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
TIFFClose (out);
|
||||||
|
#ifdef WIN32
|
||||||
|
fclose (file);
|
||||||
|
#endif
|
||||||
|
|
||||||
delete [] linebuffer;
|
delete [] linebuffer;
|
||||||
|
|
||||||
if (pl) {
|
if (pl) {
|
||||||
|
@@ -1274,21 +1274,18 @@ void ImProcCoordinator::saveInputICCReference (const Glib::ustring& fname, bool
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Image16* im16 = im->to16();
|
|
||||||
delete im;
|
|
||||||
|
|
||||||
int imw, imh;
|
int imw, imh;
|
||||||
double tmpScale = ipf.resizeScale (¶ms, fW, fH, imw, imh);
|
double tmpScale = ipf.resizeScale (¶ms, fW, fH, imw, imh);
|
||||||
|
|
||||||
if (tmpScale != 1.0) {
|
if (tmpScale != 1.0) {
|
||||||
Image16* tempImage = new Image16 (imw, imh);
|
Imagefloat* tempImage = new Imagefloat (imw, imh);
|
||||||
ipf.resize (im16, tempImage, tmpScale);
|
ipf.resize (im, tempImage, tmpScale);
|
||||||
delete im16;
|
delete im;
|
||||||
im16 = tempImage;
|
im = tempImage;
|
||||||
}
|
}
|
||||||
|
|
||||||
im16->saveTIFF (fname, 16, true);
|
im->saveTIFF (fname, 16, true);
|
||||||
delete im16;
|
delete im;
|
||||||
|
|
||||||
if (plistener) {
|
if (plistener) {
|
||||||
plistener->setProgressState (false);
|
plistener->setProgressState (false);
|
||||||
|
@@ -239,9 +239,9 @@ public:
|
|||||||
void transform (Imagefloat* original, Imagefloat* transformed, int cx, int cy, int sx, int sy, int oW, int oH, int fW, int fH, const FramesMetaData *metadata, int rawRotationDeg, bool fullImage);
|
void transform (Imagefloat* original, Imagefloat* transformed, int cx, int cy, int sx, int sy, int oW, int oH, int fW, int fH, const FramesMetaData *metadata, int rawRotationDeg, bool fullImage);
|
||||||
float resizeScale (const ProcParams* params, int fw, int fh, int &imw, int &imh);
|
float resizeScale (const ProcParams* params, int fw, int fh, int &imw, int &imh);
|
||||||
void lab2monitorRgb (LabImage* lab, Image8* image);
|
void lab2monitorRgb (LabImage* lab, Image8* image);
|
||||||
void resize (Image16* src, Image16* dst, float dScale);
|
void resize (Imagefloat* src, Imagefloat* dst, float dScale);
|
||||||
void Lanczos (const LabImage* src, LabImage* dst, float scale);
|
void Lanczos (const LabImage* src, LabImage* dst, float scale);
|
||||||
void Lanczos (const Image16* src, Image16* dst, float scale);
|
void Lanczos (const Imagefloat* src, Imagefloat* dst, float scale);
|
||||||
|
|
||||||
void deconvsharpening (float** luminance, float** buffer, int W, int H, const SharpeningParams &sharpenParam);
|
void deconvsharpening (float** luminance, float** buffer, int W, int H, const SharpeningParams &sharpenParam);
|
||||||
void MLsharpen (LabImage* lab);// Manuel's clarity / sharpening
|
void MLsharpen (LabImage* lab);// Manuel's clarity / sharpening
|
||||||
@@ -349,7 +349,7 @@ public:
|
|||||||
void localContrast(LabImage *lab);
|
void localContrast(LabImage *lab);
|
||||||
|
|
||||||
Image8* lab2rgb (LabImage* lab, int cx, int cy, int cw, int ch, const procparams::ColorManagementParams &icm);
|
Image8* lab2rgb (LabImage* lab, int cx, int cy, int cw, int ch, const procparams::ColorManagementParams &icm);
|
||||||
Image16* lab2rgb16 (LabImage* lab, int cx, int cy, int cw, int ch, const procparams::ColorManagementParams &icm, GammaValues *ga = nullptr);
|
Imagefloat* lab2rgbOut (LabImage* lab, int cx, int cy, int cw, int ch, const procparams::ColorManagementParams &icm, GammaValues *ga = nullptr);
|
||||||
// CieImage *ciec;
|
// CieImage *ciec;
|
||||||
|
|
||||||
bool transCoord (int W, int H, int x, int y, int w, int h, int& xv, int& yv, int& wv, int& hv, double ascaleDef = -1, const LensCorrection *pLCPMap = nullptr);
|
bool transCoord (int W, int H, int x, int y, int w, int h, int& xv, int& yv, int& wv, int& hv, double ascaleDef = -1, const LensCorrection *pLCPMap = nullptr);
|
||||||
|
@@ -262,7 +262,7 @@ Image8* ImProcFunctions::lab2rgb (LabImage* lab, int cx, int cy, int cw, int ch,
|
|||||||
* If a custom gamma profile can be created, divide by 327.68, convert to xyz and apply the custom gamma transform
|
* If a custom gamma profile can be created, divide by 327.68, convert to xyz and apply the custom gamma transform
|
||||||
* otherwise divide by 327.68, convert to xyz and apply the sRGB transform, before converting with gamma2curve
|
* otherwise divide by 327.68, convert to xyz and apply the sRGB transform, before converting with gamma2curve
|
||||||
*/
|
*/
|
||||||
Image16* ImProcFunctions::lab2rgb16 (LabImage* lab, int cx, int cy, int cw, int ch, const procparams::ColorManagementParams &icm, GammaValues *ga)
|
Imagefloat* ImProcFunctions::lab2rgbOut (LabImage* lab, int cx, int cy, int cw, int ch, const procparams::ColorManagementParams &icm, GammaValues *ga)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (cx < 0) {
|
if (cx < 0) {
|
||||||
@@ -281,7 +281,7 @@ Image16* ImProcFunctions::lab2rgb16 (LabImage* lab, int cx, int cy, int cw, int
|
|||||||
ch = lab->H - cy;
|
ch = lab->H - cy;
|
||||||
}
|
}
|
||||||
|
|
||||||
Image16* image = new Image16 (cw, ch);
|
Imagefloat* image = new Imagefloat (cw, ch);
|
||||||
|
|
||||||
cmsHPROFILE oprof = nullptr;
|
cmsHPROFILE oprof = nullptr;
|
||||||
if (ga) {
|
if (ga) {
|
||||||
@@ -300,11 +300,12 @@ Image16* ImProcFunctions::lab2rgb16 (LabImage* lab, int cx, int cy, int cw, int
|
|||||||
}
|
}
|
||||||
lcmsMutex->lock ();
|
lcmsMutex->lock ();
|
||||||
cmsHPROFILE iprof = cmsCreateLab4Profile(nullptr);
|
cmsHPROFILE iprof = cmsCreateLab4Profile(nullptr);
|
||||||
cmsHTRANSFORM hTransform = cmsCreateTransform (iprof, TYPE_Lab_FLT, oprof, TYPE_RGB_16, icm.outputIntent, flags);
|
cmsHTRANSFORM hTransform = cmsCreateTransform (iprof, TYPE_Lab_FLT, oprof, TYPE_RGB_FLT, icm.outputIntent, flags);
|
||||||
lcmsMutex->unlock ();
|
lcmsMutex->unlock ();
|
||||||
|
|
||||||
image->ExecCMSTransform(hTransform, *lab, cx, cy);
|
image->ExecCMSTransform(hTransform, *lab, cx, cy);
|
||||||
cmsDeleteTransform(hTransform);
|
cmsDeleteTransform(hTransform);
|
||||||
|
image->normalizeFloatTo65535();
|
||||||
} else {
|
} else {
|
||||||
#ifdef _OPENMP
|
#ifdef _OPENMP
|
||||||
#pragma omp parallel for schedule(dynamic,16) if (multiThread)
|
#pragma omp parallel for schedule(dynamic,16) if (multiThread)
|
||||||
@@ -329,9 +330,9 @@ Image16* ImProcFunctions::lab2rgb16 (LabImage* lab, int cx, int cy, int cw, int
|
|||||||
|
|
||||||
Color::xyz2srgb(x_, y_, z_, R, G, B);
|
Color::xyz2srgb(x_, y_, z_, R, G, B);
|
||||||
|
|
||||||
image->r(i - cy, j - cx) = (int)Color::gamma2curve[CLIP(R)];
|
image->r(i - cy, j - cx) = Color::gamma2curve[CLIP(R)];
|
||||||
image->g(i - cy, j - cx) = (int)Color::gamma2curve[CLIP(G)];
|
image->g(i - cy, j - cx) = Color::gamma2curve[CLIP(G)];
|
||||||
image->b(i - cy, j - cx) = (int)Color::gamma2curve[CLIP(B)];
|
image->b(i - cy, j - cx) = Color::gamma2curve[CLIP(B)];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -46,7 +46,7 @@ static inline float Lanc (float x, float a)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImProcFunctions::Lanczos (const Image16* src, Image16* dst, float scale)
|
void ImProcFunctions::Lanczos (const Imagefloat* src, Imagefloat* dst, float scale)
|
||||||
{
|
{
|
||||||
|
|
||||||
const float delta = 1.0f / scale;
|
const float delta = 1.0f / scale;
|
||||||
@@ -159,9 +159,9 @@ void ImProcFunctions::Lanczos (const Image16* src, Image16* dst, float scale)
|
|||||||
b += wh[k] * lb[jj];
|
b += wh[k] * lb[jj];
|
||||||
}
|
}
|
||||||
|
|
||||||
dst->r (i, j) = CLIP (static_cast<int> (r));
|
dst->r (i, j) = CLIP (r);//static_cast<int> (r));
|
||||||
dst->g (i, j) = CLIP (static_cast<int> (g));
|
dst->g (i, j) = CLIP (g);//static_cast<int> (g));
|
||||||
dst->b (i, j) = CLIP (static_cast<int> (b));
|
dst->b (i, j) = CLIP (b);//static_cast<int> (b));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -396,7 +396,7 @@ float ImProcFunctions::resizeScale (const ProcParams* params, int fw, int fh, in
|
|||||||
return (float)dScale;
|
return (float)dScale;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImProcFunctions::resize (Image16* src, Image16* dst, float dScale)
|
void ImProcFunctions::resize (Imagefloat* src, Imagefloat* dst, float dScale)
|
||||||
{
|
{
|
||||||
#ifdef PROFILE
|
#ifdef PROFILE
|
||||||
time_t t1 = clock();
|
time_t t1 = clock();
|
||||||
|
@@ -534,7 +534,7 @@ public:
|
|||||||
* @param errorCode is the error code if an error occured (e.g. the input image could not be loaded etc.)
|
* @param errorCode is the error code if an error occured (e.g. the input image could not be loaded etc.)
|
||||||
* @param pl is an optional ProgressListener if you want to keep track of the progress
|
* @param pl is an optional ProgressListener if you want to keep track of the progress
|
||||||
* @return the resulting image, with the output profile applied, exif and iptc data set. You have to save it or you can access the pixel data directly. */
|
* @return the resulting image, with the output profile applied, exif and iptc data set. You have to save it or you can access the pixel data directly. */
|
||||||
IImage16* processImage (ProcessingJob* job, int& errorCode, ProgressListener* pl = nullptr, bool flush = false);
|
IImagefloat* processImage (ProcessingJob* job, int& errorCode, ProgressListener* pl = nullptr, bool flush = false);
|
||||||
|
|
||||||
/** This class is used to control the batch processing. The class implementing this interface will be called when the full processing of an
|
/** This class is used to control the batch processing. The class implementing this interface will be called when the full processing of an
|
||||||
* image is ready and the next job to process is needed. */
|
* image is ready and the next job to process is needed. */
|
||||||
@@ -545,7 +545,7 @@ public:
|
|||||||
* there is no jobs left.
|
* there is no jobs left.
|
||||||
* @param img is the result of the last ProcessingJob
|
* @param img is the result of the last ProcessingJob
|
||||||
* @return the next ProcessingJob to process */
|
* @return the next ProcessingJob to process */
|
||||||
virtual ProcessingJob* imageReady (IImage16* img) = 0;
|
virtual ProcessingJob* imageReady (IImagefloat* img) = 0;
|
||||||
virtual void error (Glib::ustring message) = 0;
|
virtual void error (Glib::ustring message) = 0;
|
||||||
};
|
};
|
||||||
/** This function performs all the image processinf steps corresponding to the given ProcessingJob. It runs in the background, thus it returns immediately,
|
/** This function performs all the image processinf steps corresponding to the given ProcessingJob. It runs in the background, thus it returns immediately,
|
||||||
|
@@ -65,7 +65,7 @@ public:
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
Image16 *operator()()
|
Imagefloat *operator()()
|
||||||
{
|
{
|
||||||
if (!job->fast) {
|
if (!job->fast) {
|
||||||
return normal_pipeline();
|
return normal_pipeline();
|
||||||
@@ -75,7 +75,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Image16 *normal_pipeline()
|
Imagefloat *normal_pipeline()
|
||||||
{
|
{
|
||||||
if (!stage_init()) {
|
if (!stage_init()) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@@ -86,7 +86,7 @@ private:
|
|||||||
return stage_finish();
|
return stage_finish();
|
||||||
}
|
}
|
||||||
|
|
||||||
Image16 *fast_pipeline()
|
Imagefloat *fast_pipeline()
|
||||||
{
|
{
|
||||||
if (!job->pparams.resize.enabled) {
|
if (!job->pparams.resize.enabled) {
|
||||||
return normal_pipeline();
|
return normal_pipeline();
|
||||||
@@ -832,7 +832,7 @@ private:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Image16 *stage_finish()
|
Imagefloat *stage_finish()
|
||||||
{
|
{
|
||||||
procparams::ProcParams& params = job->pparams;
|
procparams::ProcParams& params = job->pparams;
|
||||||
//ImProcFunctions ipf (¶ms, true);
|
//ImProcFunctions ipf (¶ms, true);
|
||||||
@@ -1228,7 +1228,7 @@ private:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Image16* readyImg = nullptr;
|
Imagefloat* readyImg = nullptr;
|
||||||
cmsHPROFILE jprof = nullptr;
|
cmsHPROFILE jprof = nullptr;
|
||||||
bool customGamma = false;
|
bool customGamma = false;
|
||||||
bool useLCMS = false;
|
bool useLCMS = false;
|
||||||
@@ -1238,7 +1238,7 @@ private:
|
|||||||
|
|
||||||
GammaValues ga;
|
GammaValues ga;
|
||||||
// if(params.blackwhite.enabled) params.toneCurve.hrenabled=false;
|
// if(params.blackwhite.enabled) params.toneCurve.hrenabled=false;
|
||||||
readyImg = ipf.lab2rgb16 (labView, cx, cy, cw, ch, params.icm, &ga);
|
readyImg = ipf.lab2rgbOut (labView, cx, cy, cw, ch, params.icm, &ga);
|
||||||
customGamma = true;
|
customGamma = true;
|
||||||
|
|
||||||
//or selected Free gamma
|
//or selected Free gamma
|
||||||
@@ -1252,7 +1252,7 @@ private:
|
|||||||
// if Default gamma mode: we use the profile selected in the "Output profile" combobox;
|
// if Default gamma mode: we use the profile selected in the "Output profile" combobox;
|
||||||
// gamma come from the selected profile, otherwise it comes from "Free gamma" tool
|
// gamma come from the selected profile, otherwise it comes from "Free gamma" tool
|
||||||
|
|
||||||
readyImg = ipf.lab2rgb16 (labView, cx, cy, cw, ch, params.icm);
|
readyImg = ipf.lab2rgbOut (labView, cx, cy, cw, ch, params.icm);
|
||||||
|
|
||||||
if (settings->verbose) {
|
if (settings->verbose) {
|
||||||
printf ("Output profile_: \"%s\"\n", params.icm.output.c_str());
|
printf ("Output profile_: \"%s\"\n", params.icm.output.c_str());
|
||||||
@@ -1282,7 +1282,7 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (tmpScale != 1.0 && params.resize.method == "Nearest") { // resize rgb data (gamma applied)
|
if (tmpScale != 1.0 && params.resize.method == "Nearest") { // resize rgb data (gamma applied)
|
||||||
Image16* tempImage = new Image16 (imw, imh);
|
Imagefloat* tempImage = new Imagefloat (imw, imh);
|
||||||
ipf.resize (readyImg, tempImage, tmpScale);
|
ipf.resize (readyImg, tempImage, tmpScale);
|
||||||
delete readyImg;
|
delete readyImg;
|
||||||
readyImg = tempImage;
|
readyImg = tempImage;
|
||||||
@@ -1568,7 +1568,7 @@ private:
|
|||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
|
||||||
IImage16* processImage (ProcessingJob* pjob, int& errorCode, ProgressListener* pl, bool flush)
|
IImagefloat* processImage (ProcessingJob* pjob, int& errorCode, ProgressListener* pl, bool flush)
|
||||||
{
|
{
|
||||||
ImageProcessor proc (pjob, errorCode, pl, flush);
|
ImageProcessor proc (pjob, errorCode, pl, flush);
|
||||||
return proc();
|
return proc();
|
||||||
@@ -1581,7 +1581,7 @@ void batchProcessingThread (ProcessingJob* job, BatchProcessingListener* bpl)
|
|||||||
|
|
||||||
while (currentJob) {
|
while (currentJob) {
|
||||||
int errorCode;
|
int errorCode;
|
||||||
IImage16* img = processImage (currentJob, errorCode, bpl, true);
|
IImagefloat* img = processImage (currentJob, errorCode, bpl, true);
|
||||||
|
|
||||||
if (errorCode) {
|
if (errorCode) {
|
||||||
bpl->error (M ("MAIN_MSG_CANNOTLOAD"));
|
bpl->error (M ("MAIN_MSG_CANNOTLOAD"));
|
||||||
|
171
rtexif/rtexif.cc
171
rtexif/rtexif.cc
@@ -739,11 +739,12 @@ void TagDirectory::applyChange (std::string name, Glib::ustring value)
|
|||||||
} else {
|
} else {
|
||||||
const TagAttrib* attrib = nullptr;
|
const TagAttrib* attrib = nullptr;
|
||||||
|
|
||||||
for (int i = 0; attribs[i].ignore != -1; i++)
|
for (int i = 0; attribs[i].ignore != -1; i++) {
|
||||||
if (!strcmp (attribs[i].name, fseg.c_str())) {
|
if (!strcmp (attribs[i].name, fseg.c_str())) {
|
||||||
attrib = &attribs[i];
|
attrib = &attribs[i];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (attrib) {
|
if (attrib) {
|
||||||
Tag* nt = new Tag (this, attrib);
|
Tag* nt = new Tag (this, attrib);
|
||||||
@@ -1663,15 +1664,11 @@ void Tag::toString (char* buffer, int ofs) const
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t maxcount = 4;
|
size_t maxcount = rtengine::min<size_t>(count, 10);
|
||||||
|
|
||||||
if (count < 4) {
|
|
||||||
maxcount = count;
|
|
||||||
}
|
|
||||||
|
|
||||||
strcpy (buffer, "");
|
strcpy (buffer, "");
|
||||||
|
|
||||||
for (ssize_t i = 0; i < std::min<int>(maxcount, valuesize - ofs); i++) {
|
for (ssize_t i = 0; i < rtengine::min<int>(maxcount, valuesize - ofs); i++) {
|
||||||
if (i > 0) {
|
if (i > 0) {
|
||||||
strcat (buffer, ", ");
|
strcat (buffer, ", ");
|
||||||
}
|
}
|
||||||
@@ -1931,22 +1928,48 @@ void Tag::initInt (int data, TagType t, int cnt)
|
|||||||
setInt (data, 0, t);
|
setInt (data, 0, t);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Tag::swapByteOrder2(char *buffer, int count)
|
||||||
|
{
|
||||||
|
char* ptr = buffer;
|
||||||
|
for (int i = 0; i < count; i+=2) {
|
||||||
|
unsigned char c = ptr[0];
|
||||||
|
ptr[0] = ptr[1];
|
||||||
|
ptr[1] = c;
|
||||||
|
ptr += 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
void Tag::initUserComment (const Glib::ustring &text)
|
void Tag::initUserComment (const Glib::ustring &text)
|
||||||
{
|
{
|
||||||
|
const bool useBOM = false; // set it to true if you want to output BOM in UCS-2/UTF-8 UserComments ; this could be turned to an options entry
|
||||||
type = UNDEFINED;
|
type = UNDEFINED;
|
||||||
if (text.is_ascii()) {
|
if (text.is_ascii()) {
|
||||||
count = 8 + strlen (text.c_str());
|
valuesize = count = 8 + strlen (text.c_str());
|
||||||
valuesize = count;
|
|
||||||
value = new unsigned char[valuesize];
|
value = new unsigned char[valuesize];
|
||||||
memcpy((char*)value, "ASCII\0\0\0", 8);
|
memcpy(value, "ASCII\0\0\0", 8);
|
||||||
memcpy((char*)value + 8, text.c_str(), valuesize - 8);
|
memcpy(value + 8, text.c_str(), valuesize - 8);
|
||||||
} else {
|
} else {
|
||||||
wchar_t *commentStr = (wchar_t*)g_utf8_to_utf16 (text.c_str(), -1, NULL, NULL, NULL);
|
wchar_t *commentStr = (wchar_t*)g_utf8_to_utf16 (text.c_str(), -1, nullptr, nullptr, nullptr);
|
||||||
count = 8 + wcslen(commentStr)*2;
|
size_t wcStrSize = wcslen(commentStr);
|
||||||
valuesize = count;
|
valuesize = count = wcStrSize * 2 + 8 + (useBOM ? 2 : 0);
|
||||||
value = (unsigned char*)new char[valuesize];
|
value = new unsigned char[valuesize];
|
||||||
memcpy((char*)value, "UNICODE\0", 8);
|
memcpy(value, "UNICODE\0", 8);
|
||||||
memcpy((char*)value + 8, (char*)commentStr, valuesize - 8);
|
|
||||||
|
if (useBOM) {
|
||||||
|
if (getOrder() == INTEL) { //Little Endian
|
||||||
|
value[8] = 0xFF;
|
||||||
|
value[9] = 0xFE;
|
||||||
|
} else {
|
||||||
|
value[8] = 0xFE;
|
||||||
|
value[9] = 0xFF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Swapping byte order to match the Exif's byte order
|
||||||
|
if (getOrder() != HOSTORDER) {
|
||||||
|
swapByteOrder2((char*)commentStr, wcStrSize * 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(value + 8 + (useBOM ? 2 : 0), (char*)commentStr, wcStrSize * 2);
|
||||||
g_free(commentStr);
|
g_free(commentStr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3197,120 +3220,6 @@ int ExifManager::createJPEGMarker (const TagDirectory* root, const rtengine::pro
|
|||||||
return size + 6;
|
return size + 6;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ExifManager::createTIFFHeader (const TagDirectory* root, const rtengine::procparams::ExifPairs& changeList, int W, int H, int bps, const char* profiledata, int profilelen, const char* iptcdata, int iptclen, unsigned char *&buffer, unsigned &bufferSize)
|
|
||||||
{
|
|
||||||
|
|
||||||
// write tiff header
|
|
||||||
int offs = 0;
|
|
||||||
ByteOrder order = HOSTORDER;
|
|
||||||
|
|
||||||
if (root) {
|
|
||||||
order = root->getOrder ();
|
|
||||||
}
|
|
||||||
|
|
||||||
TagDirectory* cl;
|
|
||||||
|
|
||||||
if (root) {
|
|
||||||
cl = (const_cast<TagDirectory*> (root))->clone (nullptr);
|
|
||||||
// remove some unknown top level tags which produce warnings when opening a tiff
|
|
||||||
Tag *removeTag = cl->getTag (0x9003);
|
|
||||||
|
|
||||||
if (removeTag) {
|
|
||||||
removeTag->setKeep (false);
|
|
||||||
}
|
|
||||||
|
|
||||||
removeTag = cl->getTag (0x9211);
|
|
||||||
|
|
||||||
if (removeTag) {
|
|
||||||
removeTag->setKeep (false);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
cl = new TagDirectory (nullptr, ifdAttribs, HOSTORDER);
|
|
||||||
}
|
|
||||||
|
|
||||||
// add tiff strip data
|
|
||||||
int rps = 8;
|
|
||||||
int strips = ceil ((double)H / rps);
|
|
||||||
cl->replaceTag (new Tag (cl, lookupAttrib (ifdAttribs, "RowsPerStrip"), rps, LONG));
|
|
||||||
Tag* stripBC = new Tag (cl, lookupAttrib (ifdAttribs, "StripByteCounts"));
|
|
||||||
stripBC->initInt (0, LONG, strips);
|
|
||||||
cl->replaceTag (stripBC);
|
|
||||||
Tag* stripOffs = new Tag (cl, lookupAttrib (ifdAttribs, "StripOffsets"));
|
|
||||||
stripOffs->initInt (0, LONG, strips);
|
|
||||||
cl->replaceTag (stripOffs);
|
|
||||||
|
|
||||||
for (int i = 0; i < strips - 1; i++) {
|
|
||||||
stripBC->setInt (rps * W * 3 * bps / 8, i * 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
int remaining = (H - rps * floor ((double)H / rps)) * W * 3 * bps / 8;
|
|
||||||
|
|
||||||
if (remaining) {
|
|
||||||
stripBC->setInt (remaining, (strips - 1) * 4);
|
|
||||||
} else {
|
|
||||||
stripBC->setInt (rps * W * 3 * bps / 8, (strips - 1) * 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (profiledata) {
|
|
||||||
Tag* icc = new Tag (cl, lookupAttrib (ifdAttribs, "ICCProfile"));
|
|
||||||
icc->initUndefArray (profiledata, profilelen);
|
|
||||||
cl->replaceTag (icc);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (iptcdata) {
|
|
||||||
Tag* iptc = new Tag (cl, lookupAttrib (ifdAttribs, "IPTCData"));
|
|
||||||
iptc->initLongArray (iptcdata, iptclen);
|
|
||||||
cl->replaceTag (iptc);
|
|
||||||
}
|
|
||||||
|
|
||||||
// apply list of changes
|
|
||||||
for (rtengine::procparams::ExifPairs::const_iterator i = changeList.begin(); i != changeList.end(); ++i) {
|
|
||||||
cl->applyChange (i->first, i->second);
|
|
||||||
}
|
|
||||||
|
|
||||||
// append default properties
|
|
||||||
const std::vector<Tag*> defTags = getDefaultTIFFTags (cl);
|
|
||||||
|
|
||||||
defTags[0]->setInt (W, 0, LONG);
|
|
||||||
defTags[1]->setInt (H, 0, LONG);
|
|
||||||
defTags[8]->initInt (0, SHORT, 3);
|
|
||||||
|
|
||||||
for (int i = 0; i < 3; i++) {
|
|
||||||
defTags[8]->setInt (bps, i * 2, SHORT);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = defTags.size() - 1; i >= 0; i--) {
|
|
||||||
Tag* defTag = defTags[i];
|
|
||||||
cl->replaceTag (defTag->clone (cl));
|
|
||||||
delete defTag;
|
|
||||||
}
|
|
||||||
|
|
||||||
// calculate strip offsets
|
|
||||||
int size = cl->calculateSize ();
|
|
||||||
int byps = bps / 8;
|
|
||||||
|
|
||||||
for (int i = 0; i < strips; i++) {
|
|
||||||
stripOffs->setInt (size + 8 + i * rps * W * 3 * byps, i * 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
cl->sort ();
|
|
||||||
bufferSize = cl->calculateSize() + 8;
|
|
||||||
buffer = new unsigned char[bufferSize]; // this has to be deleted in caller
|
|
||||||
sset2 ((unsigned short)order, buffer + offs, order);
|
|
||||||
offs += 2;
|
|
||||||
sset2 (42, buffer + offs, order);
|
|
||||||
offs += 2;
|
|
||||||
sset4 (8, buffer + offs, order);
|
|
||||||
|
|
||||||
int endOffs = cl->write (8, buffer);
|
|
||||||
|
|
||||||
// cl->printAll();
|
|
||||||
delete cl;
|
|
||||||
|
|
||||||
return endOffs;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int ExifManager::createPNGMarker(const TagDirectory* root, const rtengine::procparams::ExifPairs &changeList, int W, int H, int bps, const char* iptcdata, int iptclen, unsigned char *&buffer, unsigned &bufferSize)
|
int ExifManager::createPNGMarker(const TagDirectory* root, const rtengine::procparams::ExifPairs &changeList, int W, int H, int bps, const char* iptcdata, int iptclen, unsigned char *&buffer, unsigned &bufferSize)
|
||||||
{
|
{
|
||||||
// write tiff header
|
// write tiff header
|
||||||
|
@@ -236,6 +236,8 @@ public:
|
|||||||
void initLongArray (const char* data, int len);
|
void initLongArray (const char* data, int len);
|
||||||
void initRational (int num, int den);
|
void initRational (int num, int den);
|
||||||
|
|
||||||
|
static void swapByteOrder2 (char *buffer, int count);
|
||||||
|
|
||||||
// get basic tag properties
|
// get basic tag properties
|
||||||
int getID () const
|
int getID () const
|
||||||
{
|
{
|
||||||
|
@@ -452,12 +452,109 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
count = std::min (count, 65535); // limit to 65535 chars to avoid crashes in case of corrupted metadata
|
count = std::min (count, 65535); // limit to 65535 chars to avoid crashes in case of corrupted metadata
|
||||||
char *buffer = new char[count - 7];
|
char *buffer = new char[count - 6]; // include 2 ending null chars for UCS-2 string (possibly)
|
||||||
|
char *value = (char*)t->getValue();
|
||||||
|
|
||||||
if (!memcmp ((char*)t->getValue(), "ASCII\0\0\0", 8)) {
|
if (!memcmp(value, "ASCII\0\0\0", 8)) {
|
||||||
strncpy (buffer, (char*)t->getValue() + 8, count - 8);
|
memcpy(buffer, value + 8, count - 8);
|
||||||
buffer[count - 8] = '\0';
|
buffer[count - 8] = '\0';
|
||||||
|
} else if (!memcmp(value, "UNICODE\0", 8)) {
|
||||||
|
memcpy(buffer, value + 8, count - 8);
|
||||||
|
buffer[count - 7] = buffer[count - 8] = '\0';
|
||||||
|
Glib::ustring tmp1(buffer);
|
||||||
|
|
||||||
|
|
||||||
|
bool hasBOM = false;
|
||||||
|
enum ByteOrder bo = UNKNOWN;
|
||||||
|
if (count % 2 || (count >= 11 && (buffer[0] == 0xEF && buffer[1] == 0xBB && buffer[2] == 0xBF))) {
|
||||||
|
// odd string length can only be UTF-8, don't change anything
|
||||||
|
std::string retVal (buffer + 3);
|
||||||
|
delete [] buffer;
|
||||||
|
return retVal;
|
||||||
|
} else if (count >= 10) {
|
||||||
|
if (buffer[0] == 0xFF && buffer[1] == 0xFE) {
|
||||||
|
bo = INTEL; // little endian
|
||||||
|
hasBOM = true;
|
||||||
|
} else if (buffer[0] == 0xFE && buffer[1] == 0xFF) {
|
||||||
|
bo = MOTOROLA; // big endian
|
||||||
|
hasBOM = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (bo == UNKNOWN) {
|
||||||
|
// auto-detecting byte order; we still don't know if it's UCS-2 or UTF-8
|
||||||
|
int a = 0, b = 0, c = 0, d = 0;
|
||||||
|
for (int j = 8; j < count; j++) {
|
||||||
|
char cc = value[j];
|
||||||
|
if (!(j%2)) {
|
||||||
|
// counting zeros for first byte
|
||||||
|
if (!cc) {
|
||||||
|
++a;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// counting zeros for second byte
|
||||||
|
if (!cc) {
|
||||||
|
++b;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!(cc & 0x80) || ((cc & 0xC0) == 0xC0) || ((cc & 0xC0) == 0x80)) {
|
||||||
|
++c;
|
||||||
|
}
|
||||||
|
if ((cc & 0xC0) == 0x80) {
|
||||||
|
++d;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (c == (count - 8) && d) {
|
||||||
|
// this is an UTF-8 string
|
||||||
|
std::string retVal (buffer);
|
||||||
|
delete [] buffer;
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
if ((a || b) && a != b) {
|
||||||
|
bo = a > b ? MOTOROLA : INTEL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (bo == UNKNOWN) {
|
||||||
|
// assuming platform's byte order
|
||||||
|
#if __BYTE_ORDER__==__ORDER_LITTLE_ENDIAN__
|
||||||
|
bo = INTEL;
|
||||||
|
#else
|
||||||
|
bo = MOTOROLA;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// now swapping if necessary
|
||||||
|
if (!hasBOM && bo != HOSTORDER) {
|
||||||
|
if (t->getOrder() != HOSTORDER) {
|
||||||
|
Tag::swapByteOrder2(buffer, count - 8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
glong written;
|
||||||
|
char* utf8Str = g_utf16_to_utf8((unsigned short int*)buffer, -1, nullptr, &written, nullptr);
|
||||||
|
delete [] buffer;
|
||||||
|
buffer = new char[written + 1];
|
||||||
|
memcpy(buffer, utf8Str, written);
|
||||||
|
buffer[written] = 0;
|
||||||
|
} else if (!memcmp(value, "\0\0\0\0\0\0\0\0", 8)) {
|
||||||
|
// local charset string, whatever it is
|
||||||
|
memcpy(buffer, value + 8, count - 8);
|
||||||
|
buffer[count - 7] = buffer[count - 8] = '\0';
|
||||||
|
|
||||||
|
gsize written = 0;
|
||||||
|
char *utf8Str = g_locale_to_utf8(buffer, count - 8, nullptr, &written, nullptr);
|
||||||
|
if (utf8Str && written) {
|
||||||
|
delete [] buffer;
|
||||||
|
size_t length = strlen(utf8Str);
|
||||||
|
buffer = new char[length + 1];
|
||||||
|
strcpy(buffer, utf8Str);
|
||||||
|
} else {
|
||||||
|
buffer[0] = 0;
|
||||||
|
}
|
||||||
|
if (utf8Str) {
|
||||||
|
g_free(utf8Str);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
|
// JIS: unsupported
|
||||||
buffer[0] = 0;
|
buffer[0] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -467,11 +564,8 @@ public:
|
|||||||
}
|
}
|
||||||
virtual void fromString (Tag* t, const std::string& value)
|
virtual void fromString (Tag* t, const std::string& value)
|
||||||
{
|
{
|
||||||
char *buffer = new char[t->getCount()];
|
Glib::ustring tmpStr(value);
|
||||||
memcpy (buffer, "ASCII\0\0\0", 8);
|
t->userCommentFromString (tmpStr);
|
||||||
strcpy (buffer + 8, value.c_str());
|
|
||||||
t->fromString (buffer, value.size() + 9);
|
|
||||||
delete [] buffer;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
UserCommentInterpreter userCommentInterpreter;
|
UserCommentInterpreter userCommentInterpreter;
|
||||||
@@ -809,10 +903,10 @@ const TagAttrib ifdAttribs[] = {
|
|||||||
{0, AC_WRITE, 0, nullptr, 0x828e, AUTO, "CFAPattern", &cfaInterpreter},
|
{0, AC_WRITE, 0, nullptr, 0x828e, AUTO, "CFAPattern", &cfaInterpreter},
|
||||||
{0, AC_WRITE, 0, kodakIfdAttribs, 0x8290, AUTO, "KodakIFD", &stdInterpreter},
|
{0, AC_WRITE, 0, kodakIfdAttribs, 0x8290, AUTO, "KodakIFD", &stdInterpreter},
|
||||||
{0, AC_WRITE, 1, nullptr, 0x8298, AUTO, "Copyright", &stdInterpreter},
|
{0, AC_WRITE, 1, nullptr, 0x8298, AUTO, "Copyright", &stdInterpreter},
|
||||||
|
{0, AC_SYSTEM, 0, nullptr, 0x83BB, AUTO, "IPTCData", &stdInterpreter},
|
||||||
{0, AC_DONTWRITE, 0, nullptr, 0x8606, AUTO, "LeafData", &stdInterpreter}, // is actually a subdir, but a proprietary format
|
{0, AC_DONTWRITE, 0, nullptr, 0x8606, AUTO, "LeafData", &stdInterpreter}, // is actually a subdir, but a proprietary format
|
||||||
{0, AC_WRITE, 0, exifAttribs, 0x8769, AUTO, "Exif", &stdInterpreter},
|
{0, AC_WRITE, 0, exifAttribs, 0x8769, AUTO, "Exif", &stdInterpreter},
|
||||||
{0, AC_SYSTEM, 0, nullptr, 0x8773, AUTO, "ICCProfile", &stdInterpreter},
|
{0, AC_SYSTEM, 0, nullptr, 0x8773, AUTO, "ICCProfile", &stdInterpreter},
|
||||||
{0, AC_SYSTEM, 0, nullptr, 0x83BB, AUTO, "IPTCData", &stdInterpreter},
|
|
||||||
{0, AC_WRITE, 0, gpsAttribs, 0x8825, AUTO, "GPSInfo", &stdInterpreter},
|
{0, AC_WRITE, 0, gpsAttribs, 0x8825, AUTO, "GPSInfo", &stdInterpreter},
|
||||||
{0, AC_WRITE, 0, nullptr, 0x9003, AUTO, "DateTimeOriginal", &stdInterpreter},
|
{0, AC_WRITE, 0, nullptr, 0x9003, AUTO, "DateTimeOriginal", &stdInterpreter},
|
||||||
{0, AC_WRITE, 0, nullptr, 0x9004, AUTO, "DateTimeDigitized", &stdInterpreter},
|
{0, AC_WRITE, 0, nullptr, 0x9004, AUTO, "DateTimeDigitized", &stdInterpreter},
|
||||||
|
@@ -578,7 +578,7 @@ void BatchQueue::startProcessing ()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
rtengine::ProcessingJob* BatchQueue::imageReady (rtengine::IImage16* img)
|
rtengine::ProcessingJob* BatchQueue::imageReady (rtengine::IImagefloat* img)
|
||||||
{
|
{
|
||||||
|
|
||||||
// save image img
|
// save image img
|
||||||
|
@@ -62,7 +62,7 @@ public:
|
|||||||
return (!fd.empty());
|
return (!fd.empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
rtengine::ProcessingJob* imageReady (rtengine::IImage16* img);
|
rtengine::ProcessingJob* imageReady (rtengine::IImagefloat* img);
|
||||||
void error (Glib::ustring msg);
|
void error (Glib::ustring msg);
|
||||||
void setProgress (double p);
|
void setProgress (double p);
|
||||||
void rightClicked (ThumbBrowserEntryBase* entry);
|
void rightClicked (ThumbBrowserEntryBase* entry);
|
||||||
|
@@ -1772,9 +1772,9 @@ void EditorPanel::procParamsChanged (Thumbnail* thm, int whoChangedIt)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool EditorPanel::idle_saveImage (ProgressConnector<rtengine::IImage16*> *pc, Glib::ustring fname, SaveFormat sf, rtengine::procparams::ProcParams &pparams)
|
bool EditorPanel::idle_saveImage (ProgressConnector<rtengine::IImagefloat*> *pc, Glib::ustring fname, SaveFormat sf, rtengine::procparams::ProcParams &pparams)
|
||||||
{
|
{
|
||||||
rtengine::IImage16* img = pc->returnValue();
|
rtengine::IImagefloat* img = pc->returnValue();
|
||||||
delete pc;
|
delete pc;
|
||||||
|
|
||||||
if ( img ) {
|
if ( img ) {
|
||||||
@@ -1785,13 +1785,13 @@ bool EditorPanel::idle_saveImage (ProgressConnector<rtengine::IImage16*> *pc, Gl
|
|||||||
img->setSaveProgressListener (parent->getProgressListener());
|
img->setSaveProgressListener (parent->getProgressListener());
|
||||||
|
|
||||||
if (sf.format == "tif")
|
if (sf.format == "tif")
|
||||||
ld->startFunc (sigc::bind (sigc::mem_fun (img, &rtengine::IImage16::saveAsTIFF), fname, sf.tiffBits, sf.tiffUncompressed),
|
ld->startFunc (sigc::bind (sigc::mem_fun (img, &rtengine::IImagefloat::saveAsTIFF), fname, sf.tiffBits, sf.tiffUncompressed),
|
||||||
sigc::bind (sigc::mem_fun (*this, &EditorPanel::idle_imageSaved), ld, img, fname, sf, pparams));
|
sigc::bind (sigc::mem_fun (*this, &EditorPanel::idle_imageSaved), ld, img, fname, sf, pparams));
|
||||||
else if (sf.format == "png")
|
else if (sf.format == "png")
|
||||||
ld->startFunc (sigc::bind (sigc::mem_fun (img, &rtengine::IImage16::saveAsPNG), fname, sf.pngBits),
|
ld->startFunc (sigc::bind (sigc::mem_fun (img, &rtengine::IImagefloat::saveAsPNG), fname, sf.pngBits),
|
||||||
sigc::bind (sigc::mem_fun (*this, &EditorPanel::idle_imageSaved), ld, img, fname, sf, pparams));
|
sigc::bind (sigc::mem_fun (*this, &EditorPanel::idle_imageSaved), ld, img, fname, sf, pparams));
|
||||||
else if (sf.format == "jpg")
|
else if (sf.format == "jpg")
|
||||||
ld->startFunc (sigc::bind (sigc::mem_fun (img, &rtengine::IImage16::saveAsJPEG), fname, sf.jpegQuality, sf.jpegSubSamp),
|
ld->startFunc (sigc::bind (sigc::mem_fun (img, &rtengine::IImagefloat::saveAsJPEG), fname, sf.jpegQuality, sf.jpegSubSamp),
|
||||||
sigc::bind (sigc::mem_fun (*this, &EditorPanel::idle_imageSaved), ld, img, fname, sf, pparams));
|
sigc::bind (sigc::mem_fun (*this, &EditorPanel::idle_imageSaved), ld, img, fname, sf, pparams));
|
||||||
else {
|
else {
|
||||||
delete ld;
|
delete ld;
|
||||||
@@ -1812,7 +1812,7 @@ bool EditorPanel::idle_saveImage (ProgressConnector<rtengine::IImage16*> *pc, Gl
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool EditorPanel::idle_imageSaved (ProgressConnector<int> *pc, rtengine::IImage16* img, Glib::ustring fname, SaveFormat sf, rtengine::procparams::ProcParams &pparams)
|
bool EditorPanel::idle_imageSaved (ProgressConnector<int> *pc, rtengine::IImagefloat* img, Glib::ustring fname, SaveFormat sf, rtengine::procparams::ProcParams &pparams)
|
||||||
{
|
{
|
||||||
img->free ();
|
img->free ();
|
||||||
|
|
||||||
@@ -1937,7 +1937,7 @@ void EditorPanel::saveAsPressed ()
|
|||||||
ipc->getParams (&pparams);
|
ipc->getParams (&pparams);
|
||||||
rtengine::ProcessingJob* job = rtengine::ProcessingJob::create (ipc->getInitialImage(), pparams);
|
rtengine::ProcessingJob* job = rtengine::ProcessingJob::create (ipc->getInitialImage(), pparams);
|
||||||
|
|
||||||
ProgressConnector<rtengine::IImage16*> *ld = new ProgressConnector<rtengine::IImage16*>();
|
ProgressConnector<rtengine::IImagefloat*> *ld = new ProgressConnector<rtengine::IImagefloat*>();
|
||||||
ld->startFunc (sigc::bind (sigc::ptr_fun (&rtengine::processImage), job, err, parent->getProgressListener(), false ),
|
ld->startFunc (sigc::bind (sigc::ptr_fun (&rtengine::processImage), job, err, parent->getProgressListener(), false ),
|
||||||
sigc::bind (sigc::mem_fun ( *this, &EditorPanel::idle_saveImage ), ld, fnameOut, sf, pparams));
|
sigc::bind (sigc::mem_fun ( *this, &EditorPanel::idle_saveImage ), ld, fnameOut, sf, pparams));
|
||||||
saveimgas->set_sensitive (false);
|
saveimgas->set_sensitive (false);
|
||||||
@@ -1981,7 +1981,7 @@ void EditorPanel::sendToGimpPressed ()
|
|||||||
rtengine::procparams::ProcParams pparams;
|
rtengine::procparams::ProcParams pparams;
|
||||||
ipc->getParams (&pparams);
|
ipc->getParams (&pparams);
|
||||||
rtengine::ProcessingJob* job = rtengine::ProcessingJob::create (ipc->getInitialImage(), pparams);
|
rtengine::ProcessingJob* job = rtengine::ProcessingJob::create (ipc->getInitialImage(), pparams);
|
||||||
ProgressConnector<rtengine::IImage16*> *ld = new ProgressConnector<rtengine::IImage16*>();
|
ProgressConnector<rtengine::IImagefloat*> *ld = new ProgressConnector<rtengine::IImagefloat*>();
|
||||||
ld->startFunc (sigc::bind (sigc::ptr_fun (&rtengine::processImage), job, err, parent->getProgressListener(), false ),
|
ld->startFunc (sigc::bind (sigc::ptr_fun (&rtengine::processImage), job, err, parent->getProgressListener(), false ),
|
||||||
sigc::bind (sigc::mem_fun ( *this, &EditorPanel::idle_sendToGimp ), ld, openThm->getFileName() ));
|
sigc::bind (sigc::mem_fun ( *this, &EditorPanel::idle_sendToGimp ), ld, openThm->getFileName() ));
|
||||||
saveimgas->set_sensitive (false);
|
saveimgas->set_sensitive (false);
|
||||||
@@ -1996,7 +1996,7 @@ bool EditorPanel::saveImmediately (const Glib::ustring &filename, const SaveForm
|
|||||||
rtengine::ProcessingJob *job = rtengine::ProcessingJob::create (ipc->getInitialImage(), pparams);
|
rtengine::ProcessingJob *job = rtengine::ProcessingJob::create (ipc->getInitialImage(), pparams);
|
||||||
|
|
||||||
// save immediately
|
// save immediately
|
||||||
rtengine::IImage16 *img = rtengine::processImage (job, err, nullptr, false);
|
rtengine::IImagefloat *img = rtengine::processImage (job, err, nullptr, false);
|
||||||
|
|
||||||
int err = 0;
|
int err = 0;
|
||||||
|
|
||||||
@@ -2042,10 +2042,10 @@ void EditorPanel::histogramProfile_toggled()
|
|||||||
colorMgmtToolBar->updateHistogram();
|
colorMgmtToolBar->updateHistogram();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool EditorPanel::idle_sendToGimp ( ProgressConnector<rtengine::IImage16*> *pc, Glib::ustring fname)
|
bool EditorPanel::idle_sendToGimp ( ProgressConnector<rtengine::IImagefloat*> *pc, Glib::ustring fname)
|
||||||
{
|
{
|
||||||
|
|
||||||
rtengine::IImage16* img = pc->returnValue();
|
rtengine::IImagefloat* img = pc->returnValue();
|
||||||
delete pc;
|
delete pc;
|
||||||
|
|
||||||
if (img) {
|
if (img) {
|
||||||
@@ -2077,7 +2077,7 @@ bool EditorPanel::idle_sendToGimp ( ProgressConnector<rtengine::IImage16*> *pc,
|
|||||||
|
|
||||||
ProgressConnector<int> *ld = new ProgressConnector<int>();
|
ProgressConnector<int> *ld = new ProgressConnector<int>();
|
||||||
img->setSaveProgressListener (parent->getProgressListener());
|
img->setSaveProgressListener (parent->getProgressListener());
|
||||||
ld->startFunc (sigc::bind (sigc::mem_fun (img, &rtengine::IImage16::saveAsTIFF), fileName, sf.tiffBits, sf.tiffUncompressed),
|
ld->startFunc (sigc::bind (sigc::mem_fun (img, &rtengine::IImagefloat::saveAsTIFF), fileName, sf.tiffBits, sf.tiffUncompressed),
|
||||||
sigc::bind (sigc::mem_fun (*this, &EditorPanel::idle_sentToGimp), ld, img, fileName));
|
sigc::bind (sigc::mem_fun (*this, &EditorPanel::idle_sentToGimp), ld, img, fileName));
|
||||||
} else {
|
} else {
|
||||||
Glib::ustring msg_ = Glib::ustring ("<b> Error during image processing\n</b>");
|
Glib::ustring msg_ = Glib::ustring ("<b> Error during image processing\n</b>");
|
||||||
@@ -2090,7 +2090,7 @@ bool EditorPanel::idle_sendToGimp ( ProgressConnector<rtengine::IImage16*> *pc,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool EditorPanel::idle_sentToGimp (ProgressConnector<int> *pc, rtengine::IImage16* img, Glib::ustring filename)
|
bool EditorPanel::idle_sentToGimp (ProgressConnector<int> *pc, rtengine::IImagefloat* img, Glib::ustring filename)
|
||||||
{
|
{
|
||||||
img->free ();
|
img->free ();
|
||||||
int errore = pc->returnValue();
|
int errore = pc->returnValue();
|
||||||
|
@@ -146,10 +146,10 @@ private:
|
|||||||
void close ();
|
void close ();
|
||||||
|
|
||||||
BatchQueueEntry* createBatchQueueEntry ();
|
BatchQueueEntry* createBatchQueueEntry ();
|
||||||
bool idle_imageSaved (ProgressConnector<int> *pc, rtengine::IImage16* img, Glib::ustring fname, SaveFormat sf, rtengine::procparams::ProcParams &pparams);
|
bool idle_imageSaved (ProgressConnector<int> *pc, rtengine::IImagefloat* img, Glib::ustring fname, SaveFormat sf, rtengine::procparams::ProcParams &pparams);
|
||||||
bool idle_saveImage (ProgressConnector<rtengine::IImage16*> *pc, Glib::ustring fname, SaveFormat sf, rtengine::procparams::ProcParams &pparams);
|
bool idle_saveImage (ProgressConnector<rtengine::IImagefloat*> *pc, Glib::ustring fname, SaveFormat sf, rtengine::procparams::ProcParams &pparams);
|
||||||
bool idle_sendToGimp ( ProgressConnector<rtengine::IImage16*> *pc, Glib::ustring fname);
|
bool idle_sendToGimp ( ProgressConnector<rtengine::IImagefloat*> *pc, Glib::ustring fname);
|
||||||
bool idle_sentToGimp (ProgressConnector<int> *pc, rtengine::IImage16* img, Glib::ustring filename);
|
bool idle_sentToGimp (ProgressConnector<int> *pc, rtengine::IImagefloat* img, Glib::ustring filename);
|
||||||
void histogramProfile_toggled ();
|
void histogramProfile_toggled ();
|
||||||
|
|
||||||
|
|
||||||
|
@@ -822,7 +822,7 @@ int processLineParams ( int argc, char **argv )
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Process image
|
// Process image
|
||||||
rtengine::IImage16* resultImage = rtengine::processImage (job, errorCode, nullptr);
|
rtengine::IImagefloat* resultImage = rtengine::processImage (job, errorCode, nullptr);
|
||||||
|
|
||||||
if ( !resultImage ) {
|
if ( !resultImage ) {
|
||||||
errors++;
|
errors++;
|
||||||
|
@@ -40,14 +40,16 @@ SaveFormatPanel::SaveFormatPanel () : listener (nullptr)
|
|||||||
format->append ("JPEG (8 bit)");
|
format->append ("JPEG (8 bit)");
|
||||||
format->append ("TIFF (8 bit)");
|
format->append ("TIFF (8 bit)");
|
||||||
format->append ("TIFF (16 bit)");
|
format->append ("TIFF (16 bit)");
|
||||||
|
format->append ("TIFF (32 bit float)");
|
||||||
format->append ("PNG (8 bit)");
|
format->append ("PNG (8 bit)");
|
||||||
format->append ("PNG (16 bit)");
|
format->append ("PNG (16 bit)");
|
||||||
|
|
||||||
fstr[0] = "jpg";
|
fstr[0] = "jpg";
|
||||||
fstr[1] = "tif";
|
fstr[1] = "tif";
|
||||||
fstr[2] = "tif";
|
fstr[2] = "tif";
|
||||||
fstr[3] = "png";
|
fstr[3] = "tif";
|
||||||
fstr[4] = "png";
|
fstr[4] = "png";
|
||||||
|
fstr[5] = "png";
|
||||||
|
|
||||||
hb1->attach (*flab, 0, 0, 1, 1);
|
hb1->attach (*flab, 0, 0, 1, 1);
|
||||||
hb1->attach (*format, 1, 0, 1, 1);
|
hb1->attach (*format, 1, 0, 1, 1);
|
||||||
@@ -121,8 +123,10 @@ void SaveFormatPanel::init (SaveFormat &sf)
|
|||||||
if (sf.format == "jpg") {
|
if (sf.format == "jpg") {
|
||||||
format->set_active (0);
|
format->set_active (0);
|
||||||
} else if (sf.format == "png" && sf.pngBits == 16) {
|
} else if (sf.format == "png" && sf.pngBits == 16) {
|
||||||
format->set_active (4);
|
format->set_active (5);
|
||||||
} else if (sf.format == "png" && sf.pngBits == 8) {
|
} else if (sf.format == "png" && sf.pngBits == 8) {
|
||||||
|
format->set_active (4);
|
||||||
|
} else if (sf.format == "tif" && sf.tiffBits == 32) {
|
||||||
format->set_active (3);
|
format->set_active (3);
|
||||||
} else if (sf.format == "tif" && sf.tiffBits == 16) {
|
} else if (sf.format == "tif" && sf.tiffBits == 16) {
|
||||||
format->set_active (2);
|
format->set_active (2);
|
||||||
@@ -146,7 +150,7 @@ SaveFormat SaveFormatPanel::getFormat ()
|
|||||||
int sel = format->get_active_row_number();
|
int sel = format->get_active_row_number();
|
||||||
sf.format = fstr[sel];
|
sf.format = fstr[sel];
|
||||||
|
|
||||||
if (sel == 4) {
|
if (sel == 5) {
|
||||||
sf.pngBits = 16;
|
sf.pngBits = 16;
|
||||||
} else {
|
} else {
|
||||||
sf.pngBits = 8;
|
sf.pngBits = 8;
|
||||||
@@ -154,6 +158,8 @@ SaveFormat SaveFormatPanel::getFormat ()
|
|||||||
|
|
||||||
if (sel == 2) {
|
if (sel == 2) {
|
||||||
sf.tiffBits = 16;
|
sf.tiffBits = 16;
|
||||||
|
} else if (sel == 3) {
|
||||||
|
sf.tiffBits = 32;
|
||||||
} else {
|
} else {
|
||||||
sf.tiffBits = 8;
|
sf.tiffBits = 8;
|
||||||
}
|
}
|
||||||
|
@@ -44,7 +44,7 @@ protected:
|
|||||||
Gtk::Grid* jpegOpts;
|
Gtk::Grid* jpegOpts;
|
||||||
Gtk::Label* jpegSubSampLabel;
|
Gtk::Label* jpegSubSampLabel;
|
||||||
FormatChangeListener* listener;
|
FormatChangeListener* listener;
|
||||||
Glib::ustring fstr[5];
|
Glib::ustring fstr[6];
|
||||||
Gtk::CheckButton* savesPP;
|
Gtk::CheckButton* savesPP;
|
||||||
|
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user