先说说silverlight 的独立存储吧,和windows phone的独立存储概念一样,http://soft.zdnet.com.cn/software_zone/2009/0204/1332042.shtml 这篇文章写得非常好。
保存路径:C:\Users\v-jialia\AppData\LocalLow\Microsoft\Silverlight\is\j3lfxcgg.wes\3c5zew4w.pwg\1\s\22q1ww4utygitwusgxbr2pltyjvnx5scqrz3yvlhsvltkplyz2aaadba\f 独立存储所在的文件夹的位置是不是很隐蔽。。。
silverlight 保存成图片也和windows phone 非常类似,但是不是一个样。
private void button1_Click(object sender, RoutedEventArgs e) { ScaleTransform transform = new ScaleTransform(); transform.ScaleX = 1; transform.ScaleY = 1; System.Windows.Media.Imaging.WriteableBitmap we = new System.Windows.Media.Imaging.WriteableBitmap( this, transform); Save(we); } private void Save(System.Windows.Media.Imaging.WriteableBitmap we) { var dlg = new SaveFileDialog(); dlg.DefaultExt = ".png"; dlg.Filter = "PNG File|*.png"; EditableImage imageData = new EditableImage(we.PixelWidth, we.PixelHeight); try { for (int y = 0; y < we.PixelHeight; ++y) { for (int x = 0; x < we.PixelWidth; ++x) { int pixel = we.Pixels[we.PixelWidth * y + x]; imageData.SetPixel(x, y, (byte)((pixel >> 16) & 0xFF), (byte)((pixel >> 8) & 0xFF), (byte)(pixel & 0xFF), (byte)((pixel >> 24) & 0xFF) ); } } } catch (Exception e) { } /* if (dlg.ShowDialog() == true) { Stream pngStream = imageData.GetStream(); byte[] binaryData = new byte[pngStream.Length]; pngStream.Read(binaryData,0,(int)pngStream.Length); Stream stream = dlg.OpenFile(); stream.Write(binaryData,0,binaryData.Length); stream.Close(); } */ using (IsolatedStorageFile store = IsolatedStorageFile.GetUserStoreForApplication()) { long newQuetaSize = 5242880*10; long curAvail = store.AvailableFreeSpace; if (curAvail < newQuetaSize) { store.IncreaseQuotaTo(newQuetaSize*2); } string path = "graph reports.png"; IsolatedStorageFileStream fileStream = store.CreateFile(path); Stream pngStream = imageData.GetStream(); byte[] binaryData = new byte[pngStream.Length]; pngStream.Read(binaryData, 0, (int)pngStream.Length); fileStream.Write(binaryData, 0, binaryData.Length); fileStream.Close(); } }
这里要注意的一点是,有两个辅助类需要自己定义:
/// <summary> /// PNG格式操作类 /// </summary> 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 }; /// <summary> /// 编码 /// </summary> /// <param name="data"></param> /// <param name="width"></param> /// <param name="height"></param> /// <returns></returns> public static Stream Encode(byte[] data, int width, int height) { 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(width); _ARGB[0] = size[3]; _ARGB[1] = size[2]; _ARGB[2] = size[1]; _ARGB[3] = size[0]; size = BitConverter.GetBytes(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(1 * 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)(width * 4) + 1; uint dcSize = widthLength * (uint)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); MemoryStream comp = new MemoryStream(); // 64K的块数计算 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; } // 头部 comp.WriteByte(0x78); comp.WriteByte(0xDA); for (uint blocks = 0; blocks < blockCount; blocks++) { // 长度 length = (ushort)((remainder < blockSize) ? remainder : blockSize); if (length == remainder) { comp.WriteByte(0x01); } else { comp.WriteByte(0x00); } comp.Write(BitConverter.GetBytes(length), 0, 2); comp.Write(BitConverter.GetBytes((ushort)~length), 0, 2); // Write 块 comp.Write(data, (int)(blocks * blockSize), length); //下一块 remainder -= blockSize; } WriteReversedBuffer(comp, BitConverter.GetBytes(adler)); comp.Seek(0, SeekOrigin.Begin); byte[] dat = new byte[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; } 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]; // 初始化缓冲 for (idx = 0; idx < type.Length; idx++) { buffer[idx] = type[idx]; } for (idx = 0; idx < data.Length; idx++) { buffer[idx + size] = data[idx]; } WriteReversedBuffer(stream, BitConverter.GetBytes(data.Length)); // Write 类型和数据 stream.Write(buffer, 0, buffer.Length); // Should always be 4 bytes // 计算和书写的CRC WriteReversedBuffer(stream, BitConverter.GetBytes(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; } //返回的字节的CRC缓冲区 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; } } /// <summary> /// 编辑图片 /// </summary> public class EditableImage { private int _width = 0; private int _height = 0; private bool _init = false; private byte[] _buffer; private int _rowLength; /// <summary> /// 当图片错误时引发 /// </summary> public event EventHandler<EditableImageErrorEventArgs> ImageError; /// <summary> /// 实例化 /// </summary> /// <param name="width"></param> /// <param name="height"></param> public EditableImage(int width, int height) { this.Width = width; this.Height = height; } public int Width { get { return _width; } set { if (_init) { OnImageError("错误: 图片初始化后不可以改变宽度"); } else if ((value <= 0) || (value > 2047)) { OnImageError("错误: 宽度必须在 0 到 2047"); } else { _width = value; } } } public int Height { get { return _height; } set { if (_init) { OnImageError("错误: 图片初始化后不可以改变高度"); } else if ((value <= 0) || (value > 2047)) { OnImageError("错误: 高度必须在 0 到 2047"); } else { _height = value; } } } public void SetPixel(int col, int row, Color color) { SetPixel(col, row, color.R, color.G, color.B, color.A); } 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; } if ((col > _width) || (col < 0)) { OnImageError("Error: Column must be greater than 0 and less than the Width"); } else if ((row > _height) || (row < 0)) { OnImageError("Error: Row must be greater than 0 and less than the Height"); } // 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 Color GetPixel(int col, int row) { if ((col > _width) || (col < 0)) { OnImageError("Error: Column must be greater than 0 and less than the Width"); } else if ((row > _height) || (row < 0)) { OnImageError("Error: Row must be greater than 0 and less than the Height"); } Color color = new Color(); int _base = _rowLength * row + col + 1; color.R = _buffer[_base]; color.G = _buffer[_base + 1]; color.B = _buffer[_base + 2]; color.A = _buffer[_base + 3]; return color; } public Stream GetStream() { Stream stream; if (!_init) { OnImageError("Error: Image has not been initialized"); stream = null; } else { stream = PngEncoder.Encode(_buffer, _width, _height); } return stream; } private void OnImageError(string msg) { if (null != ImageError) { EditableImageErrorEventArgs args = new EditableImageErrorEventArgs(); args.ErrorMessage = msg; ImageError(this, args); } } public class EditableImageErrorEventArgs : EventArgs { private string _errorMessage = string.Empty; public string ErrorMessage { get { return _errorMessage; } set { _errorMessage = value; } } } }
有一个很大的问题暂时没法解决: 当网页超过屏幕长度时,截出来的图也是最多只有一个屏幕大小,而不会把滚动条内的内容都显示出来。