Silverlightエクスポートピクチャファイル
65501 ワード
Silverlightアプリケーションを新規作成し、次の2つのコントロールを追加します.
imageコントロール:image 1;
Buttonコントロール:Click="Button 1_Click";
code-Behindコードは以下の通りです.
次の3つのクラスを追加します.
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 //* -------------------------------------------------------------------------------------------------