| /*****************************************************************************/ |
| // Copyright 2006-2008 Adobe Systems Incorporated |
| // All Rights Reserved. |
| // |
| // NOTICE: Adobe permits you to use, modify, and distribute this file in |
| // accordance with the terms of the Adobe license agreement accompanying it. |
| /*****************************************************************************/ |
| |
| /* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_image.cpp#1 $ */ |
| /* $DateTime: 2012/05/30 13:28:51 $ */ |
| /* $Change: 832332 $ */ |
| /* $Author: tknoll $ */ |
| |
| /*****************************************************************************/ |
| |
| #include "dng_image.h" |
| |
| #include "dng_assertions.h" |
| #include "dng_exceptions.h" |
| #include "dng_orientation.h" |
| #include "dng_pixel_buffer.h" |
| #include "dng_tag_types.h" |
| #include "dng_tile_iterator.h" |
| #include "dng_utils.h" |
| |
| /*****************************************************************************/ |
| |
| dng_tile_buffer::dng_tile_buffer (const dng_image &image, |
| const dng_rect &tile, |
| bool dirty) |
| |
| : fImage (image) |
| , fRefData (NULL) |
| |
| { |
| |
| fImage.AcquireTileBuffer (*this, |
| tile, |
| dirty); |
| |
| } |
| |
| /*****************************************************************************/ |
| |
| dng_tile_buffer::~dng_tile_buffer () |
| { |
| |
| fImage.ReleaseTileBuffer (*this); |
| |
| } |
| |
| /*****************************************************************************/ |
| |
| dng_const_tile_buffer::dng_const_tile_buffer (const dng_image &image, |
| const dng_rect &tile) |
| |
| : dng_tile_buffer (image, tile, false) |
| |
| { |
| |
| } |
| |
| /*****************************************************************************/ |
| |
| dng_const_tile_buffer::~dng_const_tile_buffer () |
| { |
| |
| } |
| |
| /*****************************************************************************/ |
| |
| dng_dirty_tile_buffer::dng_dirty_tile_buffer (dng_image &image, |
| const dng_rect &tile) |
| |
| : dng_tile_buffer (image, tile, true) |
| |
| { |
| |
| } |
| |
| /*****************************************************************************/ |
| |
| dng_dirty_tile_buffer::~dng_dirty_tile_buffer () |
| { |
| |
| } |
| |
| /*****************************************************************************/ |
| |
| dng_image::dng_image (const dng_rect &bounds, |
| uint32 planes, |
| uint32 pixelType) |
| |
| : fBounds (bounds) |
| , fPlanes (planes) |
| , fPixelType (pixelType) |
| |
| { |
| |
| if (bounds.IsEmpty () || planes == 0 || PixelSize () == 0) |
| { |
| |
| #if qDNGValidate |
| |
| ReportError ("Fuzz: Attempt to create zero size image"); |
| |
| #endif |
| |
| ThrowBadFormat (); |
| |
| } |
| |
| } |
| |
| /*****************************************************************************/ |
| |
| dng_image::~dng_image () |
| { |
| |
| } |
| |
| /*****************************************************************************/ |
| |
| dng_image * dng_image::Clone () const |
| { |
| |
| ThrowProgramError ("Clone is not supported by this dng_image subclass"); |
| |
| return NULL; |
| |
| } |
| |
| /*****************************************************************************/ |
| |
| void dng_image::SetPixelType (uint32 pixelType) |
| { |
| |
| if (TagTypeSize (pixelType) != PixelSize ()) |
| { |
| |
| ThrowProgramError ("Cannot change pixel size for existing image"); |
| |
| } |
| |
| fPixelType = pixelType; |
| |
| } |
| |
| /*****************************************************************************/ |
| |
| uint32 dng_image::PixelSize () const |
| { |
| |
| return TagTypeSize (PixelType ()); |
| |
| } |
| |
| /*****************************************************************************/ |
| |
| uint32 dng_image::PixelRange () const |
| { |
| |
| switch (fPixelType) |
| { |
| |
| case ttByte: |
| case ttSByte: |
| { |
| return 0x0FF; |
| } |
| |
| case ttShort: |
| case ttSShort: |
| { |
| return 0x0FFFF; |
| } |
| |
| case ttLong: |
| case ttSLong: |
| { |
| return 0xFFFFFFFF; |
| } |
| |
| default: |
| break; |
| |
| } |
| |
| return 0; |
| |
| } |
| |
| /*****************************************************************************/ |
| |
| dng_rect dng_image::RepeatingTile () const |
| { |
| |
| return fBounds; |
| |
| } |
| |
| /*****************************************************************************/ |
| |
| void dng_image::AcquireTileBuffer (dng_tile_buffer & /* buffer */, |
| const dng_rect & /* area */, |
| bool /* dirty */) const |
| { |
| |
| ThrowProgramError (); |
| |
| } |
| |
| /*****************************************************************************/ |
| |
| void dng_image::ReleaseTileBuffer (dng_tile_buffer & /* buffer */) const |
| { |
| |
| } |
| |
| /*****************************************************************************/ |
| |
| void dng_image::DoGet (dng_pixel_buffer &buffer) const |
| { |
| |
| dng_rect tile; |
| |
| dng_tile_iterator iter (*this, buffer.fArea); |
| |
| while (iter.GetOneTile (tile)) |
| { |
| |
| dng_const_tile_buffer tileBuffer (*this, tile); |
| |
| buffer.CopyArea (tileBuffer, |
| tile, |
| buffer.fPlane, |
| buffer.fPlanes); |
| |
| } |
| |
| } |
| |
| /*****************************************************************************/ |
| |
| void dng_image::DoPut (const dng_pixel_buffer &buffer) |
| { |
| |
| dng_rect tile; |
| |
| dng_tile_iterator iter (*this, buffer.fArea); |
| |
| while (iter.GetOneTile (tile)) |
| { |
| |
| dng_dirty_tile_buffer tileBuffer (*this, tile); |
| |
| tileBuffer.CopyArea (buffer, |
| tile, |
| buffer.fPlane, |
| buffer.fPlanes); |
| |
| } |
| |
| } |
| |
| /*****************************************************************************/ |
| |
| 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 dng_image::GetEdge (dng_pixel_buffer &buffer, |
| edge_option edgeOption, |
| const dng_rect &srcArea, |
| const dng_rect &dstArea) const |
| { |
| |
| switch (edgeOption) |
| { |
| |
| case edge_zero: |
| { |
| |
| buffer.SetZero (dstArea, |
| buffer.fPlane, |
| buffer.fPlanes); |
| |
| break; |
| |
| } |
| |
| case edge_repeat: |
| { |
| |
| GetRepeat (buffer, |
| srcArea, |
| dstArea); |
| |
| break; |
| |
| } |
| |
| case edge_repeat_zero_last: |
| { |
| |
| if (buffer.fPlanes > 1) |
| { |
| |
| dng_pixel_buffer buffer1 (buffer); |
| |
| buffer1.fPlanes--; |
| |
| GetEdge (buffer1, |
| edge_repeat, |
| srcArea, |
| dstArea); |
| |
| } |
| |
| dng_pixel_buffer buffer2 (buffer); |
| |
| buffer2.fPlane = buffer.fPlanes - 1; |
| buffer2.fPlanes = 1; |
| |
| buffer2.fData = buffer.DirtyPixel (buffer2.fArea.t, |
| buffer2.fArea.l, |
| buffer2.fPlane); |
| |
| GetEdge (buffer2, |
| edge_zero, |
| srcArea, |
| dstArea); |
| |
| break; |
| |
| } |
| |
| default: |
| { |
| |
| ThrowProgramError (); |
| |
| } |
| |
| } |
| |
| } |
| |
| /*****************************************************************************/ |
| |
| 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::Put (const dng_pixel_buffer &buffer) |
| { |
| |
| // Move the overlapping pixels. |
| |
| dng_rect overlap = buffer.fArea & fBounds; |
| |
| if (overlap.NotEmpty ()) |
| { |
| |
| dng_pixel_buffer temp (buffer); |
| |
| temp.fArea = overlap; |
| |
| temp.fData = (void *) buffer.ConstPixel (overlap.t, |
| overlap.l, |
| buffer.fPlane); |
| |
| // Move the overlapping planes. |
| |
| if (temp.fPlane < Planes ()) |
| { |
| |
| temp.fPlanes = Min_uint32 (temp.fPlanes, |
| Planes () - temp.fPlane); |
| |
| DoPut (temp); |
| |
| } |
| |
| } |
| |
| } |
| |
| /*****************************************************************************/ |
| |
| void dng_image::Trim (const dng_rect &r) |
| { |
| |
| if (r != Bounds ()) |
| { |
| |
| ThrowProgramError ("Trim is not support by this dng_image subclass"); |
| |
| } |
| |
| } |
| |
| /*****************************************************************************/ |
| |
| void dng_image::Rotate (const dng_orientation &orientation) |
| { |
| |
| if (orientation != dng_orientation::Normal ()) |
| { |
| |
| ThrowProgramError ("Rotate is not support by this dng_image subclass"); |
| |
| } |
| |
| } |
| |
| /*****************************************************************************/ |
| |
| void dng_image::CopyArea (const dng_image &src, |
| const dng_rect &area, |
| uint32 srcPlane, |
| uint32 dstPlane, |
| uint32 planes) |
| { |
| |
| if (&src == this) |
| return; |
| |
| dng_tile_iterator destIter(*this, area); |
| dng_rect destTileArea; |
| |
| while (destIter.GetOneTile(destTileArea)) |
| { |
| dng_tile_iterator srcIter(src, destTileArea); |
| dng_rect srcTileArea; |
| |
| while (srcIter.GetOneTile(srcTileArea)) |
| { |
| |
| dng_dirty_tile_buffer destTile(*this, srcTileArea); |
| dng_const_tile_buffer srcTile(src, srcTileArea); |
| |
| destTile.CopyArea (srcTile, srcTileArea, srcPlane, dstPlane, planes); |
| |
| } |
| |
| } |
| |
| } |
| |
| /*****************************************************************************/ |
| |
| bool dng_image::EqualArea (const dng_image &src, |
| const dng_rect &area, |
| uint32 plane, |
| uint32 planes) const |
| { |
| |
| if (&src == this) |
| return true; |
| |
| dng_tile_iterator destIter (*this, area); |
| |
| dng_rect destTileArea; |
| |
| while (destIter.GetOneTile (destTileArea)) |
| { |
| |
| dng_tile_iterator srcIter (src, destTileArea); |
| |
| dng_rect srcTileArea; |
| |
| while (srcIter.GetOneTile (srcTileArea)) |
| { |
| |
| dng_const_tile_buffer destTile (*this, srcTileArea); |
| dng_const_tile_buffer srcTile (src , srcTileArea); |
| |
| if (!destTile.EqualArea (srcTile, srcTileArea, plane, planes)) |
| { |
| return false; |
| } |
| |
| } |
| |
| } |
| |
| return true; |
| |
| } |
| |
| /*****************************************************************************/ |
| |
| void dng_image::SetConstant (uint32 value, |
| const dng_rect &area) |
| { |
| |
| dng_tile_iterator iter (*this, area); |
| |
| dng_rect tileArea; |
| |
| while (iter.GetOneTile (tileArea)) |
| { |
| |
| dng_dirty_tile_buffer buffer (*this, tileArea); |
| |
| buffer.SetConstant (tileArea, |
| 0, |
| fPlanes, |
| value); |
| |
| } |
| |
| } |
| |
| /*****************************************************************************/ |