/// <summary> /// Fills the <see cref="OverlayData"/> property with the overlay(s) that had been encoded /// in the <see cref="DicomTags.PixelData"/> of the SOP Instance. If the image is a /// multi-frame, overlay data is extracted from all the frames. /// </summary> /// <param name="pd">The pixel data that contains the encoded overlay(s).</param> /// <exception cref="DicomException">Thrown if <paramref name="pd"/> is not a valid source of embedded overlay data.</exception> /// <returns>True if the <see cref="OverlayData"/> was populated with data encoded in the pixel data; False if <see cref="OverlayData"/> is not empty.</returns> public unsafe bool ExtractEmbeddedOverlay(DicomUncompressedPixelData pd) { byte[] overlayData = this.OverlayData; if (overlayData != null && overlayData.Length > 0) { return(false); } // General sanity checks if (pd.SamplesPerPixel > 1) { throw new DicomException("Unable to convert embedded overlays when Samples Per Pixel > 1"); } if (pd.BitsStored == 8 && pd.BitsAllocated == 8) { throw new DicomException("Unable to remove overlay with 8 Bits Stored and 8 Bits Allocated"); } if (pd.BitsStored == 16 && pd.BitsAllocated == 16) { throw new DicomException("Unable to remove overlay with 16 Bits Stored and 16 Bits Allocated"); } if (OverlayBitPosition <= pd.HighBit && OverlayBitPosition >= pd.LowBit) { throw new DicomException(String.Format("Invalid overlay bit position ({0}); overlay would be in the middle of the pixel data.", OverlayBitPosition)); } int frameSize = pd.UncompressedFrameSize; int overlayDataLength = (int)Math.Ceiling((frameSize * pd.NumberOfFrames) / (pd.BitsAllocated * 1d)); int frameLength = frameSize / pd.BytesAllocated; // Ensure even length overlay if (overlayDataLength % 2 == 1) { overlayDataLength++; } overlayData = new byte[overlayDataLength]; int overlayOffset = 0; byte overlayMask = 0x01; if (pd.BitsAllocated <= 8) { var embeddedOverlayMask = ((byte)(0x1 << OverlayBitPosition)); // Embededded overlays must exist for all frames, they can't be for a subset for (int i = 0; i < pd.NumberOfFrames; i++) { byte[] frameData = pd.GetFrame(i); ExtractEmbeddedOverlay(frameData, frameLength, embeddedOverlayMask, overlayData, ref overlayOffset, ref overlayMask); pd.ReplaceFrame(i, frameData); } } else { var embeddedOverlayMask = ((ushort)(0x1 << OverlayBitPosition)); // Embededded overlays must exist for all frames, they can't be for a subset for (int i = 0; i < pd.NumberOfFrames; i++) { byte[] frameData = pd.GetFrame(i); ExtractEmbeddedOverlay(frameData, frameLength, embeddedOverlayMask, overlayData, ref overlayOffset, ref overlayMask); pd.ReplaceFrame(i, frameData); } } // Assign the new overlay tags this.OverlayBitPosition = 0; this.OverlayBitsAllocated = 1; if (this.IsBigEndianOW) { // Just do a bulk swap, performance isn't much of an issue. ByteBuffer buffer = new ByteBuffer(overlayData, Endian.Little); buffer.Swap2(); this.OverlayData = buffer.ToBytes(); } else { this.OverlayData = overlayData; } // Cleanup Rows/Columns if necessary if (this.OverlayColumns == 0) { this.OverlayColumns = pd.ImageWidth; } if (this.OverlayRows == 0) { this.OverlayRows = pd.ImageHeight; } return(true); }