예제 #1
0
파일: Targa.cs 프로젝트: Krakean/Pfim
 /// <summary>
 /// Constructs a targa image from a targa image and raw data
 /// </summary>
 private Targa(TargaHeader header, PfimConfig config, byte[] data, int dataLen)
 {
     _config = config;
     Header  = header;
     Data    = data;
     DataLen = dataLen;
 }
예제 #2
0
        /// <summary>Fills data starting from the bottom left</summary>
        public byte[] BottomLeft(Stream str, TargaHeader header, PfimConfig config)
        {
            var stride     = Util.Stride(header.Width, header.PixelDepthBits);
            var len        = header.Height * stride;
            var data       = config.Allocator.Rent(len);
            var trueStride = header.PixelDepthBytes * header.Width;

            InnerBottomLeft(str, config, data, len, stride, trueStride);
            return(data);
        }
예제 #3
0
파일: Targa.cs 프로젝트: Krakean/Pfim
        private static Targa DecodeTarga(Stream str, PfimConfig config, TargaHeader header)
        {
            var targa = (header.IsCompressed)
                ? (IDecodeTarga)(new CompressedTarga())
                : new UncompressedTarga();

            byte[] data;
            switch (header.Orientation)
            {
            case TargaHeader.TargaOrientation.BottomLeft:
                data = targa.BottomLeft(str, header, config);
                break;

            case TargaHeader.TargaOrientation.BottomRight:
                data = targa.BottomRight(str, header, config);
                break;

            case TargaHeader.TargaOrientation.TopRight:
                data = targa.TopRight(str, header, config);
                break;

            case TargaHeader.TargaOrientation.TopLeft:
                data = targa.TopLeft(str, header, config);
                break;

            default:
                throw new Exception("Targa orientation not recognized");
            }

            var stride = Util.Stride(header.Width, header.PixelDepthBits);
            var len    = header.Height * stride;
            var result = new Targa(header, config, data, len);

            if (config.ApplyColorMap)
            {
                result.ApplyColorMap();
            }

            return(result);
        }
예제 #4
0
파일: Targa.cs 프로젝트: Krakean/Pfim
        internal static IImage CreateWithPartialHeader(Stream str, PfimConfig config, byte[] magic)
        {
            var header = new TargaHeader(str, magic, 4, config);

            return(DecodeTarga(str, config, header));
        }
예제 #5
0
파일: Targa.cs 프로젝트: Krakean/Pfim
        /// <summary>
        /// Creates a targa image from a given stream. The type of targa is determined from the
        /// targa header, which is assumed to be a part of the stream
        /// </summary>
        /// <param name="str">Stream to read the targa image from</param>
        /// <returns>A targa image</returns>
        public static Targa Create(Stream str, PfimConfig config)
        {
            var header = new TargaHeader(str, config);

            return(DecodeTarga(str, config, header));
        }
예제 #6
0
        /// <summary>Fills data starting from the bottom left</summary>
        public byte[] BottomLeft(Stream str, TargaHeader header, PfimConfig config)
        {
            var stride  = Util.Stride(header.Width, header.PixelDepthBits);
            var dataLen = header.Height * stride;
            var data    = config.Allocator.Rent(dataLen);

            if (str is MemoryStream s && s.TryGetBuffer(out var arr))
            {
                return(FastPass(data, arr, header, stride, s.Position));
            }

            int dataIndex       = dataLen - stride;
            int bytesPerPixel   = header.PixelDepthBytes;
            int fileBufferIndex = 0;

            // Calculate the maximum number of bytes potentially needed from the buffer.
            // If our buffer doesn't have enough to decode the maximum number of bytes,
            // fetch another batch of bytes from the stream.
            int maxRead = bytesPerPixel * 128 + 1;

            byte[] filebuffer = config.Allocator.Rent(config.BufferSize);
            try
            {
                int workingSize = str.Read(filebuffer, 0, config.BufferSize);
                while (dataIndex >= 0)
                {
                    int colIndex = 0;
                    do
                    {
                        if (config.BufferSize - fileBufferIndex < maxRead && workingSize == config.BufferSize)
                        {
                            workingSize     = Util.Translate(str, filebuffer, config.BufferSize, fileBufferIndex);
                            fileBufferIndex = 0;
                        }

                        bool isRunLength = (filebuffer[fileBufferIndex] & 128) != 0;
                        int  count       = isRunLength ? bytesPerPixel + 1 : filebuffer[fileBufferIndex] + 1;

                        // If the first bit is on, it means that the next packet is run length encoded
                        if (isRunLength)
                        {
                            RunLength(data, filebuffer, dataIndex, fileBufferIndex, bytesPerPixel);
                            dataIndex       += (filebuffer[fileBufferIndex] - 127) * bytesPerPixel;
                            colIndex        += filebuffer[fileBufferIndex] - 127;
                            fileBufferIndex += count;
                        }
                        else
                        {
                            int bytcount = count * bytesPerPixel;
                            fileBufferIndex++;

                            Buffer.BlockCopy(filebuffer, fileBufferIndex, data, dataIndex, bytcount);
                            fileBufferIndex += bytcount;
                            colIndex        += count;
                            dataIndex       += bytcount;
                        }
                    } while (colIndex < header.Width);
                    dataIndex -= bytesPerPixel * header.Width + stride;
                }

                return(data);
            }
            finally
            {
                config.Allocator.Return(filebuffer);
            }
        }
예제 #7
0
 public byte[] TopRight(Stream str, TargaHeader header, PfimConfig config)
 {
     return(BottomLeft(str, header, config));
 }
예제 #8
0
        unsafe byte[] FastPass(byte[] data, ArraySegment <byte> arr, TargaHeader header, int stride, long arrPosition)
        {
            var dataLen       = header.Height * stride;
            int bytesPerPixel = header.PixelDepthBytes;

            fixed(byte *startDataPtr = data)
            fixed(byte *fixedInputPtr = &arr.Array[arrPosition])
            {
                byte *endSentinal = startDataPtr + dataLen;
                byte *dataPtr     = endSentinal - stride;
                byte *inputPtr    = fixedInputPtr;

                while (dataPtr >= startDataPtr)
                {
                    int pixelIndex = 0;
                    do
                    {
                        bool isRunLength = (*inputPtr & 128) != 0;
                        if (isRunLength)
                        {
                            var run = *inputPtr++ - 127;

                            if (bytesPerPixel == 3)
                            {
                                RunLength3(dataPtr, run, *inputPtr++, *inputPtr++, *inputPtr++);
                            }
                            else if (bytesPerPixel == 4)
                            {
                                byte color0 = *inputPtr++;
                                byte color1 = *inputPtr++;
                                byte color2 = *inputPtr++;
                                byte color3 = *inputPtr++;
                                var  comb   = (color0 | color1 << 8 | color2 << 16 | color3 << 24);
                                Util.memset((int *)dataPtr, comb, run * 4);
                            }
                            else if (bytesPerPixel == 1)
                            {
                                Util.memset(dataPtr, *inputPtr++, run);
                            }
                            else if (bytesPerPixel == 2)
                            {
                                byte color0 = *inputPtr++;
                                byte color1 = *inputPtr++;
                                var  comb   = color0 | color1 << 8 | color0 << 16 | color1 << 24;
                                Util.memset((int *)dataPtr, comb, run * 2);
                            }

                            dataPtr    += run * bytesPerPixel;
                            pixelIndex += run;
                        }
                        else
                        {
                            int pixels = *inputPtr++ + 1;
                            int bytes  = pixels * bytesPerPixel;
                            Buffer.MemoryCopy(inputPtr, dataPtr, endSentinal - dataPtr, bytes);
                            dataPtr    += bytes;
                            pixelIndex += pixels;
                            inputPtr   += bytes;
                        }
                    } while (pixelIndex < header.Width);
                    dataPtr -= bytesPerPixel * header.Width + stride;
                }
            }

            return(data);
        }