protected void DeserializeSoftcopyVoiLut(SoftcopyVoiLutModuleIod module, T image)
        {
            SoftcopyVoiLutModuleIod.SoftcopyVoiLutSequenceItem[] lutSequences = module.SoftcopyVoiLutSequence;
            if (lutSequences == null)
            {
                return;
            }

            DicomVoiLuts voiLuts = (DicomVoiLuts)image.DicomVoiLuts;

            voiLuts.ReinitializePresentationLuts(this.PresentationSopInstanceUid);

            foreach (SoftcopyVoiLutModuleIod.SoftcopyVoiLutSequenceItem lutSequence in lutSequences)
            {
                var dictionary = !DeserializeIgnoreImageRelationship ? new ImageSopInstanceReferenceDictionary(lutSequence.ReferencedImageSequence, true) : null;
                if (dictionary == null || dictionary.ReferencesFrame(image.ImageSop.SopInstanceUid, image.Frame.FrameNumber))
                {
                    if (lutSequence.CountWindows > 0)
                    {
                        double[] widths       = lutSequence.WindowWidth;
                        double[] centers      = lutSequence.WindowCenter;
                        int      countWindows = Math.Min(widths.Length, centers.Length);
                        string[] explanation  = lutSequence.WindowCenterWidthExplanation;
                        if (explanation == null || explanation.Length < countWindows)
                        {
                            explanation = new string[countWindows];
                        }

                        if (lutSequence.VoiLutFunction == VoiLutFunction.Sigmoid)
                        {
                            Platform.Log(LogLevel.Warn, "Sigmoid LUTs are not currently supported.");
                        }
                        else                         // default is linear
                        {
                            for (int n = 0; n < countWindows; n++)
                            {
                                voiLuts.AddPresentationLinearLut(widths[n], centers[n], explanation[n]);
                            }
                        }
                    }

                    if (lutSequence.CountDataLuts > 0)
                    {
                        foreach (VoiLutSequenceItem item in lutSequence.VoiLutSequence)
                        {
                            DataLutIod dl = DataLutIod.Create(item.DicomSequenceItem, item.DicomAttributeProvider[DicomTags.LutDescriptor] is DicomAttributeSS, false);
                            voiLuts.AddPresentationDataLut(new VoiDataLut(dl.FirstMappedPixelValue, dl.BitsPerEntry, dl.Data, dl.Explanation));
                        }
                    }
                }
            }
        }
        protected void SerializeSoftcopyVoiLut(SoftcopyVoiLutModuleIod module, DicomPresentationImageCollection <T> images)
        {
            List <SoftcopyVoiLutModuleIod.SoftcopyVoiLutSequenceItem> voiLutSequenceItems = new List <SoftcopyVoiLutModuleIod.SoftcopyVoiLutSequenceItem>();

            foreach (T image in images)
            {
                if (!image.VoiLutManager.Enabled)
                {
                    continue;
                }

                SoftcopyVoiLutModuleIod.SoftcopyVoiLutSequenceItem sequenceItem = new SoftcopyVoiLutModuleIod.SoftcopyVoiLutSequenceItem();
                sequenceItem.InitializeAttributes();
                sequenceItem.ReferencedImageSequence = new ImageSopInstanceReferenceMacro[] { CreateImageSopInstanceReference(image.Frame) };

                IVoiLut lut = image.VoiLutManager.VoiLut;
                if (lut is IDataLut)
                {
                    IDataLut voiLut = (IDataLut)lut;
                    sequenceItem.VoiLutSequence = new VoiLutSequenceItem[] { SerializeDataLut(voiLut) };
                }
                else if (lut is IVoiLutLinear)
                {
                    IVoiLutLinear voiLut = (IVoiLutLinear)lut;
                    sequenceItem.WindowWidth  = new double[] { voiLut.WindowWidth };
                    sequenceItem.WindowCenter = new double[] { voiLut.WindowCenter };
                    sequenceItem.WindowCenterWidthExplanation = new string[] { SR.LabelPresentationVoiLinearLut };
                    sequenceItem.VoiLutFunction = VoiLutFunction.Linear;                     // we don't support sigmoid
                }
                else
                {
                    // should never happen - all VOI LUT object should implement either interface
                    continue;
                }

                voiLutSequenceItems.Add(sequenceItem);
            }

            if (voiLutSequenceItems.Count > 0)
            {
                module.SoftcopyVoiLutSequence = voiLutSequenceItems.ToArray();
            }
        }