images in webserver

Feb 25, 2010 at 11:47 AM

Hello,

is it somehow possible to have a static webpage with some images stored in Resources? I mean the web page can be treated just as

string and sent to client, but i have been unable so far to send image file. I can get the image from resources

Bitmap image = Resources.GetBitmap(Resources.BitmapResources.imageId);

But what to do then? how to read bytes from these image and send them to client? Or is there some other way? I dont want to use SD card

or anything external, that would be a waste of resources.

 

Thank you

Coordinator
Feb 25, 2010 at 8:49 PM

Hi weirdo777,

yes, this is possible, of course.  ;)

Here is a short how-to:

  1. Rename your image xxxx.jpg to xxxx.bin
  2. Open Resources.resx and select the type files (instead of type images)
  3. Click on add new file, select file filter *.*
  4. Select the image xxxx.bin which will be added as xxxx resource
  5. Use following code in your HttpHandler:

if (context.Request.RawUrl == "/xxxx.jpg")
{
    context.Response.ContentType = "images/jpeg";
    context.Response.Write(Resources.GetBytes(Resources.BinaryResources.xxxx));
}

Does this help?

If  you want to use the SD card you need to read the bytes from it and then use context.Response.Write(byte[]).

Regards,
Michael

 

Mar 1, 2010 at 10:09 AM
Yes thank for your response. I kind of figure out this few hours later after i wrote my question.
But now i can be certain that there is nothing better ;).
Well just keep up the good work and one more time, thanks for the quick reply.

Roman

On Thu, Feb 25, 2010 at 10:49 PM, interactive <notifications@codeplex.com> wrote:

From: interactive

Hi weirdo777,

yes, this is possible, of course.  ;)

Here is a short how-to:

  1. Rename your image xxxx.jpg to xxxx.bin
  2. Open Resources.resx and select the type files (instead of type images)
  3. Click on add new file, select file filter *.*
  4. Select the image xxxx.bin which will be added as xxxx resource
  5. Use following code in your HttpHandler:

if (context.Request.RawUrl == "/xxxx.jpg")
{
    context.Response.ContentType = "images/jpeg";
    context.Response.Write(Resources.GetBytes(Resources.BinaryResources.xxxx));
}

Does this help?

If  you want to use the SD card you need to read the bytes from it and then use context.Response.Write(byte[]).

Regards,
Michael

 

Read the full discussion online.

To add a post to this discussion, reply to this email (mftoolkit@discussions.codeplex.com)

To start a new discussion for this project, email mftoolkit@discussions.codeplex.com

You are receiving this email because you subscribed to this discussion on CodePlex. You can unsubscribe on CodePlex.com.

Please note: Images and attachments will be removed from emails. Any posts to this discussion will also be available online at CodePlex.com


Oct 25, 2010 at 4:10 PM

If you need the ability to generate the image's at run time I have a solution... 

Since the Binary Format of a TinyCLR Bitmap is different then DIB's you need to convert the bytes to something a browser can render...

The first step is to get the image data in a format which means something.

 

Use this class to achive that:

 (Can't remember which MSDN Blog I got this from)

namespace Graphics
{
    public class BinaryImageData
    {
        private int _width = 0;
        private int _height = 0;
        private bool _init = false;
        private byte[] _buffer;
        private int _rowLength;

        public BinaryImageData(int width, int height)
        {
            this.Width = width;
            this.Height = height;
        }

        public int Width
        {
            get
            {
                return _width;
            }
            set
            {
                _width = value;
            }
        }

        public int Height
        {
            get
            {
                return _height;
            }
            set
            {
                _height = value;
            }
        }

        public byte[] ImageData
        {
            get { return _buffer; }            
        }

        public void SetPixel(int col, int row, Microsoft.SPOT.Presentation.Media.Color color)
        {
            SetPixel(col, row, Microsoft.SPOT.Presentation.Media.ColorUtility.GetRValue(color),
                                Microsoft.SPOT.Presentation.Media.ColorUtility.GetGValue(color),
                                Microsoft.SPOT.Presentation.Media.ColorUtility.GetBValue(color),
                                255);
        }

        public void SetPixel(int col, int row, byte red, byte green, byte blue, byte alpha)
        {
            if (!_init)
            {
                _rowLength = _width * 4 + 1;
                _buffer = new byte[_rowLength * _height];

                // Initialize
                for (int idx = 0; idx < _height; idx++)
                {
                    _buffer[idx * _rowLength] = 0;      // Filter bit
                }

                _init = true;
            }

            // Set the pixel
            int start = _rowLength * row + col * 4 + 1;
            _buffer[start] = red;
            _buffer[start + 1] = green;
            _buffer[start + 2] = blue;
            _buffer[start + 3] = alpha;
        }

        public Microsoft.SPOT.Presentation.Media.Color GetPixel(int col, int row)
        {
            int _base = _rowLength * row + col + 1;
            return (Microsoft.SPOT.Presentation.Media.Color)(_buffer[_base] | _buffer[_base + 1] | _buffer[_base + 2] | _buffer[_base + 3]);            
        }        

        public System.IO.MemoryStream GetPNGStream()
        {
            return Graphics.Encoders.PngEncoder.Encode(this);            
        }

        public System.IO.MemoryStream GetBMP24Stream()
        {
            return Graphics.Encoders.Bitmap24Encoder.Encode(this);
        }

    }
}

 Next you need to get these meaningful bytes into a binary format which can be rendered by a browser, e.g. Encode the image.

 

Use one of these classes in combination with the BinaryImageData class above..

 

using System;
using System.IO;
using Microsoft.SPOT;
using Microsoft.SPOT.Presentation.Media;

namespace Graphics.Encoders
{
    public class PngEncoder
    {
        private const int _ADLER32_BASE = 65521;
        private const int _MAXBLOCK = 0xFFFF;
        private static byte[] _HEADER = { 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A };
        private static byte[] _IHDR = { (byte)'I', (byte)'H', (byte)'D', (byte)'R' };
        private static byte[] _GAMA = { (byte)'g', (byte)'A', (byte)'M', (byte)'A' };
        private static byte[] _IDAT = { (byte)'I', (byte)'D', (byte)'A', (byte)'T' };
        private static byte[] _IEND = { (byte)'I', (byte)'E', (byte)'N', (byte)'D' };
        private static byte[] _4BYTEDATA = { 0, 0, 0, 0 };
        private static byte[] _ARGB = { 0, 0, 0, 0, 0, 0, 0, 0, 8, 6, 0, 0, 0 };


        public static MemoryStream Encode(BinaryImageData data)
        {
            MemoryStream ms = new MemoryStream();
            byte[] size;

            // Write PNG header
            ms.Write(_HEADER, 0, _HEADER.Length);

            // Write IHDR
            //  Width:              4 bytes
            //  Height:             4 bytes
            //  Bit depth:          1 byte
            //  Color type:         1 byte
            //  Compression method: 1 byte
            //  Filter method:      1 byte
            //  Interlace method:   1 byte

            size = BitConverter.GetBytes(data.Width);
            _ARGB[0] = size[3]; _ARGB[1] = size[2]; _ARGB[2] = size[1]; _ARGB[3] = size[0];

            size = BitConverter.GetBytes(data.Height);
            _ARGB[4] = size[3]; _ARGB[5] = size[2]; _ARGB[6] = size[1]; _ARGB[7] = size[0];

            // Write IHDR chunk
            WriteChunk(ms, _IHDR, _ARGB);

            // Set gamma = 1
            size = BitConverter.GetBytes(100000);
            _4BYTEDATA[0] = size[3]; _4BYTEDATA[1] = size[2]; _4BYTEDATA[2] = size[1]; _4BYTEDATA[3] = size[0];

            // Write gAMA chunk
            WriteChunk(ms, _GAMA, _4BYTEDATA);

            // Write IDAT chunk
            uint widthLength = (uint)(data.Width * 4) + 1;
            uint dcSize = widthLength * (uint)data.Height;

            // First part of ZLIB header is 78 1101 1010 (DA) 0000 00001 (01)
            // ZLIB info
            //
            // CMF Byte: 78
            //  CINFO = 7 (32K window size)
            //  CM = 8 = (deflate compression)
            // FLG Byte: DA
            //  FLEVEL = 3 (bits 6 and 7 - ignored but signifies max compression)
            //  FDICT = 0 (bit 5, 0 - no preset dictionary)
            //  FCHCK = 26 (bits 0-4 - ensure CMF*256+FLG / 31 has no remainder)
            // Compressed data
            //  FLAGS: 0 or 1
            //    00000 00 (no compression) X (X=1 for last block, 0=not the last block)
            //    LEN = length in bytes (equal to ((width*4)+1)*height
            //    NLEN = one's compliment of LEN
            //    Example: 1111 1011 1111 1111 (FB), 0000 0100 0000 0000 (40)
            //    Data for each line: 0 [RGBA] [RGBA] [RGBA] ...
            //    ADLER32

            uint adler = ComputeAdler32(data.ImageData);
            MemoryStream comp = new MemoryStream();

            // Calculate number of 64K blocks
            uint rowsPerBlock = _MAXBLOCK / widthLength;
            uint blockSize = rowsPerBlock * widthLength;
            uint blockCount;
            ushort length;
            uint remainder = dcSize;

            if ((dcSize % blockSize) == 0)
            {
                blockCount = dcSize / blockSize;
            }
            else
            {
                blockCount = (dcSize / blockSize) + 1;
            }

            // Write headers
            comp.WriteByte(0x78);
            comp.WriteByte(0xDA);

            for (uint blocks = 0; blocks < blockCount; blocks++)
            {
                // Write LEN
                length = (ushort)((remainder < blockSize) ? remainder : blockSize);

                if (length == remainder)
                {
                    comp.WriteByte(0x01);
                }
                else
                {
                    comp.WriteByte(0x00);
                }

                comp.Write(BitConverter.GetBytes(length), 0, 2);

                // Write one's compliment of LEN
                comp.Write(BitConverter.GetBytes((ushort)~length), 0, 2);

                // Write blocks
                comp.Write(data.ImageData, (int)(blocks * blockSize), data.ImageData.Length);

                // Next block
                remainder -= blockSize;

            }

            WriteReversedBuffer(comp, BitConverter.GetBytes((int)adler));
            comp.Seek(0, SeekOrigin.Begin);

            byte[] dat = new byte[(int)comp.Length];
            comp.Read(dat, 0, (int)comp.Length);

            WriteChunk(ms, _IDAT, dat);

            // Write IEND chunk
            WriteChunk(ms, _IEND, new byte[0]);

            // Reset stream
            ms.Seek(0, SeekOrigin.Begin);

            return ms;


            // See http://www.libpng.org/pub/png//spec/1.2/PNG-Chunks.html
            // See http://www.libpng.org/pub/png/book/chapter08.html#png.ch08.div.4
            // See http://www.gzip.org/zlib/rfc-zlib.html (ZLIB format)
            // See ftp://ftp.uu.net/pub/archiving/zip/doc/rfc1951.txt (ZLIB compression format)
        }

        private static void WriteReversedBuffer(Stream stream, byte[] data)
        {
            int size = data.Length;
            byte[] reorder = new byte[size];

            for (int idx = 0; idx < size; idx++)
            {
                reorder[idx] = data[size - idx - 1];
            }
            stream.Write(reorder, 0, size);
        }

        private static void WriteChunk(Stream stream, byte[] type, byte[] data)
        {
            int idx;
            int size = type.Length;
            byte[] buffer = new byte[type.Length + data.Length];

            // Initialize buffer
            for (idx = 0; idx < type.Length; idx++)
            {
                buffer[idx] = type[idx];
            }

            for (idx = 0; idx < data.Length; idx++)
            {
                buffer[idx + size] = data[idx];
            }

            // Write length
            WriteReversedBuffer(stream, BitConverter.GetBytes(data.Length));

            // Write type and data
            stream.Write(buffer, 0, buffer.Length);   // Should always be 4 bytes

            // Compute and write the CRC
            WriteReversedBuffer(stream, BitConverter.GetBytes((int)GetCRC(buffer)));

        }

        private static uint[] _crcTable = new uint[256];
        private static bool _crcTableComputed = false;

        private static void MakeCRCTable()
        {
            uint c;

            for (int n = 0; n < 256; n++)
            {
                c = (uint)n;
                for (int k = 0; k < 8; k++)
                {
                    if ((c & (0x00000001)) > 0)
                        c = 0xEDB88320 ^ (c >> 1);
                    else
                        c = c >> 1;
                }
                _crcTable[n] = c;
            }

            _crcTableComputed = true;
        }

        private static uint UpdateCRC(uint crc, byte[] buf, int len)
        {
            uint c = crc;

            if (!_crcTableComputed)
            {
                MakeCRCTable();
            }

            for (int n = 0; n < len; n++)
            {
                c = _crcTable[(c ^ buf[n]) & 0xFF] ^ (c >> 8);
            }

            return c;
        }

        /* Return the CRC of the bytes buf[0..len-1]. */
        private static uint GetCRC(byte[] buf)
        {
            return UpdateCRC(0xFFFFFFFF, buf, buf.Length) ^ 0xFFFFFFFF;            
        }

        private static uint ComputeAdler32(byte[] buf)
        {
            uint s1 = 1;
            uint s2 = 0;
            int length = buf.Length;

            for (int idx = 0; idx < length; idx++)
            {
                s1 = (s1 + (uint)buf[idx]) % _ADLER32_BASE;
                s2 = (s2 + s1) % _ADLER32_BASE;
            }

            return (s2 << 16) + s1;
        }
    }

}

using MemoryStream = System.IO.MemoryStream;
using System;
namespace Graphics.Encoders
{
    public sealed class Bitmap24Encoder
    {
        const short BIT_DEPTH = 24;

        public static MemoryStream Encode(BinaryImageData bmp)
        {
            ByteWriter bw = new ByteWriter(ByteOrder.LittleEndian);
            writeHeader(ref bw, ref bmp);
            writeData(ref bw, ref bmp);
            byte[] data = bw.GetBytes();

            byte[] size = BitConverter.GetBytes((uint)data.Length, ByteOrder.LittleEndian);
            
            size.CopyTo(data, 2);
            Array.Clear(size, 0, size.Length);
            size = null;
            
            bw.Dispose();
            bw = null;

            return new MemoryStream(data);
        }

        private static void writeData(ref ByteWriter bytes, ref BinaryImageData bmp)
        {
            int padLength = bmp.Width % 4;
            byte[] padding = null;

            if (padLength > 0)
            {
                padding = new byte[padLength];
                for (int i = 0; i < padLength; i++) padding[i] = 0;
            }

            for (int y = bmp.Height - 1; y >= 0; y--)
            {
                for (int x = 0; x < bmp.Width; x++) writePixel(ref bytes, bmp.GetPixel(x, y));
                if (padLength > 0) bytes.BaseStream.Write(padding, 0, padding.Length);
            }

        }

        private static void writePixel(ref ByteWriter bytes, Microsoft.SPOT.Presentation.Media.Color c)
        {
            int pixel = (int)c;
            bytes.Write((byte)(0x0000ff & pixel));
            bytes.Write((byte)(0x00ff00 & pixel));
            bytes.Write((byte)(0xff0000 & pixel));
            //bytes.Write(Microsoft.SPOT.Presentation.Media.ColorUtility.GetBValue(pixel));
            //bytes.Write(Microsoft.SPOT.Presentation.Media.ColorUtility.GetGValue(pixel));
            //bytes.Write(Microsoft.SPOT.Presentation.Media.ColorUtility.GetRValue(pixel));
        }

        private static void writeHeader(ref ByteWriter bytes, ref BinaryImageData bmp)
        {
            // Bitmap header			
            bytes.Write((byte)0x4d); // BMPs start with 'BM'
            bytes.Write((byte)0x42);
            bytes.Write((uint)0); // filesize in bytes, set after the data is populated.
            bytes.Write((short)0); // reserved.
            bytes.Write((short)0); // reserved.
            bytes.Write((uint)54); //data offset.
            // Bitmap Info header
            bytes.Write((uint)40); // Size of info header. V3
            bytes.Write(bmp.Width); // signed int width of image.
            bytes.Write(bmp.Height); // signed int height of image.
            bytes.Write((short)1); // # of color planes.
            bytes.Write(BIT_DEPTH); // # bits per pixel.
            bytes.Write((uint)0); // No compresion.
            bytes.Write((uint)0); // Size of the raw image data.	0 is valid for no compression.	
            bytes.Write(0); // x resolution 
            bytes.Write(0); // y resolution
            bytes.Write((uint)0); // # of colors in color pallete. 0 indicates default 2^n.
            bytes.Write((uint)0); // # of important colors. what?
        }
    }
}

 Finally you need to serve the image to a client so make a HttpHandler and stream the image...

 private static void StreamPNG(HttpContext context)
        {            
            context.Response.HttpStatus = HttpStatusCode.OK;
            context.Response.ContentType = "image/png";
            using (MemoryStream s = SomeBinaryImageData.GetPNGStream() as MemoryStream)
            {
                s.WriteTo(context.Response.OutputStream);
            }
            context.Response.OutputStream.Flush();
        }

        private static void StreamBMP(HttpContext context)
        {            
            context.Response.HttpStatus = HttpStatusCode.OK;
            context.Response.ContentType = "image/bmp";
            using (MemoryStream ms = SomeBinaryImageData.GetBMP24Stream())
            {
                ms.WriteTo(context.Response.OutputStream);

            }
            context.Response.OutputStream.Flush();
        }