Silverlightエクスポートピクチャファイル

65501 ワード

Silverlightアプリケーションを新規作成し、次の2つのコントロールを追加します.
imageコントロール:image 1;
Buttonコントロール:Click="Button 1_Click";
code-Behindコードは以下の通りです.
1         private void Button1_Click(object sender, RoutedEventArgs e)
2         {
3             ElementToPNG eTP = new ElementToPNG();
4             eTP.ShowSaveDialog(image1);
5         }

次の3つのクラスを追加します.
  1 //* -------------------------------------------------------------------------------------------------
  2 //*  
  3 //* -------------------------------------------------------------------------------------------------
  4 # region Class ElementToPNG
  5     public class ElementToPNG
  6     {
  7         public void ShowSaveDialog(UIElement elementToExport)
  8         {
  9             SaveFileDialog sfd = new SaveFileDialog()
 10             {
 11                 DefaultExt = "png",
 12                 Filter = "Png files (*.png)|*.png|All files (*.*)|*.*",
 13                 FilterIndex = 1
 14             };
 15 
 16             if (sfd.ShowDialog() == true)
 17             {
 18                 SaveAsPNG(sfd, elementToExport);
 19             }
 20         }
 21         private void SaveAsPNG(SaveFileDialog sfd, UIElement elementToExport)
 22         {
 23             WriteableBitmap bitmap = new WriteableBitmap(elementToExport, new TranslateTransform());
 24             EditableImage imageData = new EditableImage(bitmap.PixelWidth, bitmap.PixelHeight);
 25             try
 26             {
 27                 for (int y = 0; y < bitmap.PixelHeight; ++y)
 28                 {
 29                     for (int x = 0; x < bitmap.PixelWidth; ++x)
 30                     {
 31                         int pixel = bitmap.Pixels[bitmap.PixelWidth * y + x];
 32                         imageData.SetPixel(x, y,
 33                         (byte)((pixel >> 16) & 0xFF),
 34                         (byte)((pixel >> 8) & 0xFF),
 35                         (byte)(pixel & 0xFF), (byte)((pixel >> 24) & 0xFF)
 36                         );
 37                     }
 38                 }
 39             }
 40             catch (System.Security.SecurityException)
 41             {
 42                 throw new Exception("Cannot print images from other domains");
 43             }
 44             Stream pngStream = imageData.GetStream();
 45             byte[] binaryData = new Byte[pngStream.Length];
 46             long bytesRead = pngStream.Read(binaryData, 0, (int)pngStream.Length);
 47             Stream stream = sfd.OpenFile();
 48             stream.Write(binaryData, 0, binaryData.Length);
 49             stream.Close();
 50         }
 51     }
 52 # endregion
 53 
 54 # region Class EditableImage
 55     public class EditableImage
 56     {
 57         private int _width = 0;
 58         private int _height = 0;
 59         private bool _init = false;
 60         private byte[] _buffer;
 61         private int _rowLength;
 62 
 63         public event EventHandler<EditableImageErrorEventArgs> ImageError;
 64 
 65         public EditableImage(int width, int height)
 66         {
 67             this.Width = width;
 68             this.Height = height;
 69         }
 70 
 71         public int Width
 72         {
 73             get
 74             {
 75                 return _width;
 76             }
 77             set
 78             {
 79                 if (_init)
 80                 {
 81                     OnImageError("Error: Cannot change Width after the EditableImage has been initialized");
 82                 }
 83                 else if ((value <= 0) || (value > 2047))
 84                 {
 85                     OnImageError("Error: Width must be between 0 and 2047");
 86                 }
 87                 else
 88                 {
 89                     _width = value;
 90                 }
 91             }
 92         }
 93 
 94         public int Height
 95         {
 96             get
 97             {
 98                 return _height;
 99             }
100             set
101             {
102                 if (_init)
103                 {
104                     OnImageError("Error: Cannot change Height after the EditableImage has been initialized");
105                 }
106                 else if ((value <= 0) || (value > 2047))
107                 {
108                     OnImageError("Error: Height must be between 0 and 2047");
109                 }
110                 else
111                 {
112                     _height = value;
113                 }
114             }
115         }
116 
117         public void SetPixel(int col, int row, Color color)
118         {
119             SetPixel(col, row, color.R, color.G, color.B, color.A);
120         }
121 
122         public void SetPixel(int col, int row, byte red, byte green, byte blue, byte alpha)
123         {
124             if (!_init)
125             {
126                 _rowLength = _width * 4 + 1;
127                 _buffer = new byte[_rowLength * _height];
128 
129                 // Initialize
130                 for (int idx = 0; idx < _height; idx++)
131                 {
132                     _buffer[idx * _rowLength] = 0;      // Filter bit
133                 }
134 
135                 _init = true;
136             }
137 
138             if ((col > _width) || (col < 0))
139             {
140                 OnImageError("Error: Column must be greater than 0 and less than the Width");
141             }
142             else if ((row > _height) || (row < 0))
143             {
144                 OnImageError("Error: Row must be greater than 0 and less than the Height");
145             }
146 
147             // Set the pixel
148             int start = _rowLength * row + col * 4 + 1;
149             _buffer[start] = red;
150             _buffer[start + 1] = green;
151             _buffer[start + 2] = blue;
152             _buffer[start + 3] = alpha;
153         }
154 
155         public Color GetPixel(int col, int row)
156         {
157             if ((col > _width) || (col < 0))
158             {
159                 OnImageError("Error: Column must be greater than 0 and less than the Width");
160             }
161             else if ((row > _height) || (row < 0))
162             {
163                 OnImageError("Error: Row must be greater than 0 and less than the Height");
164             }
165 
166             Color color = new Color();
167             int _base = _rowLength * row + col + 1;
168 
169             color.R = _buffer[_base];
170             color.G = _buffer[_base + 1];
171             color.B = _buffer[_base + 2];
172             color.A = _buffer[_base + 3];
173 
174             return color;
175         }
176 
177         public Stream GetStream()
178         {
179             Stream stream;
180 
181             if (!_init)
182             {
183                 OnImageError("Error: Image has not been initialized");
184                 stream = null;
185             }
186             else
187             {
188                 stream = PngEncoder.Encode(_buffer, _width, _height);
189             }
190 
191             return stream;
192         }
193 
194         private void OnImageError(string msg)
195         {
196             if (null != ImageError)
197             {
198                 EditableImageErrorEventArgs args = new EditableImageErrorEventArgs();
199                 args.ErrorMessage = msg;
200                 ImageError(this, args);
201             }
202         }
203 
204         public class EditableImageErrorEventArgs : EventArgs
205         {
206             private string _errorMessage = string.Empty;
207 
208             public string ErrorMessage
209             {
210                 get { return _errorMessage; }
211                 set { _errorMessage = value; }
212             }
213         }
214 
215     }
216 # endregion
217 
218 # region Class PngEncoder
219     public class PngEncoder
220     {
221         private const int _ADLER32_BASE = 65521;
222         private const int _MAXBLOCK = 0xFFFF;
223         private static byte[] _HEADER = { 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A };
224         private static byte[] _IHDR = { (byte)'I', (byte)'H', (byte)'D', (byte)'R' };
225         private static byte[] _GAMA = { (byte)'g', (byte)'A', (byte)'M', (byte)'A' };
226         private static byte[] _IDAT = { (byte)'I', (byte)'D', (byte)'A', (byte)'T' };
227         private static byte[] _IEND = { (byte)'I', (byte)'E', (byte)'N', (byte)'D' };
228         private static byte[] _4BYTEDATA = { 0, 0, 0, 0 };
229         private static byte[] _ARGB = { 0, 0, 0, 0, 0, 0, 0, 0, 8, 6, 0, 0, 0 };
230 
231 
232         public static Stream Encode(byte[] data, int width, int height)
233         {
234             MemoryStream ms = new MemoryStream();
235             byte[] size;
236 
237             // Write PNG header
238             ms.Write(_HEADER, 0, _HEADER.Length);
239 
240             size = BitConverter.GetBytes(width);
241             _ARGB[0] = size[3]; _ARGB[1] = size[2]; _ARGB[2] = size[1]; _ARGB[3] = size[0];
242 
243             size = BitConverter.GetBytes(height);
244             _ARGB[4] = size[3]; _ARGB[5] = size[2]; _ARGB[6] = size[1]; _ARGB[7] = size[0];
245 
246             // Write IHDR chunk
247             WriteChunk(ms, _IHDR, _ARGB);
248 
249             // Set gamma = 1
250             size = BitConverter.GetBytes(1 * 100000);
251             _4BYTEDATA[0] = size[3]; _4BYTEDATA[1] = size[2]; _4BYTEDATA[2] = size[1]; _4BYTEDATA[3] = size[0];
252 
253             // Write gAMA chunk
254             WriteChunk(ms, _GAMA, _4BYTEDATA);
255 
256             // Write IDAT chunk
257             uint widthLength = (uint)(width * 4) + 1;
258             uint dcSize = widthLength * (uint)height;
259 
260             uint adler = ComputeAdler32(data);
261             MemoryStream comp = new MemoryStream();
262 
263             // Calculate number of 64K blocks
264             uint rowsPerBlock = _MAXBLOCK / widthLength;
265             uint blockSize = rowsPerBlock * widthLength;
266             uint blockCount;
267             ushort length;
268             uint remainder = dcSize;
269 
270             if ((dcSize % blockSize) == 0)
271             {
272                 blockCount = dcSize / blockSize;
273             }
274             else
275             {
276                 blockCount = (dcSize / blockSize) + 1;
277             }
278 
279             // Write headers
280             comp.WriteByte(0x78);
281             comp.WriteByte(0xDA);
282 
283             for (uint blocks = 0; blocks < blockCount; blocks++)
284             {
285                 // Write LEN
286                 length = (ushort)((remainder < blockSize) ? remainder : blockSize);
287 
288                 if (length == remainder)
289                 {
290                     comp.WriteByte(0x01);
291                 }
292                 else
293                 {
294                     comp.WriteByte(0x00);
295                 }
296 
297                 comp.Write(BitConverter.GetBytes(length), 0, 2);
298 
299                 // Write one's compliment of LEN
300                 comp.Write(BitConverter.GetBytes((ushort)~length), 0, 2);
301 
302                 // Write blocks
303                 comp.Write(data, (int)(blocks * blockSize), length);
304 
305                 // Next block
306                 remainder -= blockSize;
307             }
308 
309             WriteReversedBuffer(comp, BitConverter.GetBytes(adler));
310             comp.Seek(0, SeekOrigin.Begin);
311 
312             byte[] dat = new byte[comp.Length];
313             comp.Read(dat, 0, (int)comp.Length);
314 
315             WriteChunk(ms, _IDAT, dat);
316 
317             // Write IEND chunk
318             WriteChunk(ms, _IEND, new byte[0]);
319 
320             // Reset stream
321             ms.Seek(0, SeekOrigin.Begin);
322 
323             return ms;
324         }
325 
326         private static void WriteReversedBuffer(Stream stream, byte[] data)
327         {
328             int size = data.Length;
329             byte[] reorder = new byte[size];
330 
331             for (int idx = 0; idx < size; idx++)
332             {
333                 reorder[idx] = data[size - idx - 1];
334             }
335             stream.Write(reorder, 0, size);
336         }
337 
338         private static void WriteChunk(Stream stream, byte[] type, byte[] data)
339         {
340             int idx;
341             int size = type.Length;
342             byte[] buffer = new byte[type.Length + data.Length];
343 
344             // Initialize buffer
345             for (idx = 0; idx < type.Length; idx++)
346             {
347                 buffer[idx] = type[idx];
348             }
349 
350             for (idx = 0; idx < data.Length; idx++)
351             {
352                 buffer[idx + size] = data[idx];
353             }
354 
355             // Write length
356             WriteReversedBuffer(stream, BitConverter.GetBytes(data.Length));
357 
358             // Write type and data
359             stream.Write(buffer, 0, buffer.Length);   // Should always be 4 bytes
360 
361             // Compute and write the CRC
362             WriteReversedBuffer(stream, BitConverter.GetBytes(GetCRC(buffer)));
363         }
364         private static uint[] _crcTable = new uint[256];
365         private static bool _crcTableComputed = false;
366         private static void MakeCRCTable()
367         {
368             uint c;
369             for (int n = 0; n < 256; n++)
370             {
371                 c = (uint)n;
372                 for (int k = 0; k < 8; k++)
373                 {
374                     if ((c & (0x00000001)) > 0)
375                         c = 0xEDB88320 ^ (c >> 1);
376                     else
377                         c = c >> 1;
378                 }
379                 _crcTable[n] = c;
380             }
381 
382             _crcTableComputed = true;
383         }
384         private static uint UpdateCRC(uint crc, byte[] buf, int len)
385         {
386             uint c = crc;
387 
388             if (!_crcTableComputed)
389             {
390                 MakeCRCTable();
391             }
392 
393             for (int n = 0; n < len; n++)
394             {
395                 c = _crcTable[(c ^ buf[n]) & 0xFF] ^ (c >> 8);
396             }
397 
398             return c;
399         }
400         private static uint GetCRC(byte[] buf)
401         {
402             return UpdateCRC(0xFFFFFFFF, buf, buf.Length) ^ 0xFFFFFFFF;
403         }
404         private static uint ComputeAdler32(byte[] buf)
405         {
406             uint s1 = 1;
407             uint s2 = 0;
408             int length = buf.Length;
409 
410             for (int idx = 0; idx < length; idx++)
411             {
412                 s1 = (s1 + (uint)buf[idx]) % _ADLER32_BASE;
413                 s2 = (s2 + s1) % _ADLER32_BASE;
414             }
415             return (s2 << 16) + s1;
416         }
417     }
418 # endregion
419 //* -------------------------------------------------------------------------------------------------
420 //* -------------------------------------------------------------------------------------------------