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);
		
		}
			
	}
Ejemplo n.º 2
0
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));
}