dng_rect dng_area_spec::Overlap (const dng_rect &tile) const { // Special case - if the fArea is empty, then dng_area_spec covers // the entire image, no matter how large it is. if (fArea.IsEmpty ()) { return tile; } dng_rect overlap = fArea & tile; if (overlap.NotEmpty ()) { overlap.t = fArea.t + ((overlap.t - fArea.t + fRowPitch - 1) / fRowPitch) * fRowPitch; overlap.l = fArea.l + ((overlap.l - fArea.l + fColPitch - 1) / fColPitch) * fColPitch; if (overlap.NotEmpty ()) { overlap.b = overlap.t + ((overlap.H () - 1) / fRowPitch) * fRowPitch + 1; overlap.r = overlap.l + ((overlap.W () - 1) / fColPitch) * fColPitch + 1; return overlap; } } return dng_rect (); }
SkCodec::Result SkRawCodec::onGetPixels(const SkImageInfo& requestedInfo, void* dst, size_t dstRowBytes, const Options& options, SkPMColor ctable[], int* ctableCount, int* rowsDecoded) { if (!conversion_possible(requestedInfo, this->getInfo())) { SkCodecPrintf("Error: cannot convert input type to output type.\n"); return kInvalidConversion; } SkAutoTDelete<SkSwizzler> swizzler(SkSwizzler::CreateSwizzler( SkSwizzler::kRGB, nullptr, requestedInfo, options)); SkASSERT(swizzler); const int width = requestedInfo.width(); const int height = requestedInfo.height(); SkAutoTDelete<dng_image> image(fDngImage->render(width, height)); if (!image) { return kInvalidInput; } // Because the DNG SDK can not guarantee to render to requested size, we allow a small // difference. Only the overlapping region will be converted. const float maxDiffRatio = 1.03f; const dng_point& imageSize = image->Size(); if (imageSize.h / width > maxDiffRatio || imageSize.h < width || imageSize.v / height > maxDiffRatio || imageSize.v < height) { return SkCodec::kInvalidScale; } void* dstRow = dst; SkAutoTMalloc<uint8_t> srcRow(width * 3); dng_pixel_buffer buffer; buffer.fData = &srcRow[0]; buffer.fPlane = 0; buffer.fPlanes = 3; buffer.fColStep = buffer.fPlanes; buffer.fPlaneStep = 1; buffer.fPixelType = ttByte; buffer.fPixelSize = sizeof(uint8_t); buffer.fRowStep = width * 3; for (int i = 0; i < height; ++i) { buffer.fArea = dng_rect(i, 0, i + 1, width); try { image->Get(buffer, dng_image::edge_zero); } catch (...) { *rowsDecoded = i; return kIncompleteInput; } swizzler->swizzle(dstRow, &srcRow[0]); dstRow = SkTAddOffset<void>(dstRow, dstRowBytes); } return kSuccess; }
void NegativeProcessor::buildDNGImage() { libraw_image_sizes_t *sizes = &m_RawProcessor->imgdata.sizes; // ----------------------------------------------------------------------------------------- // Select right data source from LibRaw unsigned short *rawBuffer = (unsigned short*) m_RawProcessor->imgdata.rawdata.raw_image; uint32 inputPlanes = 1; if (rawBuffer == NULL) { rawBuffer = (unsigned short*) m_RawProcessor->imgdata.rawdata.color3_image; inputPlanes = 3; } if (rawBuffer == NULL) { rawBuffer = (unsigned short*) m_RawProcessor->imgdata.rawdata.color4_image; inputPlanes = 4; } uint32 outputPlanes = (inputPlanes == 1) ? 1 : m_RawProcessor->imgdata.idata.colors; // ----------------------------------------------------------------------------------------- // Create new dng_image and copy data dng_rect bounds = dng_rect(sizes->raw_height, sizes->raw_width); dng_simple_image *image = new dng_simple_image(bounds, outputPlanes, ttShort, m_host->Allocator()); dng_pixel_buffer buffer; image->GetPixelBuffer(buffer); unsigned short *imageBuffer = (unsigned short*)buffer.fData; if (inputPlanes == outputPlanes) memcpy(imageBuffer, rawBuffer, sizes->raw_height * sizes->raw_width * outputPlanes * sizeof(unsigned short)); else { for (int i = 0; i < (sizes->raw_height * sizes->raw_width); i++) { memcpy(imageBuffer, rawBuffer, outputPlanes * sizeof(unsigned short)); imageBuffer += outputPlanes; rawBuffer += inputPlanes; } } AutoPtr<dng_image> castImage(dynamic_cast<dng_image*>(image)); m_negative->SetStage1Image(castImage); }
void dng_image::Get (dng_pixel_buffer &buffer, edge_option edgeOption, uint32 repeatV, uint32 repeatH) const { // Find the overlap with the image bounds. dng_rect overlap = buffer.fArea & fBounds; // Move the overlapping pixels. if (overlap.NotEmpty ()) { dng_pixel_buffer temp (buffer); temp.fArea = overlap; temp.fData = buffer.DirtyPixel (overlap.t, overlap.l, buffer.fPlane); DoGet (temp); } // See if we need to pad the edge values. if ((edgeOption != edge_none) && (overlap != buffer.fArea)) { dng_rect areaT (buffer.fArea); dng_rect areaL (buffer.fArea); dng_rect areaB (buffer.fArea); dng_rect areaR (buffer.fArea); areaT.b = Min_int32 (areaT.b, fBounds.t); areaL.r = Min_int32 (areaL.r, fBounds.l); areaB.t = Max_int32 (areaB.t, fBounds.b); areaR.l = Max_int32 (areaR.l, fBounds.r); dng_rect areaH (buffer.fArea); dng_rect areaV (buffer.fArea); areaH.l = Max_int32 (areaH.l, fBounds.l); areaH.r = Min_int32 (areaH.r, fBounds.r); areaV.t = Max_int32 (areaV.t, fBounds.t); areaV.b = Min_int32 (areaV.b, fBounds.b); // Top left. dng_rect areaTL = areaT & areaL; if (areaTL.NotEmpty ()) { GetEdge (buffer, edgeOption, dng_rect (fBounds.t, fBounds.l, fBounds.t + (int32)repeatV, fBounds.l + (int32)repeatH), areaTL); } // Top middle. dng_rect areaTM = areaT & areaH; if (areaTM.NotEmpty ()) { GetEdge (buffer, edgeOption, dng_rect (fBounds.t, areaTM.l, fBounds.t + (int32)repeatV, areaTM.r), areaTM); } // Top right. dng_rect areaTR = areaT & areaR; if (areaTR.NotEmpty ()) { GetEdge (buffer, edgeOption, dng_rect (fBounds.t, fBounds.r - (int32)repeatH, fBounds.t + (int32)repeatV, fBounds.r), areaTR); } // Left middle. dng_rect areaLM = areaL & areaV; if (areaLM.NotEmpty ()) { GetEdge (buffer, edgeOption, dng_rect (areaLM.t, fBounds.l, areaLM.b, fBounds.l + (int32)repeatH), areaLM); } // Right middle. dng_rect areaRM = areaR & areaV; if (areaRM.NotEmpty ()) { GetEdge (buffer, edgeOption, dng_rect (areaRM.t, fBounds.r - (int32)repeatH, areaRM.b, fBounds.r), areaRM); } // Bottom left. dng_rect areaBL = areaB & areaL; if (areaBL.NotEmpty ()) { GetEdge (buffer, edgeOption, dng_rect (fBounds.b - (int32)repeatV, fBounds.l, fBounds.b, fBounds.l + (int32)repeatH), areaBL); } // Bottom middle. dng_rect areaBM = areaB & areaH; if (areaBM.NotEmpty ()) { GetEdge (buffer, edgeOption, dng_rect (fBounds.b - (int32)repeatV, areaBM.l, fBounds.b, areaBM.r), areaBM); } // Bottom right. dng_rect areaBR = areaB & areaR; if (areaBR.NotEmpty ()) { GetEdge (buffer, edgeOption, dng_rect (fBounds.b - (int32)repeatV, fBounds.r - (int32)repeatH, fBounds.b, fBounds.r), areaBR); } } }
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)); }
dng_rect dng_area_task::RepeatingTile3 () const { return dng_rect (); }
SkCodec::Result SkRawCodec::onGetPixels(const SkImageInfo& dstInfo, void* dst, size_t dstRowBytes, const Options& options, SkPMColor ctable[], int* ctableCount, int* rowsDecoded) { if (!conversion_possible(dstInfo, this->getInfo()) || !this->initializeColorXform(dstInfo, options.fPremulBehavior)) { SkCodecPrintf("Error: cannot convert input type to output type.\n"); return kInvalidConversion; } static const SkColorType kXformSrcColorType = kRGBA_8888_SkColorType; SkImageInfo swizzlerInfo = dstInfo; std::unique_ptr<uint32_t[]> xformBuffer = nullptr; if (this->colorXform()) { swizzlerInfo = swizzlerInfo.makeColorType(kXformSrcColorType); xformBuffer.reset(new uint32_t[dstInfo.width()]); } std::unique_ptr<SkSwizzler> swizzler(SkSwizzler::CreateSwizzler( this->getEncodedInfo(), nullptr, swizzlerInfo, options)); SkASSERT(swizzler); const int width = dstInfo.width(); const int height = dstInfo.height(); std::unique_ptr<dng_image> image(fDngImage->render(width, height)); if (!image) { return kInvalidInput; } // Because the DNG SDK can not guarantee to render to requested size, we allow a small // difference. Only the overlapping region will be converted. const float maxDiffRatio = 1.03f; const dng_point& imageSize = image->Size(); if (imageSize.h / (float) width > maxDiffRatio || imageSize.h < width || imageSize.v / (float) height > maxDiffRatio || imageSize.v < height) { return SkCodec::kInvalidScale; } void* dstRow = dst; SkAutoTMalloc<uint8_t> srcRow(width * 3); dng_pixel_buffer buffer; buffer.fData = &srcRow[0]; buffer.fPlane = 0; buffer.fPlanes = 3; buffer.fColStep = buffer.fPlanes; buffer.fPlaneStep = 1; buffer.fPixelType = ttByte; buffer.fPixelSize = sizeof(uint8_t); buffer.fRowStep = width * 3; for (int i = 0; i < height; ++i) { buffer.fArea = dng_rect(i, 0, i + 1, width); try { image->Get(buffer, dng_image::edge_zero); } catch (...) { *rowsDecoded = i; return kIncompleteInput; } if (this->colorXform()) { swizzler->swizzle(xformBuffer.get(), &srcRow[0]); const SkColorSpaceXform::ColorFormat srcFormat = select_xform_format(kXformSrcColorType); const SkColorSpaceXform::ColorFormat dstFormat = select_xform_format(dstInfo.colorType()); this->colorXform()->apply(dstFormat, dstRow, srcFormat, xformBuffer.get(), dstInfo.width(), kOpaque_SkAlphaType); dstRow = SkTAddOffset<void>(dstRow, dstRowBytes); } else { swizzler->swizzle(dstRow, &srcRow[0]); dstRow = SkTAddOffset<void>(dstRow, dstRowBytes); } } return kSuccess; }