private static IVoiLut GetInitialVoiLut(IGraphic graphic)
		{
			GrayscaleImageGraphic grayImageGraphic = (GrayscaleImageGraphic) graphic;
			IVoiLut lut = InitialVoiLutProvider.Instance.GetLut(graphic.ParentPresentationImage);
			if (lut == null)
				lut = new MinMaxPixelCalculatedLinearLut(grayImageGraphic.PixelData, grayImageGraphic.ModalityLut);
			return lut;
		}
		/// <summary>
		/// Gets the initial VOI LUT for the source frames (base or overlay). This is NOT the LUT used on the fusion image! See <see cref="InstallVoiLut"/>.
		/// </summary>
		private static IVoiLut GetInitialVoiLut(Frame frame)
		{
			if (frame != null)
			{
				using (var image = PresentationImageFactory.Create(frame))
				{
					var voiLut = InitialVoiLutProvider.Instance.GetLut(image);
					if (voiLut == null && image is IImageGraphicProvider)
					{
						var pixelData = ((IImageGraphicProvider) image).ImageGraphic.PixelData;
						if (pixelData is GrayscalePixelData)
							voiLut = new MinMaxPixelCalculatedLinearLut((GrayscalePixelData) pixelData);
					}
					return voiLut;
				}
			}
			return null;
		}
		private MinMaxPixelCalculatedLinearLut(MinMaxPixelCalculatedLinearLut source, ICloningContext context)
			: base(source, context)
		{
			context.CloneFields(source, this);
		}
		/// <summary>
		/// Attempts to install an appropriate equivalent of the specified <paramref name="sourceVoiLut"/> to a fusion image. If the LUT is not linear, computes a dummy LUT.
		/// </summary>
		private static void InstallVoiLut(FusionPresentationImage fusionImage, IVoiLut sourceVoiLut, Frame sourceFrame, bool applyToOverlay)
		{
			IVoiLut newVoiLut;
			if (sourceVoiLut is MinMaxPixelCalculatedLinearLut)
			{
				if (applyToOverlay)
				{
					// if the overlay source image is using a min/max calculated LUT, install a custom calculated LUT that delay-computes min/max from the fusion data
					// we need to delay-compute this because the fusion image graphic is delay-generated, and thus not necessarily available until just before rendering!
					var skipModalityLut = sourceFrame.ParentImageSop.Modality == @"PT" && sourceFrame.IsSubnormalRescale;
					newVoiLut = new FusionOverlayMinMaxVoiLutLinear(fusionImage, !skipModalityLut);
				}
				else
				{
					// if the base source image is using a min/max calculated LUT, install a similarly min/max calculated LUT for the base of the fusion image
					newVoiLut = new MinMaxPixelCalculatedLinearLut(fusionImage.ImageGraphic.PixelData);
				}
			}
			else if (sourceVoiLut is IVoiLutLinear)
			{
				var voiLutLinear = (IVoiLutLinear) sourceVoiLut;
				var normalizedVoiSlope = 1.0;
				var normalizedVoiIntercept = 0.0;
				if (applyToOverlay && sourceFrame.ParentImageSop.Modality == @"PT" && sourceFrame.IsSubnormalRescale)
				{
					// for subnormal PET rescale slope cases, the original VOI windows must be transformed through the same process as what MPR did to the pixel data
					normalizedVoiSlope = sourceFrame.RescaleSlope/fusionImage.OverlayFrameData.OverlayRescaleSlope;
					normalizedVoiIntercept = (sourceFrame.RescaleIntercept - fusionImage.OverlayFrameData.OverlayRescaleIntercept)/fusionImage.OverlayFrameData.OverlayRescaleSlope;
				}
				newVoiLut = new BasicVoiLutLinear(voiLutLinear.WindowWidth*normalizedVoiSlope, voiLutLinear.WindowCenter*normalizedVoiSlope + normalizedVoiIntercept);
			}
			else
			{
				// if the source image is using some non-linear LUT, just install a default pass-through LUT
				newVoiLut = new IdentityVoiLinearLut();
			}

			if (applyToOverlay)
				fusionImage.OverlayVoiLutManager.InstallVoiLut(newVoiLut);
			else
				fusionImage.BaseVoiLutManager.InstallVoiLut(newVoiLut);
		}
 private MinMaxPixelCalculatedLinearLut(MinMaxPixelCalculatedLinearLut source, ICloningContext context)
     : base(source, context)
 {
     context.CloneFields(source, this);
 }