Beispiel #1
0
        public static (Image image, ImageMetadata metadata) ExtractCurrentFrame(Tiff tiff)
        {
            // read image properties
            int width           = GetTagInt32(TiffTag.IMAGEWIDTH, null);
            int height          = GetTagInt32(TiffTag.IMAGELENGTH, null);
            int samplesPerPixel = GetTagInt32(TiffTag.SAMPLESPERPIXEL, 1);
            int bitsPerSample   = GetTagInt32(TiffTag.BITSPERSAMPLE, 1);
            int xres            = GetTagInt32(TiffTag.XRESOLUTION, 200);
            int yres            = GetTagInt32(TiffTag.YRESOLUTION, 200);
            int photometric     = GetTagInt32(TiffTag.PHOTOMETRIC, (int)TIFFPhotometricInterpretation.WhiteIsZero);

            Image image = null;

            if (photometric == (int)TIFFPhotometricInterpretation.YCbCr)
            {
                // special case for YCbCr photometric - read image as rgba
                image = new Image(width, height, 32, xres, yres);

                int   imageSize = height * width;
                int[] buffer    = new int[imageSize];

                // Read the image into the memory buffer
                if (tiff.ReadRGBAImageOriented(width, height, buffer, Orientation.TOPLEFT))
                {
                    unsafe
                    {
                        fixed(int *src = buffer)
                        {
                            fixed(ulong *dst = image.Bits)
                            {
                                Arrays.CopyStrides(image.Height, new IntPtr(src), width * sizeof(int), new IntPtr(dst), image.Stride8);
                            }
                        }
                    }
                }
            }
            else
            {
                image = new Image(width, height, samplesPerPixel * bitsPerSample, xres, yres);

                // read bytes
                int    scanlineSize = tiff.ScanlineSize();
                byte[] buffer       = new byte[Math.Max(scanlineSize, image.Stride8)];
                for (int i = 0, offdst = 0; i < height; i++, offdst += image.Stride)
                {
                    if (!tiff.ReadScanline(buffer, 0, i, 0))
                    {
                        throw new InvalidOperationException(Properties.Resources.E_CannotDecodeImage);
                    }

                    if (image.BitsPerPixel < 8)
                    {
                        unsafe
                        {
                            fixed(ulong *dst = &image.Bits[offdst])
                            {
                                fixed(byte *src = buffer)
                                {
                                    Vectors.SwapBits(image.Stride, (ulong *)src, image.BitsPerPixel, dst);
                                }
                            }
                        }
                    }
                    else
                    {
                        Buffer.BlockCopy(buffer, 0, image.Bits, offdst, image.Stride8);
                    }
                }
            }

            // read all set tags
            ImageMetadata metadata = new ImageMetadata();

            foreach (TiffFieldInfo fip in tiff.EnumFieldInfo(TiffType.ANY))
            {
                object value = GetTag(fip);
                if (value != null)
                {
                    metadata.SetPropertyItem((int)fip.Tag, value);
                }
            }

            return(image, metadata);

            int GetTagInt32(TiffTag tag, int?defaultValue)
            {
                FieldValue[] values = tiff.GetField(tag);
                if (values != null && values.Length > 0)
                {
                    return(values[0].ToInt());
                }

                if (!defaultValue.HasValue)
                {
                    throw new InvalidOperationException();
                }

                return(defaultValue.Value);
            }

            object GetTag(TiffFieldInfo fip)
            {
                object convertedValue = null;

                if (CanLoadTag((int)fip.Tag))
                {
                    FieldValue[] value = tiff.GetField(fip.Tag);
                    if (value != null && value.Length > 0)
                    {
                        try
                        {
                            if (value.Length == 1)
                            {
                                convertedValue = ConvertFieldValue(fip.Type, value[0]);
                            }
                            else if (value.Length == 2 && fip.PassCount)
                            {
                                convertedValue = ConvertFieldValue(fip.Type, value[1]);
                            }
                            else
                            {
                                convertedValue = CastFieldValues(fip.Type, value.Select(x => ConvertFieldValue(fip.Type, x)).ToArray());
                            }
                        }
                        catch
                        {
                        }
                    }
                }

                return(convertedValue);

                bool CanLoadTag(int id)
                {
                    if (id == (int)TIFFField.RowsPerStrip ||
                        id == (int)TIFFField.StripByteCounts ||
                        id == (int)TIFFField.StripOffsets ||
                        id == (int)TIFFField.TileByteCounts ||
                        id == (int)TIFFField.TileOffsets)
                    {
                        return(false);
                    }

                    return(true);
                }

                object ConvertFieldValue(TiffType type, FieldValue value)
                {
                    switch (type)
                    {
                    case TiffType.BYTE:
                        return(value.Value is Array ? (object)value.ToByteArray() : value.ToByte());

                    case TiffType.SBYTE:
                        return(value.Value is Array ? (object)value.ToSByteArray() : value.ToSByte());

                    case TiffType.SHORT:
                        return(value.Value is Array ? (object)value.ToUShortArray() : value.ToUShort());

                    case TiffType.SSHORT:
                        return(value.Value is Array ? (object)value.ToShortArray() : value.ToShort());

                    case TiffType.LONG:
                    case TiffType.IFD:
                        return(value.Value is Array ? (object)value.ToUIntArray() : value.ToUInt());

                    case TiffType.SLONG:
                        return(value.Value is Array ? (object)value.ToIntArray() : value.ToInt());

                    case TiffType.LONG8:
                    case TiffType.IFD8:
                    case TiffType.SLONG8:
                        return(value.Value is Array ? (object)value.TolongArray() : value.ToLong());

                    case TiffType.RATIONAL:
                    case TiffType.SRATIONAL:
                    case TiffType.FLOAT:
                        return(value.Value is Array ? (object)value.ToFloatArray() : value.ToFloat());

                    case TiffType.DOUBLE:
                        return(value.Value is Array ? (object)value.ToDoubleArray() : value.ToDouble());

                    case TiffType.ASCII:
                        if (value.Value is byte[])
                        {
                            return(Encoding.GetEncoding("Latin1").GetString(value.Value as byte[]).TrimEnd(new[] { '\0' }));
                        }
                        else
                        {
                            return(Convert.ToString(value, CultureInfo.InvariantCulture));
                        }

                    default:
                        return(value.ToString());
                    }
                }

                object CastFieldValues(TiffType type, object[] values)
                {
                    switch (type)
                    {
                    case TiffType.BYTE:
                        return(Cast <byte>());

                    case TiffType.SBYTE:
                        return(Cast <sbyte>());

                    case TiffType.SHORT:
                        return(Cast <ushort>());

                    case TiffType.SSHORT:
                        return(Cast <short>());

                    case TiffType.LONG:
                    case TiffType.IFD:
                        return(Cast <uint>());

                    case TiffType.SLONG:
                        return(Cast <int>());

                    case TiffType.LONG8:
                    case TiffType.IFD8:
                        return(Cast <ulong>());

                    case TiffType.SLONG8:
                        return(Cast <long>());

                    case TiffType.RATIONAL:
                    case TiffType.SRATIONAL:
                    case TiffType.FLOAT:
                        return(Cast <float>());

                    case TiffType.DOUBLE:
                        return(Cast <double>());

                    case TiffType.ASCII:
                        return(Cast <string>());

                    default:
                        return(values);
                    }

                    object Cast <T>()
                    {
                        return(values.All(x => x is T) ? (object)values.Cast <T>().ToArray() : values);
                    }
                }
            }
        }