Silverlight上传图片,保存二进制数据到数据库(支持bmp方法)

 

  前段项目中遇到了用户图片上传问题,Silverlight仅支持jpg和png格式,无法满足用户对BMP和GIF格式上传的支持。再者就是需要在在客户端将图片转为byte[]格式,之后传回服务器并保存到SQL Server 2005中image类型的字段,查看了网上很多资料和风云的《银光志》,给出的方法不大适合当前项目的要求,所以综合大家的方法,支持了BMP图片格式,和客户端转化数据流的方法(没有支持GIF格式)。

  1、前台和数据库

    

  2、项目中用到了Silverlight功能的WCF服务,为了简化服务端的操作,直接将图片转化为byte[]类型,在O/R设计器中拖放过来的表,image对应生成的类型为Binary (System.Data.Linq.Binary)类型,在转化时遇到了byte[]转Binary的难题,后来在一个老外的博客里看到,在O/R设计器里直接把Binary类型修改成byte[]类型,试了试果然有效。

  3、解决WCF传输限流问题,WCF限流16K,如果从客户端向服务器端发送数据,需要分段传输,也可以修改webconfig文件,自定义传输数据量的大小,这里直接限制到了最大值。

  

  4、准备工作做好后,开始做图片上传和转化的工作。JPG上传和格式转化代码如下:

代码
1 //如果是jpg文件
2   byte[] buffer = new Byte[readSize];
3 int byteRead = inputStream.Read(buffer, 0, readSize);
4 byte[] setData = new Byte[byteRead];
5 setData = buffer;
6 //为公共变量mapByte赋值
7 this.mapByte = setData;
8
9 if (mapInfo != null)
10 {
11 BitmapImage image = new BitmapImage();
12 image.SetSource(inputStream);
13 this.imgPrisonerPhoto.Source = image;
14 this.imgPrisonerPhoto.Visibility = Visibility.Visible;
15 inputStream.Close();
16 }
17 else
18 {
19 MessageBox.Show(" 请选择要上传的地图文件! ");
20 }

 

  BMP格式图片上传和格式转化代码如下:

  

代码
1 if (mapFullName[mapFullName.Length - 1].Contains("bmp"))
2 {
3 //如果是bmp文件
4 //bmp图片解码
5 DoBackgroundWork(DoLoad, inputStream);
6 }

 

 

代码
1 #region BMP图片转换操作
2
3 private void DoLoad(object sender, DoWorkEventArgs e)
4 {
5 Stream file = e.Argument as Stream;
6
7 //bmp图片解码
8 _texture = BMPDecoder.Decode(file);
9 e.Result = _texture;
10 file.Close();
11 }
12
13 private void DoBackgroundWork(DoWorkEventHandler bgWorker, object arg)
14 {
15 BackgroundWorker bw = new BackgroundWorker();
16
17 bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(BW_RunWorkerCompleted);
18 bw.DoWork += new DoWorkEventHandler(bgWorker);
19
20 bw.RunWorkerAsync(arg);
21 }
22
23 void BW_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
24 {
25 //显示图片
26 WriteableBitmap wb = (e.Result as Texture).GetWriteableBitmap();
27 wb.Invalidate();
28
29 imgPrisonerPhoto.Source = wb;
30 //将WriteableBitmap保存为byte[]数组
31 SaveToByteArray(wb, tempStream);
32 }
33
34 //将WriteableBitmap保存为byte[]数组
35 void SaveToByteArray(WriteableBitmap bitmap, Stream fs)
36 {
37 int width = bitmap.PixelWidth;
38 int height = bitmap.PixelHeight;
39 int bands = 3;
40 byte[][,] raster = new byte[bands][,];
41
42 for (int i = 0; i < bands; i++)
43 {
44 raster[i] = new byte[width, height];
45 }
46
47 for (int row = 0; row < height; row++)
48 {
49 for (int column = 0; column < width; column++)
50 {
51 int pixel = bitmap.Pixels[width * row + column];
52 raster[0][column, row] = (byte)(pixel >> 16);
53 raster[1][column, row] = (byte)(pixel >> 8);
54 raster[2][column, row] = (byte)pixel;
55 }
56
57 }
58
59 FluxJpeg.Core.ColorModel model =
60 new FluxJpeg.Core.ColorModel { colorspace = FluxJpeg.Core.ColorSpace.RGB };
61 FluxJpeg.Core.Image img = new FluxJpeg.Core.Image(model, raster);
62
63
64 //Encode the Image as a JPEG
65 MemoryStream stream = new MemoryStream();
66 FluxJpeg.Core.Encoder.JpegEncoder encoder =
67 new FluxJpeg.Core.Encoder.JpegEncoder(img, 100, stream);
68 encoder.Encode();
69
70 //Back to the start
71 stream.Seek(0, SeekOrigin.Begin);
72
73 //获取byte[]数组
74 //读二进制的长度
75 int readSize = 204800;
76 byte[] buffer = new Byte[readSize];
77 int byteRead = stream.Read(buffer, 0, readSize);
78 byte[] setData = new Byte[byteRead];
79 setData = buffer;
80 this.mapByte = setData;
81 }
82
83 #endregion

  “上传图片”按钮完整代码:

  

代码
1 //上传图片
2 private void btnUploadPic_Click(object sender, RoutedEventArgs e)
3 {
4 //打开选取窗口
5 OpenFileDialog openFileDialog = new OpenFileDialog()
6 {
7 Filter = "Images (*.BMP;*.JPG;)|*.BMP;*.JPG;|All Files(*.*)|*.*",
8 Multiselect = false
9 };
10
11 if (openFileDialog.ShowDialog() == true)
12 {
13 //获取上传文件
14 mapInfo = openFileDialog.File;
15
16 //判断文件格式是否正确
17 string[] mapFullName = mapInfo.Name.Split('.');
18 if (!(mapFullName[mapFullName.Length - 1].Contains("jpg") || mapFullName[mapFullName.Length - 1].Contains("bmp")))
19 {
20 MessageBox.Show(" 请选择.jpg或.bmp格式的文件! ");
21 return;
22 }
23
24 //读取文件流
25 Stream inputStream = mapInfo.OpenRead();
26 tempStream = inputStream;
27 //读二进制的长度,200KB
28 int readSize = 204800;
29
30 //判断图片大小
31 if (inputStream.Length > readSize)
32 {
33 MessageBox.Show(" 上传图片的大小不能超过200KB! ");
34 return;
35 }
36
37 //根据不同格式的文件,进行不同数据读取
38 if (mapFullName[mapFullName.Length - 1].Contains("bmp"))
39 {
40 //如果是bmp文件
41 //bmp图片解码
42 DoBackgroundWork(DoLoad, inputStream);
43 }
44 else
45 {
46 //如果是jpg文件
47 byte[] buffer = new Byte[readSize];
48 int byteRead = inputStream.Read(buffer, 0, readSize);
49 byte[] setData = new Byte[byteRead];
50 setData = buffer;
51 //为公共变量mapByte赋值
52 this.mapByte = setData;
53
54 if (mapInfo != null)
55 {
56 BitmapImage image = new BitmapImage();
57 image.SetSource(inputStream);
58 this.imgPrisonerPhoto.Source = image;
59 this.imgPrisonerPhoto.Visibility = Visibility.Visible;
60 inputStream.Close();
61 }
62 else
63 {
64 MessageBox.Show(" 请选择要上传的地图文件! ");
65 }
66 }
67 }
68 }

 

  5、BMP图片格式转化中用到了两个辅助类和一个引用。辅助类代码如下:

  BMPDecoder.cs

  

代码
1 using System;
2 using System.Windows;
3 using System.Windows.Controls;
4 using System.Windows.Documents;
5 using System.Windows.Ink;
6 using System.Windows.Input;
7 using System.Windows.Media;
8 using System.Windows.Media.Animation;
9 using System.Windows.Shapes;
10 using System.IO;
11
12 using System.Windows.Browser;
13 using System.Runtime.InteropServices;
14
15 namespace RPS.UI.ImagesConverter
16 {
17 public class BmpFileHeader
18 {
19 private const int _SIZE = 14;
20
21 public short BitmapType { get; set; }
22 public int Size { get; set; }
23 public short NA1 { get; set; }
24 public short NA2 { get; set; }
25 public int OffsetToData { get; set; }
26
27 public static BmpFileHeader FillFromStream(Stream stream)
28 {
29 byte[] buffer = new byte[_SIZE];
30 BmpFileHeader header = new BmpFileHeader();
31
32 stream.Read(buffer, 0, _SIZE);
33
34 // Fill
35 header.BitmapType = BitConverter.ToInt16(buffer, 0);
36 header.Size = BitConverter.ToInt32(buffer, 2);
37 header.OffsetToData = BitConverter.ToInt32(buffer, 10);
38
39 // Return results
40 return header;
41 }
42 }
43
44 public class BmpInfoHeader
45 {
46 private const int _SIZE = 40;
47
48 public int HeaderSize { get; set; }
49 public int Width { get; set; }
50 public int Height { get; set; }
51 public short NA1 { get; set; } // Color planes = 1
52 public short BitsPerPixel { get; set; }
53 public int Compression { get; set; }
54 public int ImageSize { get; set; }
55 public int NA2 { get; set; } // Horizontal pixels per meter
56 public int NA3 { get; set; } // Vertical pixels per meter
57 public int ColorCount { get; set; }
58 public int NA4 { get; set; } // Important colors = 0
59
60 public static BmpInfoHeader FillFromStream(Stream stream)
61 {
62 byte[] buffer = new byte[_SIZE];
63 BmpInfoHeader header = new BmpInfoHeader();
64
65 stream.Read(buffer, 0, _SIZE);
66
67 // Fill
68 header.HeaderSize = BitConverter.ToInt32(buffer, 0);
69 header.Width = BitConverter.ToInt32(buffer, 4);
70 header.Height = BitConverter.ToInt32(buffer, 8);
71 header.BitsPerPixel = BitConverter.ToInt16(buffer, 14);
72 header.Compression = BitConverter.ToInt32(buffer, 16);
73 header.ImageSize = BitConverter.ToInt32(buffer, 20);
74 header.ColorCount = BitConverter.ToInt32(buffer, 32);
75
76 if (header.ColorCount == 0)
77 {
78 header.ColorCount = (1 << header.BitsPerPixel);
79 }
80
81 // Return results
82 return header;
83 }
84 }
85
86 public class BMPDecoder
87 {
88 private const int _REDMASK = 0xF800;
89 private const int _GREENMASK = 0x07E0;
90 private const int _BLUEMASK = 0x001F;
91
92 public static Texture Decode(Stream stream)
93 {
94 Texture image = null;
95
96 // See http://en.wikipedia.org/wiki/BMP_file_format
97
98 byte[] buffer;
99 BmpFileHeader fHeader;
100 BmpInfoHeader iHeader;
101
102 // Read File Header
103 fHeader = BmpFileHeader.FillFromStream(stream);
104
105 // Validate file type
106 if (fHeader.BitmapType != 19778)
107 {
108 throw new Exception("Invalid BMP file");
109 }
110
111 // Read Info Header
112 iHeader = BmpInfoHeader.FillFromStream(stream);
113
114 // Data
115 if ((iHeader.Compression == 0) && (iHeader.BitsPerPixel == 24))
116 {
117 // Read bits into the buffer
118 buffer = new byte[iHeader.ImageSize];
119 stream.Read(buffer, 0, iHeader.ImageSize);
120
121 // Standard RGB file
122 image = Read24BitBmp(buffer, iHeader);
123 }
124 else if ((iHeader.Compression == 0) && (iHeader.BitsPerPixel <= 8))
125 {
126 int count = iHeader.ColorCount * 4; // 4 bytes per color
127 Color[] palette;
128
129 // Read colors
130 buffer = new byte[count];
131 stream.Read(buffer, 0, count);
132
133 palette = FillColorPalette(buffer, iHeader.ColorCount);
134
135 // Read data
136 buffer = new byte[iHeader.ImageSize];
137 stream.Read(buffer, 0, iHeader.ImageSize);
138
139 image = ReadPaletteBmp(buffer, palette, iHeader, iHeader.BitsPerPixel);
140 }
141 else if ((iHeader.Compression == 3) && (iHeader.BitsPerPixel == 16))
142 {
143 // Special 565 16 bit encoding - see http://www.virtualdub.org/blog/pivot/entry.php?id=177
144 int remainder = fHeader.OffsetToData - (int)stream.Position;
145 int rMask;
146 int bMask;
147 int gMask;
148
149 // Read remainder
150 buffer = new byte[remainder];
151 stream.Read(buffer, 0, remainder);
152
153 // Read masks
154 rMask = BitConverter.ToInt32(buffer, 0);
155 gMask = BitConverter.ToInt32(buffer, 4);
156 bMask = BitConverter.ToInt32(buffer, 8);
157
158 if ((_REDMASK != rMask) || (_GREENMASK != gMask) || (_BLUEMASK != bMask))
159 {
160 // Not 565 format
161 throw new Exception("Unsupported 16 bit format: " + rMask.ToString("X2") + ", " + bMask.ToString("X2") + ", " + gMask.ToString("X2"));
162 }
163
164 // Read data
165 remainder = iHeader.Height * iHeader.Width * 2; // 2 bytes per pixel
166 buffer = new byte[remainder];
167 stream.Read(buffer, 0, remainder);
168
169 // Convert to an image
170 image = Read565Bmp(buffer, iHeader);
171 }
172 else
173 {
174 throw new Exception("Unsupported format (compression: " + iHeader.Compression.ToString() + ", Bits per pixel: " + iHeader.BitsPerPixel.ToString() + ")");
175 }
176
177 return image;
178 }
179
180 private static Color[] FillColorPalette(byte[] buffer, int count)
181 {
182 Color[] colors = new Color[count];
183 int baseIdx;
184 byte alpha;
185
186 for (int idx = 0; idx < count; idx++)
187 {
188 baseIdx = idx * 4;
189 alpha = buffer[baseIdx + 3];
190 colors[idx] = Color.FromArgb(((alpha == 0) ? (byte)255 : alpha), buffer[baseIdx + 2], buffer[baseIdx + 1], buffer[baseIdx]);
191 }
192
193 return colors;
194 }
195
196 private static Texture Read565Bmp(byte[] buffer, BmpInfoHeader header)
197 {
198 int rowbase = 0;
199 int offset;
200 int realRow;
201 short color;
202 byte red;
203 byte green;
204 byte blue;
205 int scaleR = 256 / 32;
206 int scaleG = 256 / 64;
207
208 Texture image = new Texture(header.Width, header.Height);
209
210 for (int row = 0; row < header.Height; row++)
211 {
212 rowbase = (row * header.Width * 2);
213 for (int col = 0; col < header.Width; col++)
214 {
215 offset = rowbase + (col * 2);
216 realRow = header.Height - row - 1; // Reverse row
217
218 // Get color and convert
219 color = BitConverter.ToInt16(buffer, offset);
220 red = (byte)(((color & _REDMASK) >> 11) * scaleR);
221 green = (byte)(((color & _GREENMASK) >> 5) * scaleG);
222 blue = (byte)(((color & _BLUEMASK)) * scaleR);
223
224 // Set pixel
225 image.SetPixel(realRow, col, red, green, blue, 255);
226 }
227 }
228
229 return image;
230 }
231
232 private static Texture ReadPaletteBmp(byte[] buffer, Color[] palette, BmpInfoHeader header, int bpp)
233 {
234 int ppb = 8 / bpp; // Pixels per byte (bits per pixel)
235 int width = (header.Width + ppb - 1) / ppb;
236 int alignment = width % 4; // Rows are aligned on 4 byte boundaries
237 int mask = (0xFF >> (8 - bpp)); // Bit mask
238 int rowbase;
239 int colbase;
240 int offset;
241 int realRow;
242 Color color;
243
244 Texture image = new Texture(header.Width, header.Height);
245
246 if (alignment != 0)
247 {
248 alignment = 4 - alignment; // Calculate row padding
249 }
250
251 for (int row = 0; row < header.Height; row++)
252 {
253 rowbase = (row * (width + alignment));
254 for (int col = 0; col < width; col++)
255 {
256 offset = rowbase + col;
257 colbase = col * ppb;
258 realRow = header.Height - row - 1; // Reverse row
259 for (int shift = 0; ((shift < ppb) && ((colbase + shift) < header.Width)); shift++)
260 {
261 color = palette[((buffer[offset]) >> (8 - bpp - (shift * bpp))) & mask];
262 image.SetPixel(realRow, colbase + shift, color.R, color.G, color.B, 255);
263 }
264 }
265 }
266
267 return image;
268 }
269
270 private static Texture Read4BitBmp(byte[] buffer, Color[] palette, BmpInfoHeader header)
271 {
272 int width = (header.Width + 1) / 2;
273 int alignment = width % 4; // Rows are aligned on 4 byte boundaries
274 int rowbase = 0;
275 int colbase = 0;
276 int offset;
277 int realRow;
278 Color color1;
279 Color color2;
280
281 Texture image = new Texture(header.Width, header.Height);
282
283 if (alignment != 0)
284 {
285 alignment = 4 - alignment; // Calculate row padding
286 }
287
288 for (int row = 0; row < header.Height; row++)
289 {
290 rowbase = (row * (width + alignment));
291 for (int col = 0; col < width; col++)
292 {
293 colbase = col * 2;
294 offset = rowbase + col;
295 realRow = header.Height - row - 1; // Reverse row
296 color1 = palette[(buffer[offset]) >> 4];
297 color2 = palette[(buffer[offset]) & 0x0F];
298 image.SetPixel(realRow, colbase, color1.R, color1.G, color1.B, 255);
299 image.SetPixel(realRow, colbase + 1, color2.R, color2.G, color2.B, 255);
300 }
301 }
302
303 return image;
304 }
305
306 private static Texture Read8BitBmp(byte[] buffer, Color[] palette, BmpInfoHeader header)
307 {
308 int alignment = header.Width % 4; // Rows are aligned on 4 byte boundaries
309 int rowbase = 0;
310 int offset;
311 int realRow;
312 Color color;
313
314 Texture image = new Texture(header.Width, header.Height);
315
316 if (alignment != 0)
317 {
318 alignment = 4 - alignment; // Calculate row padding
319 }
320
321 for (int row = 0; row < header.Height; row++)
322 {
323 rowbase = (row * (header.Width + alignment));
324 for (int col = 0; col < header.Width; col++)
325 {
326 offset = rowbase + col;
327 realRow = header.Height - row - 1; // Reverse row
328 color = palette[buffer[offset]];
329 image.SetPixel(realRow, col, color.R, color.G, color.B, color.A);
330 }
331 }
332
333 return image;
334 }
335
336 private static Texture Read24BitBmp(byte[] buffer, BmpInfoHeader header)
337 {
338 int alignment = (header.Width * 3) % 4; // Rows are aligned on 4 byte boundaries
339 int rowbase = 0;
340 int offset;
341 int realRow;
342
343 Texture image = new Texture(header.Width, header.Height);
344
345 if (alignment != 0)
346 {
347 alignment = 4 - alignment; // Calculate row padding
348 }
349
350 for (int row = 0; row < header.Height; row++)
351 {
352 rowbase = (row * ((header.Width * 3) + alignment));
353 for (int col = 0; col < header.Width; col++)
354 {
355 offset = rowbase + (col * 3);
356 realRow = header.Height - row - 1; // Reverse row
357 if (offset >= buffer.Length)
358 {
359 HtmlPage.Window.Alert("Error - outside of bounds and not sure why");
360 }
361 image.SetPixel(realRow, col, buffer[offset + 2], buffer[offset + 1], buffer[offset], 255);
362 }
363 }
364
365 return image;
366 }
367 }
368 }

 

   Texture.cs

 

代码
1 using System;
2 using System.Net;
3 using System.Windows;
4 using System.Windows.Controls;
5 using System.Windows.Documents;
6 using System.Windows.Ink;
7 using System.Windows.Input;
8 using System.Windows.Media;
9 using System.Windows.Media.Animation;
10 using System.Windows.Shapes;
11 using System.Windows.Media.Imaging;
12
13 namespace RPS.UI.ImagesConverter
14 {
15 public class Texture
16 {
17 private int _width = 0;
18 private int _height = 0;
19 private WriteableBitmap _wb = null;
20 private int[] _data;
21
22 public Texture(int width, int height)
23 {
24 _width = width;
25 _height = height;
26
27 // Get pixels array
28 _data = new int[width * height];
29 }
30
31 public Texture(WriteableBitmap wb)
32 {
33 _height = wb.PixelHeight;
34 _width = wb.PixelWidth;
35 _wb = wb;
36 _data = _wb.Pixels;
37 }
38
39 public int Width { get { return _width; } }
40 public int Height { get { return _height; } }
41
42 public int GetPixel(int row, int col)
43 {
44 return _data[(row * _width) + col];
45 }
46
47 public Color GetColor(int row, int col)
48 {
49 int pixel = GetPixel(row, col);
50
51 return Color.FromArgb((byte)((pixel >> 0x18) & 0xFF),
52 (byte)((pixel >> 0x10) & 0xFF),
53 (byte)((pixel >> 8) & 0xFF),
54 (byte)(pixel & 0xFF));
55 }
56
57 public void SetPixel(int row, int col, byte red, byte green, byte blue, byte alpha)
58 {
59 _data[(row * _width) + col] = alpha << 24 | red << 16 | green << 8 | blue;
60 }
61
62 public void SetPixel(int row, int col, Color color)
63 {
64 SetPixel(row, col, color.R, color.G, color.B, color.A);
65 }
66
67 public WriteableBitmap GetWriteableBitmap()
68 {
69 if (null == _wb)
70 {
71 // Create WB
72 _wb = new WriteableBitmap(_width, _height);
73 }
74
75 // Copy data
76 _data.CopyTo(_wb.Pixels, 0);
77
78 _wb.Invalidate();
79
80 // Return as writeable bitmap
81 return _wb;
82 }
83
84 }
85 }
86

  封装好的FJCore包可以到这里下载:

  http://github.com/briandonahue/FluxJpeg.Core

  使用方法参考这里:

  http://developer.51cto.com/art/200911/161555.htm

 

  个人学习,仅供参考。  

 

    

posted @ 2010-09-11 21:54  dotNET程序猿  阅读(2823)  评论(3编辑  收藏  举报