void dng_image::GetRepeat (dng_pixel_buffer &buffer, const dng_rect &srcArea, const dng_rect &dstArea) const { // If we already have the entire srcArea in the // buffer, we can just repeat that. if ((srcArea & buffer.fArea) == srcArea) { buffer.RepeatArea (srcArea, dstArea); } // Else we first need to get the srcArea into the buffer area. else { // Find repeating pattern size. dng_point repeat = srcArea.Size (); // Find pattern phase at top-left corner of destination area. dng_point phase = dng_pixel_buffer::RepeatPhase (srcArea, dstArea); // Find new source area at top-left of dstArea. dng_rect newArea = srcArea + (dstArea.TL () - srcArea.TL ()); // Find quadrant split coordinates. int32 splitV = newArea.t + repeat.v - phase.v; int32 splitH = newArea.l + repeat.h - phase.h; // Top-left quadrant. dng_rect dst1 (dng_rect (newArea.t, newArea.l, splitV, splitH) & dstArea); if (dst1.NotEmpty ()) { dng_pixel_buffer temp (buffer); temp.fArea = dst1 + (srcArea.TL () - dstArea.TL () + dng_point (phase.v, phase.h)); temp.fData = buffer.DirtyPixel (dst1.t, dst1.l, buffer.fPlane); DoGet (temp); } // Top-right quadrant. dng_rect dst2 (dng_rect (newArea.t, splitH, splitV, newArea.r) & dstArea); if (dst2.NotEmpty ()) { dng_pixel_buffer temp (buffer); temp.fArea = dst2 + (srcArea.TL () - dstArea.TL () + dng_point (phase.v, -phase.h)); temp.fData = buffer.DirtyPixel (dst2.t, dst2.l, buffer.fPlane); DoGet (temp); } // Bottom-left quadrant. dng_rect dst3 (dng_rect (splitV, newArea.l, newArea.b, splitH) & dstArea); if (dst3.NotEmpty ()) { dng_pixel_buffer temp (buffer); temp.fArea = dst3 + (srcArea.TL () - dstArea.TL () + dng_point (-phase.v, phase.h)); temp.fData = buffer.DirtyPixel (dst3.t, dst3.l, buffer.fPlane); DoGet (temp); } // Bottom-right quadrant. dng_rect dst4 (dng_rect (splitV, splitH, newArea.b, newArea.r) & dstArea); if (dst4.NotEmpty ()) { dng_pixel_buffer temp (buffer); temp.fArea = dst4 + (srcArea.TL () - dstArea.TL () + dng_point (-phase.v, -phase.h)); temp.fData = buffer.DirtyPixel (dst4.t, dst4.l, buffer.fPlane); DoGet (temp); } // Replicate this new source area. buffer.RepeatArea (newArea, dstArea); } }
void NegativeProcessor::setDNGPropertiesFromRaw() { libraw_image_sizes_t *sizes = &m_RawProcessor->imgdata.sizes; libraw_iparams_t *iparams = &m_RawProcessor->imgdata.idata; // ----------------------------------------------------------------------------------------- // Raw filename std::string file(m_RawImage->io().path()); size_t found = std::min(file.rfind("\\"), file.rfind("/")); if (found != std::string::npos) file = file.substr(found + 1, file.length() - found - 1); m_negative->SetOriginalRawFileName(file.c_str()); // ----------------------------------------------------------------------------------------- // Model dng_string makeModel; makeModel.Append(iparams->make); makeModel.Append(" "); makeModel.Append(iparams->model); m_negative->SetModelName(makeModel.Get()); // ----------------------------------------------------------------------------------------- // Orientation switch (sizes->flip) { case 180: case 3: m_negative->SetBaseOrientation(dng_orientation::Rotate180()); break; case 270: case 5: m_negative->SetBaseOrientation(dng_orientation::Rotate90CCW()); break; case 90: case 6: m_negative->SetBaseOrientation(dng_orientation::Rotate90CW()); break; default: m_negative->SetBaseOrientation(dng_orientation::Normal()); break; } // ----------------------------------------------------------------------------------------- // ColorKeys (this needs to happen before Mosaic - how about documenting that in the SDK???) m_negative->SetColorChannels(iparams->colors); m_negative->SetColorKeys(colorKey(iparams->cdesc[0]), colorKey(iparams->cdesc[1]), colorKey(iparams->cdesc[2]), colorKey(iparams->cdesc[3])); // ----------------------------------------------------------------------------------------- // Mosaic if (iparams->colors == 4) m_negative->SetQuadMosaic(iparams->filters); else switch(iparams->filters) { case 0xe1e1e1e1: m_negative->SetBayerMosaic(0); break; case 0xb4b4b4b4: m_negative->SetBayerMosaic(1); break; case 0x1e1e1e1e: m_negative->SetBayerMosaic(2); break; case 0x4b4b4b4b: m_negative->SetBayerMosaic(3); break; default: break; // not throwing error, because this might be set in a sub-class (e.g., Fuji) } // ----------------------------------------------------------------------------------------- // Default scale and crop/active area m_negative->SetDefaultScale(dng_urational(sizes->iwidth, sizes->width), dng_urational(sizes->iheight, sizes->height)); m_negative->SetActiveArea(dng_rect(sizes->top_margin, sizes->left_margin, sizes->top_margin + sizes->height, sizes->left_margin + sizes->width)); uint32 cropWidth, cropHeight; if (!getRawExifTag("Exif.Photo.PixelXDimension", 0, &cropWidth) || !getRawExifTag("Exif.Photo.PixelYDimension", 0, &cropHeight)) { cropWidth = sizes->width - 16; cropHeight = sizes->height - 16; } int cropLeftMargin = (cropWidth > sizes->width ) ? 0 : (sizes->width - cropWidth) / 2; int cropTopMargin = (cropHeight > sizes->height) ? 0 : (sizes->height - cropHeight) / 2; m_negative->SetDefaultCropOrigin(cropLeftMargin, cropTopMargin); m_negative->SetDefaultCropSize(cropWidth, cropHeight); // ----------------------------------------------------------------------------------------- // CameraNeutral //TODO/CHECK/FORK: what does this actually do? dng_vector cameraNeutral(iparams->colors); for (int i = 0; i < iparams->colors; i++) cameraNeutral[i] = 1.0 / m_RawProcessor->imgdata.color.cam_mul[i]; m_negative->SetCameraNeutral(cameraNeutral); // ----------------------------------------------------------------------------------------- // BlackLevel & WhiteLevel libraw_colordata_t *colors = &m_RawProcessor->imgdata.color; for (int i = 0; i < 4; i++) m_negative->SetWhiteLevel(static_cast<uint32>(colors->maximum), i); if ((m_negative->GetMosaicInfo() != NULL) && (m_negative->GetMosaicInfo()->fCFAPatternSize == dng_point(2, 2))) m_negative->SetQuadBlacks(colors->black + colors->cblack[0], colors->black + colors->cblack[1], colors->black + colors->cblack[2], colors->black + colors->cblack[3]); else m_negative->SetBlackLevel(colors->black + colors->cblack[0], 0); // ----------------------------------------------------------------------------------------- // Fixed properties m_negative->SetBaselineExposure(0.0); // should be fixed per camera m_negative->SetBaselineNoise(1.0); m_negative->SetBaselineSharpness(1.0); // default m_negative->SetAntiAliasStrength(dng_urational(100, 100)); // = no aliasing artifacts m_negative->SetLinearResponseLimit(1.0); // = no non-linear sensor response m_negative->SetAnalogBalance(dng_vector_3(1.0, 1.0, 1.0)); m_negative->SetShadowScale(dng_urational(1, 1)); }