File indexing completed on 2025-01-05 03:56:01

0001 /* ============================================================
0002  *
0003  * This file is a part of digiKam project
0004  * https://www.digikam.org
0005  *
0006  * Date        : 2008-09-25
0007  * Description : a tool to convert RAW file to DNG - Makernotes storage.
0008  *
0009  * SPDX-FileCopyrightText: 2008-2024 by Gilles Caulier <caulier dot gilles at gmail dot com>
0010  * SPDX-FileCopyrightText: 2010-2011 by Jens Mueller <tschenser at gmx dot de>
0011  *
0012  * SPDX-License-Identifier: GPL-2.0-or-later
0013  *
0014  * ============================================================ */
0015 
0016 #include "dngwriter_p.h"
0017 
0018 // Local includes
0019 
0020 #include "dngwriterhost.h"
0021 
0022 namespace Digikam
0023 {
0024 
0025 int DNGWriter::Private::storeMakernote(DNGWriterHost& host,
0026                                        AutoPtr<dng_negative>& negative,
0027                                        DRawInfo* const identify,
0028                                        DRawInfo* const identifyMake,
0029                                        DMetadata* const meta)
0030 {
0031     if (metaLoaded)     // We only process Makernote storage if Metadata can be loaded at Exif stage.
0032     {
0033         qCDebug(DIGIKAM_GENERAL_LOG) << "DNGWriter: Updating Makernote metadata to DNG Negative";
0034 
0035         backportNikonMakerNote(meta);
0036         backportCanonMakerNote(meta);
0037         backportPentaxMakerNote(meta);
0038         backportOlympusMakerNote(meta);
0039         backportPanasonicMakerNote(meta);
0040         backportSonyMakerNote(meta);
0041         storeLensInformation();
0042         backupMakernote(host, negative, identify, identifyMake, meta);
0043     }
0044 
0045     if (cancel)
0046     {
0047         return PROCESS_CANCELED;
0048     }
0049 
0050     return PROCESS_CONTINUE;
0051 }
0052 
0053 void DNGWriter::Private::backportNikonMakerNote(DMetadata* const meta)
0054 {
0055     QString  str;
0056     long int num, den;
0057     long     val;
0058 
0059     if (meta->getExifTagRational("Exif.Nikon3.Lens", num, den, 0))              exif->fLensInfo[0]              = dng_urational(num, den);
0060     if (meta->getExifTagRational("Exif.Nikon3.Lens", num, den, 1))              exif->fLensInfo[1]              = dng_urational(num, den);
0061     if (meta->getExifTagRational("Exif.Nikon3.Lens", num, den, 2))              exif->fLensInfo[2]              = dng_urational(num, den);
0062     if (meta->getExifTagRational("Exif.Nikon3.Lens", num, den, 3))              exif->fLensInfo[3]              = dng_urational(num, den);
0063     if (meta->getExifTagLong("Exif.Nikon3.ISOSpeed", val, 1))                   exif->fISOSpeedRatings[1]       = (uint32)val;
0064 
0065     str = meta->getExifTagString("Exif.Nikon3.SerialNO");
0066     if (!str.isEmpty()) str = str.replace(QLatin1String("NO="), QLatin1String(""));
0067     if (!str.isEmpty()) exif->fCameraSerialNumber.Set_ASCII(str.trimmed().toLatin1().constData());
0068 
0069     str = meta->getExifTagString("Exif.Nikon3.SerialNumber");
0070     if (!str.isEmpty()) exif->fCameraSerialNumber.Set_ASCII(str.toLatin1().constData());
0071 
0072     if (meta->getExifTagLong("Exif.Nikon3.ShutterCount", val))                  exif->fImageNumber              = (uint32)val;
0073     if (meta->getExifTagLong("Exif.NikonLd1.LensIDNumber", val))                exif->fLensID.Set_ASCII((QString::fromUtf8("%1").arg(val)).toLatin1().constData());
0074     if (meta->getExifTagLong("Exif.NikonLd2.LensIDNumber", val))                exif->fLensID.Set_ASCII((QString::fromUtf8("%1").arg(val)).toLatin1().constData());
0075     if (meta->getExifTagLong("Exif.NikonLd3.LensIDNumber", val))                exif->fLensID.Set_ASCII((QString::fromUtf8("%1").arg(val)).toLatin1().constData());
0076     if (meta->getExifTagLong("Exif.NikonLd2.FocusDistance", val))               exif->fSubjectDistance          = dng_urational((uint32)pow(10.0, val/40.0), 100);
0077     if (meta->getExifTagLong("Exif.NikonLd3.FocusDistance", val))               exif->fSubjectDistance          = dng_urational((uint32)pow(10.0, val/40.0), 100);
0078     str = meta->getExifTagString("Exif.NikonLd1.LensIDNumber");
0079     if (!str.isEmpty()) exif->fLensName.Set_ASCII(str.trimmed().toLatin1().constData());
0080     str = meta->getExifTagString("Exif.NikonLd2.LensIDNumber");
0081     if (!str.isEmpty()) exif->fLensName.Set_ASCII(str.trimmed().toLatin1().constData());
0082     str = meta->getExifTagString("Exif.NikonLd3.LensIDNumber");
0083     if (!str.isEmpty()) exif->fLensName.Set_ASCII(str.trimmed().toLatin1().constData());
0084 }
0085 
0086 void DNGWriter::Private::backportCanonMakerNote(DMetadata* const meta)
0087 {
0088     QString  str;
0089     long int num, den;
0090     long     val;
0091 
0092     if (meta->getExifTagLong("Exif.Canon.SerialNumber", val))                   exif->fCameraSerialNumber.Set_ASCII((QString::fromUtf8("%1").arg(val)).toLatin1().constData());
0093 /*
0094     if (meta->getExifTagLong("Exif.CanonCs.FlashActivity", val))                exif->fFlash                    = (uint32)val;
0095     if (meta->getExifTagLong("Exif.CanonFi.FileNumber", val))                   exif->fImageNumber              = (uint32)val;
0096     if (meta->getExifTagLong("Exif.CanonCs.MaxAperture", val))                  exif->fMaxApertureValue         = dng_urational(val, 100000);
0097 */
0098     if (meta->getExifTagLong("Exif.CanonCs.ExposureProgram", val))
0099     {
0100         switch (val)
0101         {
0102             case 1:
0103             {
0104                 exif->fExposureProgram = 2;
0105                 break;
0106             }
0107 
0108             case 2:
0109             {
0110                 exif->fExposureProgram = 4;
0111                 break;
0112             }
0113 
0114             case 3:
0115             {
0116                 exif->fExposureProgram = 3;
0117                 break;
0118             }
0119 
0120             case 4:
0121             {
0122                 exif->fExposureProgram = 1;
0123                 break;
0124             }
0125 
0126             default:
0127             {
0128                 break;
0129             }
0130         }
0131     }
0132 
0133     if (meta->getExifTagLong("Exif.CanonCs.MeteringMode", val))
0134     {
0135         switch (val)
0136         {
0137             case 1:
0138             {
0139                 exif->fMeteringMode = 3;
0140                 break;
0141             }
0142 
0143             case 2:
0144             {
0145                 exif->fMeteringMode = 1;
0146                 break;
0147             }
0148 
0149             case 3:
0150             {
0151                 exif->fMeteringMode = 5;
0152                 break;
0153             }
0154 
0155             case 4:
0156             {
0157                 exif->fMeteringMode = 6;
0158                 break;
0159             }
0160 
0161             case 5:
0162             {
0163                 exif->fMeteringMode = 2;
0164                 break;
0165             }
0166 
0167             default:
0168             {
0169                 break;
0170             }
0171         }
0172     }
0173 
0174     long canonLensUnits = 1;
0175     if (meta->getExifTagRational("Exif.CanonCs.Lens", num, den, 2))             canonLensUnits                  = num;
0176     if (meta->getExifTagRational("Exif.CanonCs.Lens", num, den, 0))             exif->fLensInfo[1]              = dng_urational(num, canonLensUnits);
0177     if (meta->getExifTagRational("Exif.CanonCs.Lens", num, den, 1))             exif->fLensInfo[0]              = dng_urational(num, canonLensUnits);
0178     if (meta->getExifTagRational("Exif.Canon.FocalLength", num, den, 1))        exif->fFocalLength              = dng_urational(num, canonLensUnits);
0179     long canonLensType = 65535;
0180 
0181     if (meta->getExifTagLong("Exif.CanonCs.LensType", canonLensType))           exif->fLensID.Set_ASCII((QString::fromUtf8("%1").arg(canonLensType)).toLatin1().constData());
0182     str = meta->getExifTagString("Exif.Canon.LensModel");
0183 
0184     if      (!str.isEmpty())
0185     {
0186         exif->fLensName.Set_ASCII(str.trimmed().toLatin1().constData());
0187     }
0188     else if (canonLensType != 65535)
0189     {
0190         str = meta->getExifTagString("Exif.CanonCs.LensType");
0191         if (!str.isEmpty()) exif->fLensName.Set_ASCII(str.trimmed().toLatin1().constData());
0192     }
0193 
0194     str = meta->getExifTagString("Exif.Canon.OwnerName");
0195     if (!str.isEmpty()) exif->fOwnerName.Set_ASCII(str.trimmed().toLatin1().constData());
0196 
0197     str = meta->getExifTagString("Exif.Canon.FirmwareVersion");
0198     if (!str.isEmpty()) str = str.replace(QLatin1String("Firmware"), QLatin1String(""));
0199     if (!str.isEmpty()) str = str.replace(QLatin1String("Version"), QLatin1String(""));
0200     if (!str.isEmpty()) exif->fFirmware.Set_ASCII(str.trimmed().toLatin1().constData());
0201 
0202     str = meta->getExifTagString("Exif.CanonSi.ISOSpeed");
0203     if (!str.isEmpty()) exif->fISOSpeedRatings[1] = str.toInt();
0204 }
0205 
0206 void DNGWriter::Private::backportPentaxMakerNote(DMetadata* const meta)
0207 {
0208     QString str = meta->getExifTagString("Exif.Pentax.LensType");
0209 
0210     if (!str.isEmpty())
0211     {
0212         exif->fLensName.Set_ASCII(str.trimmed().toLatin1().constData());
0213         exif->fLensName.TrimLeadingBlanks();
0214         exif->fLensName.TrimTrailingBlanks();
0215     }
0216 
0217     long pentaxLensId1 = 0;
0218     long pentaxLensId2 = 0;
0219 
0220     if ((meta->getExifTagLong("Exif.Pentax.LensType", pentaxLensId1, 0)) &&
0221         (meta->getExifTagLong("Exif.Pentax.LensType", pentaxLensId2, 1)))
0222     {
0223         exif->fLensID.Set_ASCII(QString::fromUtf8("%1").arg(pentaxLensId1, pentaxLensId2).toLatin1().constData());
0224     }
0225 }
0226 
0227 void DNGWriter::Private::backportOlympusMakerNote(DMetadata* const meta)
0228 {
0229     QString  str;
0230     long     val;
0231 
0232     str = meta->getExifTagString("Exif.OlympusEq.SerialNumber");
0233     if (!str.isEmpty()) exif->fCameraSerialNumber.Set_ASCII(str.trimmed().toLatin1().constData());
0234 
0235     str = meta->getExifTagString("Exif.OlympusEq.LensSerialNumber");
0236     if (!str.isEmpty()) exif->fLensSerialNumber.Set_ASCII(str.trimmed().toLatin1().constData());
0237 
0238     str = meta->getExifTagString("Exif.OlympusEq.LensModel");
0239     if (!str.isEmpty()) exif->fLensName.Set_ASCII(str.trimmed().toLatin1().constData());
0240 
0241     if (meta->getExifTagLong("Exif.OlympusEq.MinFocalLength", val))             exif->fLensInfo[0]              = dng_urational(val, 1);
0242     if (meta->getExifTagLong("Exif.OlympusEq.MaxFocalLength", val))             exif->fLensInfo[1]              = dng_urational(val, 1);
0243 }
0244 
0245 void DNGWriter::Private::backportPanasonicMakerNote(DMetadata* const meta)
0246 {
0247     QString  str;
0248 
0249     str = meta->getExifTagString("Exif.Panasonic.LensType");
0250     if (!str.isEmpty()) exif->fLensName.Set_ASCII(str.trimmed().toLatin1().constData());
0251 
0252     str = meta->getExifTagString("Exif.Panasonic.LensSerialNumber");
0253     if (!str.isEmpty()) exif->fLensSerialNumber.Set_ASCII(str.trimmed().toLatin1().constData());
0254 }
0255 
0256 void DNGWriter::Private::backportSonyMakerNote(DMetadata* const meta)
0257 {
0258     QString  str;
0259     long     val;
0260 
0261     if (meta->getExifTagLong("Exif.Sony2.LensID", val))
0262     {
0263         exif->fLensID.Set_ASCII(QString::fromUtf8("%1").arg(val).toLatin1().constData());
0264     }
0265 
0266     str = meta->getExifTagString("Exif.Photo.LensModel");
0267 
0268     if (str.isEmpty())
0269     {
0270         str = meta->getExifTagString("Exif.Sony2.LensID");
0271     }
0272 
0273     if (!str.isEmpty()) exif->fLensName.Set_ASCII(str.trimmed().toLatin1().constData());
0274 }
0275 
0276 void DNGWriter::Private::storeLensInformation()
0277 {
0278     if ((exif->fLensName.IsEmpty())          &&
0279         (exif->fLensInfo[0].As_real64() > 0) &&
0280         (exif->fLensInfo[1].As_real64() > 0))
0281     {
0282         QString     lensName;
0283         QTextStream stream(&lensName);
0284         double      dval = (double)exif->fLensInfo[0].n / (double)exif->fLensInfo[0].d;
0285         stream << QString::fromUtf8("%1").arg(dval, 0, 'f', 1);
0286 
0287         if (exif->fLensInfo[0].As_real64() != exif->fLensInfo[1].As_real64())
0288         {
0289             dval = (double)exif->fLensInfo[1].n / (double)exif->fLensInfo[1].d;
0290             stream << QString::fromUtf8("-%1").arg(dval, 0, 'f', 1);
0291         }
0292 
0293         stream << " mm";
0294 
0295         if (exif->fLensInfo[2].As_real64() > 0)
0296         {
0297             dval = (double)exif->fLensInfo[2].n / (double)exif->fLensInfo[2].d;
0298             stream << QString::fromUtf8(" 1/%1").arg(dval, 0, 'f', 1);
0299         }
0300 
0301         if ((exif->fLensInfo[3].As_real64() > 0) &&
0302             (exif->fLensInfo[2].As_real64() != exif->fLensInfo[3].As_real64()))
0303         {
0304             dval = (double)exif->fLensInfo[3].n / (double)exif->fLensInfo[3].d;
0305             stream << QString::fromUtf8("-%1").arg(dval, 0, 'f', 1);
0306         }
0307 
0308         exif->fLensName.Set_ASCII(lensName.toLatin1().constData());
0309     }
0310 }
0311 
0312 void DNGWriter::Private::backupMakernote(DNGWriterHost& host,
0313                                          AutoPtr<dng_negative>& negative,
0314                                          DRawInfo* const /*identify*/,
0315                                          DRawInfo* const identifyMake,
0316                                          DMetadata* const meta)
0317 {
0318     // Original Markernote storage in Standard Exif tag.
0319 
0320     long mknOffset       = 0;
0321     QString mknMake      = identifyMake->make.toUpper();
0322     QString mknByteOrder = meta->getExifTagString("Exif.MakerNote.ByteOrder");
0323     QByteArray mknData   = meta->getExifTagData("Exif.Photo.MakerNote");
0324     meta->getExifTagLong("Exif.MakerNote.Offset", mknOffset);
0325 
0326     if (!mknData.isEmpty()                      &&
0327         ((mknMake == QLatin1String("NIKON"))    ||
0328          (mknMake == QLatin1String("OLYMPUS"))  ||
0329          (mknMake == QLatin1String("FUJIFILM")))
0330        )
0331     {
0332         qCDebug(DIGIKAM_GENERAL_LOG) << "DNGWriter: Makernote storage ("
0333                                      << mknData.size() << " bytes)" ;
0334 
0335         dng_memory_allocator memalloc1(gDefaultDNGMemoryAllocator);
0336         dng_memory_stream stream(memalloc1);
0337         stream.Put(mknData.constData(), mknData.size());
0338         AutoPtr<dng_memory_block> block(host.Allocate(mknData.size()));
0339         stream.SetReadPosition(0);
0340         stream.Get(block->Buffer(), mknData.size());
0341 
0342         negative->SetMakerNoteSafety(true);
0343         negative->SetMakerNote(block);
0344     }
0345 
0346     // Backup Makernote in DNG private tag.
0347     // NOTE: Exiv2 report a warning with CR2 conversion:
0348     // Error: Directory Canon with 25665 entries considered invalid; not read.
0349 
0350     if (!mknData.isEmpty()      &&
0351         !mknByteOrder.isEmpty() &&
0352         mknOffset)
0353     {
0354         bool padding                        = ((mknData.size() & 0x01) == 0x01);
0355         dng_memory_stream* const streamPriv = new dng_memory_stream(host.Allocator());
0356         streamPriv->SetBigEndian();
0357 
0358         // Use Adobe vendor-format for encoding MakerNotes in DNGPrivateTag
0359 
0360         streamPriv->Put("Adobe", 5);
0361         streamPriv->Put_uint8(0x00);
0362         streamPriv->Put("MakN", 4);
0363         streamPriv->Put_uint32(mknData.size() + mknByteOrder.size() + 4 + (padding ? 1 : 0));
0364         streamPriv->Put(mknByteOrder.toLatin1().constData(), mknByteOrder.toLatin1().size());
0365         streamPriv->Put_uint32(mknOffset);
0366         streamPriv->Put(mknData.constData(), mknData.size());
0367 
0368         if (padding)
0369         {
0370             streamPriv->Put_uint8(0x00);
0371         }
0372 
0373         AutoPtr<dng_memory_stream> DNGPrivateTag(streamPriv);
0374 
0375         if (DNGPrivateTag.Get())
0376         {
0377             qCDebug(DIGIKAM_GENERAL_LOG) << "DNGWriter: Backup Makernote as DNG Private data ("
0378                                          << DNGPrivateTag->Length() << " bytes)";
0379 
0380             AutoPtr<dng_memory_block> blockPriv(DNGPrivateTag->AsMemoryBlock(host.Allocator()));
0381             negative->SetPrivateData(blockPriv);
0382         }
0383     }
0384 }
0385 
0386 } // namespace Digikam