BitMiracle.LibTiff.Classic.TiffRgbaImage.pickSeparateCase C# (CSharp) Method

pickSeparateCase() private method

Select the appropriate conversion routine for unpacked data. NB: we assume that unpacked single channel data is directed to the "packed routines.
private pickSeparateCase ( ) : bool
return bool
        private bool pickSeparateCase()
        {
            get = tif.IsTiled() ? new GetDelegate(gtTileSeparate) : new GetDelegate(gtStripSeparate);
            putSeparate = null;

            switch (photometric)
            {
                case Photometric.RGB:
                    switch (bitspersample)
                    {
                        case 8:
                            if (alpha == ExtraSample.ASSOCALPHA)
                                putSeparate = putRGBAAseparate8bittile;
                            else if (alpha == ExtraSample.UNASSALPHA)
                                putSeparate = putRGBUAseparate8bittile;
                            else
                                putSeparate = putRGBseparate8bittile;
                            break;

                        case 16:
                            if (alpha == ExtraSample.ASSOCALPHA)
                                putSeparate = putRGBAAseparate16bittile;
                            else if (alpha == ExtraSample.UNASSALPHA)
                                putSeparate = putRGBUAseparate16bittile;
                            else
                                putSeparate = putRGBseparate16bittile;
                            break;
                    }
                    break;

                case Photometric.YCBCR:
                    if ((bitspersample == 8) && (samplesperpixel == 3))
                    {
                        if (initYCbCrConversion())
                        {
                            FieldValue[] result = tif.GetFieldDefaulted(TiffTag.YCBCRSUBSAMPLING);
                            short hs = result[0].ToShort();
                            short vs = result[0].ToShort();

                            switch (((ushort)hs << 4) | (ushort)vs)
                            {
                                case 0x11:
                                    putSeparate = putseparate8bitYCbCr11tile;
                                    break;
                                // TODO: add other cases here
                            }
                        }
                    }
                    break;
            }

            return (putSeparate != null);
        }

Usage Example

        /// <summary>
        /// Creates new instance of the <see cref="TiffRgbaImage"/> class.
        /// </summary>
        /// <param name="tif">
        /// The instance of the <see cref="BitMiracle.LibTiff.Classic"/> class used to retrieve
        /// image data.
        /// </param>
        /// <param name="stopOnError">
        /// if set to <c>true</c> then an error will terminate the conversion; otherwise "get"
        /// methods will continue processing data until all the possible data in the image have
        /// been requested.
        /// </param>
        /// <param name="errorMsg">The error message (if any) gets placed here.</param>
        /// <returns>
        /// New instance of the <see cref="TiffRgbaImage"/> class if the image specified
        /// by <paramref name="tif"/> can be converted to RGBA format; otherwise, <c>null</c> is
        /// returned and <paramref name="errorMsg"/> contains the reason why it is being
        /// rejected.
        /// </returns>
        public static TiffRgbaImage Create(Tiff tif, bool stopOnError, out string errorMsg)
        {
            errorMsg = null;

            // Initialize to normal values
            TiffRgbaImage img = new TiffRgbaImage();
            img.row_offset = 0;
            img.col_offset = 0;
            img.redcmap = null;
            img.greencmap = null;
            img.bluecmap = null;
            img.req_orientation = Orientation.BOTLEFT; // It is the default
            img.tif = tif;
            img.stoponerr = stopOnError;

            FieldValue[] result = tif.GetFieldDefaulted(TiffTag.BITSPERSAMPLE);
            img.bitspersample = result[0].ToShort();
            switch (img.bitspersample)
            {
                case 1:
                case 2:
                case 4:
                case 8:
                case 16:
                    break;

                default:
                    errorMsg = string.Format(CultureInfo.InvariantCulture,
                        "Sorry, can not handle images with {0}-bit samples", img.bitspersample);
                    return null;
            }

            img.alpha = 0;
            result = tif.GetFieldDefaulted(TiffTag.SAMPLESPERPIXEL);
            img.samplesperpixel = result[0].ToShort();

            result = tif.GetFieldDefaulted(TiffTag.EXTRASAMPLES);
            short extrasamples = result[0].ToShort();
            byte[] sampleinfo = result[1].ToByteArray();

            if (extrasamples >= 1)
            {
                switch ((ExtraSample)sampleinfo[0])
                {
                    case ExtraSample.UNSPECIFIED:
                        if (img.samplesperpixel > 3)
                        {
                            // Workaround for some images without correct info about alpha channel
                            img.alpha = ExtraSample.ASSOCALPHA;
                        }
                        break;

                    case ExtraSample.ASSOCALPHA:
                        // data is pre-multiplied
                    case ExtraSample.UNASSALPHA:
                        // data is not pre-multiplied
                        img.alpha = (ExtraSample)sampleinfo[0];
                        break;
                }
            }

            if (Tiff.DEFAULT_EXTRASAMPLE_AS_ALPHA)
            {
                result = tif.GetField(TiffTag.PHOTOMETRIC);
                if (result == null)
                    img.photometric = Photometric.MINISWHITE;

                if (extrasamples == 0 && img.samplesperpixel == 4 && img.photometric == Photometric.RGB)
                {
                    img.alpha = ExtraSample.ASSOCALPHA;
                    extrasamples = 1;
                }
            }

            int colorchannels = img.samplesperpixel - extrasamples;

            result = tif.GetFieldDefaulted(TiffTag.COMPRESSION);
            Compression compress = (Compression)result[0].ToInt();

            result = tif.GetFieldDefaulted(TiffTag.PLANARCONFIG);
            PlanarConfig planarconfig = (PlanarConfig)result[0].ToShort();

            result = tif.GetField(TiffTag.PHOTOMETRIC);
            if (result == null)
            {
                switch (colorchannels)
                {
                    case 1:
                        if (img.isCCITTCompression())
                            img.photometric = Photometric.MINISWHITE;
                        else
                            img.photometric = Photometric.MINISBLACK;
                        break;

                    case 3:
                        img.photometric = Photometric.RGB;
                        break;

                    default:
                        errorMsg = string.Format(CultureInfo.InvariantCulture, "Missing needed {0} tag", photoTag);
                        return null;
                }
            }
            else
                img.photometric = (Photometric)result[0].ToInt();

            switch (img.photometric)
            {
                case Photometric.PALETTE:
                    result = tif.GetField(TiffTag.COLORMAP);
                    if (result == null)
                    {
                        errorMsg = string.Format(CultureInfo.InvariantCulture, "Missing required \"Colormap\" tag");
                        return null;
                    }

                    short[] red_orig = result[0].ToShortArray();
                    short[] green_orig = result[1].ToShortArray();
                    short[] blue_orig = result[2].ToShortArray();

                    // copy the colormaps so we can modify them
                    int n_color = (1 << img.bitspersample);
                    img.redcmap = new ushort[n_color];
                    img.greencmap = new ushort[n_color];
                    img.bluecmap = new ushort[n_color];

                    Buffer.BlockCopy(red_orig, 0, img.redcmap, 0, n_color * sizeof(ushort));
                    Buffer.BlockCopy(green_orig, 0, img.greencmap, 0, n_color * sizeof(ushort));
                    Buffer.BlockCopy(blue_orig, 0, img.bluecmap, 0, n_color * sizeof(ushort));

                    if (planarconfig == PlanarConfig.CONTIG &&
                        img.samplesperpixel != 1 && img.bitspersample < 8)
                    {
                        errorMsg = string.Format(CultureInfo.InvariantCulture,
                            "Sorry, can not handle contiguous data with {0}={1}, and {2}={3} and Bits/Sample={4}",
                            photoTag, img.photometric, "Samples/pixel", img.samplesperpixel, img.bitspersample);
                        return null;
                    }
                    break;

                case Photometric.MINISWHITE:
                case Photometric.MINISBLACK:
                    if (planarconfig == PlanarConfig.CONTIG &&
                        img.samplesperpixel != 1 && img.bitspersample < 8)
                    {
                        errorMsg = string.Format(CultureInfo.InvariantCulture,
                            "Sorry, can not handle contiguous data with {0}={1}, and {2}={3} and Bits/Sample={4}",
                            photoTag, img.photometric, "Samples/pixel", img.samplesperpixel, img.bitspersample);
                        return null;
                    }
                    break;

                case Photometric.YCBCR:
                    // It would probably be nice to have a reality check here.
                    if (planarconfig == PlanarConfig.CONTIG)
                    {
                        // can rely on LibJpeg.Net to convert to RGB
                        // XXX should restore current state on exit
                        switch (compress)
                        {
                            case Compression.JPEG:
                                // TODO: when complete tests verify complete desubsampling and
                                // YCbCr handling, remove use of JPEGCOLORMODE in favor of native
                                // handling
                                tif.SetField(TiffTag.JPEGCOLORMODE, JpegColorMode.RGB);
                                img.photometric = Photometric.RGB;
                                break;

                            default:
                                // do nothing
                                break;
                        }
                    }

                    // TODO: if at all meaningful and useful, make more complete support check
                    // here, or better still, refactor to let supporting code decide whether there
                    // is support and what meaningfull error to return
                    break;

                case Photometric.RGB:
                    if (colorchannels < 3)
                    {
                        errorMsg = string.Format(CultureInfo.InvariantCulture,
                            "Sorry, can not handle RGB image with {0}={1}", "Color channels", colorchannels);
                        return null;
                    }
                    break;

                case Photometric.SEPARATED:
                    result = tif.GetFieldDefaulted(TiffTag.INKSET);
                    InkSet inkset = (InkSet)result[0].ToByte();

                    if (inkset != InkSet.CMYK)
                    {
                        errorMsg = string.Format(CultureInfo.InvariantCulture,
                            "Sorry, can not handle separated image with {0}={1}", "InkSet", inkset);
                        return null;
                    }

                    if (img.samplesperpixel < 4)
                    {
                        errorMsg = string.Format(CultureInfo.InvariantCulture,
                            "Sorry, can not handle separated image with {0}={1}", "Samples/pixel", img.samplesperpixel);
                        return null;
                    }
                    break;

                case Photometric.LOGL:
                    if (compress != Compression.SGILOG)
                    {
                        errorMsg = string.Format(CultureInfo.InvariantCulture,
                            "Sorry, LogL data must have {0}={1}", "Compression", Compression.SGILOG);
                        return null;
                    }

                    tif.SetField(TiffTag.SGILOGDATAFMT, 3); // 8-bit RGB monitor values. 
                    img.photometric = Photometric.MINISBLACK; // little white lie
                    img.bitspersample = 8;
                    break;

                case Photometric.LOGLUV:
                    if (compress != Compression.SGILOG && compress != Compression.SGILOG24)
                    {
                        errorMsg = string.Format(CultureInfo.InvariantCulture,
                            "Sorry, LogLuv data must have {0}={1} or {2}", "Compression", Compression.SGILOG, Compression.SGILOG24);
                        return null;
                    }

                    if (planarconfig != PlanarConfig.CONTIG)
                    {
                        errorMsg = string.Format(CultureInfo.InvariantCulture,
                            "Sorry, can not handle LogLuv images with {0}={1}", "Planarconfiguration", planarconfig);
                        return null;
                    }

                    tif.SetField(TiffTag.SGILOGDATAFMT, 3); // 8-bit RGB monitor values. 
                    img.photometric = Photometric.RGB; // little white lie
                    img.bitspersample = 8;
                    break;

                case Photometric.CIELAB:
                    break;

                default:
                    errorMsg = string.Format(CultureInfo.InvariantCulture,
                        "Sorry, can not handle image with {0}={1}", photoTag, img.photometric);
                    return null;
            }

            img.Map = null;
            img.BWmap = null;
            img.PALmap = null;
            img.ycbcr = null;
            img.cielab = null;

            result = tif.GetField(TiffTag.IMAGEWIDTH);
            img.width = result[0].ToInt();

            result = tif.GetField(TiffTag.IMAGELENGTH);
            img.height = result[0].ToInt();

            result = tif.GetFieldDefaulted(TiffTag.ORIENTATION);
            img.orientation = (Orientation)result[0].ToByte();

            img.isContig = !(planarconfig == PlanarConfig.SEPARATE && colorchannels > 1);
            if (img.isContig)
            {
                if (!img.pickContigCase())
                {
                    errorMsg = "Sorry, can not handle image";
                    return null;
                }
            }
            else
            {
                if (!img.pickSeparateCase())
                {
                    errorMsg = "Sorry, can not handle image";
                    return null;
                }
            }

            return img;
        }