Esempio n. 1
0
        public byte[] ReadRGB8(string filename, byte[] bytes, out int width, out int height, out int numChannels, bool downSample = false)
        {
            width       = 0;
            height      = 0;
            numChannels = 0;

            Stream stream = null;

            if (bytes == null)
            {
                try
                {
                    bytes = File.ReadAllBytes(filename);
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.ToString());
                    return(null);
                }
            }
            stream = new MemoryStream(bytes);

            BinaryParser SGIReader = new BinaryParser(bytes);

            /** Read Header **/
            short magic = SGIReader.Int16BE();    // 474


            if (magic != 474)
            {
                Console.WriteLine(string.Format("file {0} does not match SGI format specifications. The file type declared in the header is not SGI.", filename));
                return(null);
            }

            Storage = (sbyte)SGIReader.Byte();                // 0 or 1: 0 -> Verbatim, 1 -> Run Length Encoding
            BytesPerPixelComponent = (sbyte)SGIReader.Byte(); // 1 or 2: 1 -> 1 byte per component, 2 -> 2 bytes per component
            Dimension = SGIReader.UInt16BE();                 // 1, 2, or 3 -> Number of Channels (Max 3, see ZSIZE)
            xSize     = SGIReader.UInt16BE();                 // Column Size
            ySize     = SGIReader.UInt16BE();                 // Row Size
            zSize     = SGIReader.UInt16BE();                 // Number of channels (can be any value)
            width     = xSize;
            height    = ySize;
            PixMin    = SGIReader.Int32BE();  // Min pixel value (e.g. 0)
            PixMax    = SGIReader.Int32BE();  // Max pixel value (e.g. 255)
            //var EmptySpace = new string(SGIReader.ReadChars(4));
            SGIReader.Position += 4;          //.ReadChars(4);
            //ImageName = OpenFlight.FltReader.GetString(SGIReader.ReadBytes(80));
            SGIReader.Position += 80;
            ColorMapID          = SGIReader.Int32BE(); // used for Run Length Encoding
            if (ColorMapID != 0)
            {
                Console.WriteLine(string.Format("unsupported color map id {0} in file {1}", ColorMapID, filename));
                return(null);
            }

            //var Dummy = new string(SGIReader.ReadChars(404));
            SGIReader.Position += 404;

            if (Dimension == 1)
            {
                numChannels = 1;
            }
            else if (Dimension == 2)
            {
                numChannels = 1;
            }
            else if (Dimension == 3)
            {
                numChannels = zSize;
            }
            else
            {
                Console.WriteLine(string.Format("unknown number of channels in {0}", filename));
                return(null);
            }

            imageDataRGB8 = new byte[xSize * ySize * numChannels];

            // Re-structure array for RGB[A] sequence
            if (Storage == 0)
            {
                ImageLength = bytes.Length - 512; // SGI Headers are 512 bytes
                //ImageLength = new FileInfo(filename).Length - 512;

                bool abort = false;
                for (int channel = 0; channel < numChannels; ++channel)         // 3 or 4 channels (RGB[A])
                {
                    for (int offset = channel; offset < ImageLength; offset += numChannels)
                    {
                        //If it's a 16 bit value, for now we'll just ignore the least significant byte
                        try
                        {
                            byte fval = BytesPerPixelComponent == 1 ? SGIReader.Byte() : (byte)(SGIReader.Int16BE() >> 8);
                            imageDataRGB8[offset] = fval;
                        }
                        catch (Exception)// ex)
                        {
                            //Console.WriteLine(ex.ToString());
                            abort = true;
                            break;
                        }
                    }
                    if (abort)
                    {
                        break;
                    }
                }
            }
            else// RLE
            {
                // TODO: leverage start offset and length tables if and when we have data that uses them
                // Table of start offsets
                int numScanlines = ySize;

                //uint[,] startTable = new uint[numChannels, numScanlines];
                for (int channel = 0; channel < numChannels; ++channel)
                {
                    for (int scanline = 0; scanline < numScanlines; ++scanline)
                    {
                        //startTable[channel, scanline] = SGIReader.ReadUInt32Big();
                        SGIReader.UInt32BE();
                    }
                }

                // Table of lengths
                //uint[,] lengthTable = new uint[numChannels, numScanlines];
                for (int channel = 0; channel < numChannels; ++channel)
                {
                    for (int scanline = 0; scanline < numScanlines; ++scanline)
                    {
                        //lengthTable[channel, scanline] = SGIReader.ReadUInt32Big();
                        SGIReader.UInt32BE();
                    }
                }

                // RLE data
                if (BytesPerPixelComponent == 1)
                {
                    byte[] byteArray   = SGIReader.Bytes;
                    int    inputIndex  = SGIReader.Position;
                    int    outputIndex = 0;

                    while (outputIndex < imageDataRGB8.Length)
                    {
                        byte val   = byteArray[inputIndex];
                        int  count = val & 0x7f;
                        if (count == 0)
                        {
                            inputIndex++;
                            continue;
                        }

                        bool flag = (val & 0x80) != 0;
                        if (flag)
                        {
                            while ((count--) != 0)
                            {
                                byte nextVal = byteArray[inputIndex + 1];
                                imageDataRGB8[outputIndex] = nextVal;
                                inputIndex++;
                                outputIndex++;
                            }

                            inputIndex++;
                        }
                        else
                        {
                            byte nextVal = byteArray[inputIndex + 1];
                            while ((count--) != 0)
                            {
                                imageDataRGB8[outputIndex] = nextVal;
                                outputIndex++;
                            }

                            inputIndex += 2;
                        }
                    }

                    if (inputIndex != byteArray.Length - 1 || outputIndex != imageDataRGB8.Length)
                    {
                        Console.WriteLine(string.Format("did not complete read of {0}", filename));
                    }

                    var tempBuffer = new byte[xSize * ySize * numChannels];
                    Array.Copy(imageDataRGB8, tempBuffer, imageDataRGB8.Length);
                    //Convert to interleaved
                    int pixelLen = width * height;
                    for (int i = 0; i < pixelLen; i++)
                    {
                        for (int channel = 0; channel < numChannels; channel++)
                        {
                            imageDataRGB8[(i * numChannels) + channel] = tempBuffer[(pixelLen * channel) + i];
                        }
                    }
                }
                else // TODO: handle shorts
                {
                    Console.WriteLine(string.Format("unsupported BytesPerPixelComponent: {0} in {1}", BytesPerPixelComponent, filename));
                    return(null);
                }
            }

            if (downSample)
            {
                var downSampleBuffer = Downsample(imageDataRGB8, ref width, ref height, numChannels);
                return(downSampleBuffer);
            }

            return(imageDataRGB8);
        }