File indexing completed on 2025-01-19 03:55:34
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 - Digital Negative creation. 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::createNegative(AutoPtr<dng_negative>& negative, 0026 DRawInfo* const identify) 0027 { 0028 qCDebug(DIGIKAM_GENERAL_LOG) << "DNGWriter: DNG Negative structure creation"; 0029 0030 negative->SetDefaultScale(dng_urational(outputWidth, activeWidth), 0031 dng_urational(outputHeight, activeHeight)); 0032 0033 if (bayerPattern != Private::LinearRaw) 0034 { 0035 qCDebug(DIGIKAM_GENERAL_LOG) << "DNGWriter: Bayer Pattern Linear Raw"; 0036 negative->SetDefaultCropOrigin(8, 8); 0037 negative->SetDefaultCropSize(activeWidth - 16, activeHeight - 16); 0038 } 0039 else 0040 { 0041 qCDebug(DIGIKAM_GENERAL_LOG) << "DNGWriter: Bayer Pattern Type:" << bayerPattern; 0042 negative->SetDefaultCropOrigin(0, 0); 0043 negative->SetDefaultCropSize(activeWidth, activeHeight); 0044 } 0045 0046 negative->SetActiveArea(activeArea); 0047 negative->SetModelName(identify->model.toLatin1().constData()); 0048 negative->SetLocalName(QString::fromUtf8("%1 %2").arg(identify->make, identify->model).toLatin1().constData()); 0049 negative->SetOriginalRawFileName(inputInfo.fileName().toLatin1().constData()); 0050 negative->SetColorChannels(identify->rawColors); 0051 0052 ColorKeyCode colorCodes[4] = 0053 { 0054 colorKeyMaxEnum, 0055 colorKeyMaxEnum, 0056 colorKeyMaxEnum, 0057 colorKeyMaxEnum 0058 }; 0059 0060 for (int i = 0 ; i < qMax(4, identify->colorKeys.length()) ; ++i) 0061 { 0062 if (identify->colorKeys[i] == QLatin1Char('R')) 0063 { 0064 colorCodes[i] = colorKeyRed; 0065 } 0066 else if (identify->colorKeys[i] == QLatin1Char('G')) 0067 { 0068 colorCodes[i] = colorKeyGreen; 0069 } 0070 else if (identify->colorKeys[i] == QLatin1Char('B')) 0071 { 0072 colorCodes[i] = colorKeyBlue; 0073 } 0074 else if (identify->colorKeys[i] == QLatin1Char('C')) 0075 { 0076 colorCodes[i] = colorKeyCyan; 0077 } 0078 else if (identify->colorKeys[i] == QLatin1Char('M')) 0079 { 0080 colorCodes[i] = colorKeyMagenta; 0081 } 0082 else if (identify->colorKeys[i] == QLatin1Char('Y')) 0083 { 0084 colorCodes[i] = colorKeyYellow; 0085 } 0086 } 0087 0088 negative->SetColorKeys(colorCodes[0], colorCodes[1], colorCodes[2], colorCodes[3]); 0089 0090 switch (bayerPattern) 0091 { 0092 case Private::Standard: 0093 { 0094 // Standard bayer mosaicing. All work fine there. 0095 // Bayer CCD mask: https://en.wikipedia.org/wiki/Bayer_filter 0096 0097 negative->SetBayerMosaic(filter); 0098 break; 0099 } 0100 0101 case Private::Fuji: 0102 { 0103 // TODO: Fuji is special case. Need to setup different bayer rules here. 0104 // It do not work in all settings. Need indeep investiguations. 0105 // Fuji superCCD: https://en.wikipedia.org/wiki/Super_CCD 0106 0107 negative->SetFujiMosaic(filter); 0108 break; 0109 } 0110 0111 case Private::Fuji6x6: 0112 { 0113 // TODO: Fuji is special case. Need to setup different bayer rules here. 0114 // It do not work in all settings. Need indeep investiguations. 0115 0116 negative->SetFujiMosaic6x6(filter); 0117 break; 0118 } 0119 0120 case Private::FourColor: 0121 { 0122 negative->SetQuadMosaic(filter); 0123 break; 0124 } 0125 0126 default: 0127 { 0128 break; 0129 } 0130 } 0131 0132 qCDebug(DIGIKAM_GENERAL_LOG) << "DNGWriter:" << dngBayerPatternToString(bayerPattern); 0133 0134 negative->SetWhiteLevel(identify->whitePoint, 0); 0135 negative->SetWhiteLevel(identify->whitePoint, 1); 0136 negative->SetWhiteLevel(identify->whitePoint, 2); 0137 negative->SetWhiteLevel(identify->whitePoint, 3); 0138 0139 const dng_mosaic_info* const mosaicinfo = negative->GetMosaicInfo(); 0140 0141 if ((mosaicinfo != nullptr) && 0142 (mosaicinfo->fCFAPatternSize == dng_point(2, 2))) 0143 { 0144 negative->SetQuadBlacks(identify->blackPoint + identify->blackPointCh[0], 0145 identify->blackPoint + identify->blackPointCh[1], 0146 identify->blackPoint + identify->blackPointCh[2], 0147 identify->blackPoint + identify->blackPointCh[3]); 0148 } 0149 else 0150 { 0151 negative->SetBlackLevel(identify->blackPoint, 0); 0152 } 0153 0154 negative->SetBaselineExposure(0.0); 0155 negative->SetBaselineNoise(1.0); 0156 negative->SetBaselineSharpness(1.0); 0157 0158 dng_orientation orientation; 0159 0160 switch (identify->orientation) 0161 { 0162 case DRawInfo::ORIENTATION_180: 0163 { 0164 qCDebug(DIGIKAM_GENERAL_LOG) << "DNGWriter: Mosaic orientation: rotate 180"; 0165 orientation = dng_orientation::Rotate180(); 0166 break; 0167 } 0168 0169 case DRawInfo::ORIENTATION_Mirror90CCW: 0170 { 0171 qCDebug(DIGIKAM_GENERAL_LOG) << "DNGWriter: Mosaic orientation: mirror 90CCW"; 0172 orientation = dng_orientation::Mirror90CCW(); 0173 break; 0174 } 0175 0176 case DRawInfo::ORIENTATION_90CCW: 0177 { 0178 qCDebug(DIGIKAM_GENERAL_LOG) << "DNGWriter: Mosaic orientation: rotate 90CCW"; 0179 orientation = dng_orientation::Rotate90CCW(); 0180 break; 0181 } 0182 0183 case DRawInfo::ORIENTATION_90CW: 0184 { 0185 qCDebug(DIGIKAM_GENERAL_LOG) << "DNGWriter: Mosaic orientation: rotate 90CW"; 0186 orientation = dng_orientation::Rotate90CW(); 0187 break; 0188 } 0189 0190 default: // ORIENTATION_NONE 0191 { 0192 qCDebug(DIGIKAM_GENERAL_LOG) << "DNGWriter: Mosaic orientation: no rotation"; 0193 orientation = dng_orientation::Normal(); 0194 break; 0195 } 0196 } 0197 0198 negative->SetBaseOrientation(orientation); 0199 negative->SetAntiAliasStrength(dng_urational(100, 100)); 0200 negative->SetLinearResponseLimit(1.0); 0201 negative->SetShadowScale( dng_urational(1, 1) ); 0202 negative->SetAnalogBalance(dng_vector_3(1.0, 1.0, 1.0)); 0203 0204 // ------------------------------------------------------------------------------- 0205 0206 AutoPtr<dng_camera_profile> prof(new dng_camera_profile); 0207 prof->SetName(QString::fromUtf8("%1 %2").arg(identify->make, identify->model).toLatin1().constData()); 0208 0209 // Set Camera->XYZ Color matrix as profile. 0210 0211 dng_matrix matrix; 0212 0213 switch (identify->rawColors) 0214 { 0215 case 3: 0216 { 0217 qCDebug(DIGIKAM_GENERAL_LOG) << "DNGWriter: Mosaic Raw color components: 3"; 0218 0219 dng_matrix_3by3 camXYZ; 0220 camXYZ[0][0] = identify->cameraXYZMatrix[0][0]; 0221 camXYZ[0][1] = identify->cameraXYZMatrix[0][1]; 0222 camXYZ[0][2] = identify->cameraXYZMatrix[0][2]; 0223 camXYZ[1][0] = identify->cameraXYZMatrix[1][0]; 0224 camXYZ[1][1] = identify->cameraXYZMatrix[1][1]; 0225 camXYZ[1][2] = identify->cameraXYZMatrix[1][2]; 0226 camXYZ[2][0] = identify->cameraXYZMatrix[2][0]; 0227 camXYZ[2][1] = identify->cameraXYZMatrix[2][1]; 0228 camXYZ[2][2] = identify->cameraXYZMatrix[2][2]; 0229 0230 if (camXYZ.MaxEntry() == 0.0) 0231 { 0232 qCCritical(DIGIKAM_GENERAL_LOG) << "DNGWriter: camera XYZ Matrix is null : camera not supported"; 0233 return FILE_NOT_SUPPORTED; 0234 } 0235 0236 matrix = camXYZ; 0237 0238 break; 0239 } 0240 0241 case 4: 0242 { 0243 qCDebug(DIGIKAM_GENERAL_LOG) << "DNGWriter: Mosaic Raw color components: 3"; 0244 0245 dng_matrix_4by3 camXYZ; 0246 camXYZ[0][0] = identify->cameraXYZMatrix[0][0]; 0247 camXYZ[0][1] = identify->cameraXYZMatrix[0][1]; 0248 camXYZ[0][2] = identify->cameraXYZMatrix[0][2]; 0249 camXYZ[1][0] = identify->cameraXYZMatrix[1][0]; 0250 camXYZ[1][1] = identify->cameraXYZMatrix[1][1]; 0251 camXYZ[1][2] = identify->cameraXYZMatrix[1][2]; 0252 camXYZ[2][0] = identify->cameraXYZMatrix[2][0]; 0253 camXYZ[2][1] = identify->cameraXYZMatrix[2][1]; 0254 camXYZ[2][2] = identify->cameraXYZMatrix[2][2]; 0255 camXYZ[3][0] = identify->cameraXYZMatrix[3][0]; 0256 camXYZ[3][1] = identify->cameraXYZMatrix[3][1]; 0257 camXYZ[3][2] = identify->cameraXYZMatrix[3][2]; 0258 0259 if (camXYZ.MaxEntry() == 0.0) 0260 { 0261 qCCritical(DIGIKAM_GENERAL_LOG) << "DNGWriter: camera XYZ Matrix is null : camera not supported"; 0262 return FILE_NOT_SUPPORTED; 0263 } 0264 0265 matrix = camXYZ; 0266 0267 break; 0268 } 0269 0270 default: 0271 { 0272 qCCritical(DIGIKAM_GENERAL_LOG) << "DNGWriter: Mosaic Raw color components not handled:" << identify->rawColors; 0273 } 0274 } 0275 0276 prof->SetColorMatrix1((dng_matrix) matrix); 0277 prof->SetCalibrationIlluminant1(lsD65); 0278 negative->AddProfile(prof); 0279 0280 dng_vector camNeutral(identify->rawColors); 0281 0282 for (int i = 0 ; i < identify->rawColors ; ++i) 0283 { 0284 camNeutral[i] = 1.0 / identify->cameraMult[i]; 0285 } 0286 0287 negative->SetCameraNeutral(camNeutral); 0288 0289 if (cancel) 0290 { 0291 return PROCESS_CANCELED; 0292 } 0293 0294 return PROCESS_CONTINUE; 0295 } 0296 0297 } // namespace Digikam