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

时间:2021-08-03 23:17:28

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

  1、前台和数据库

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

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

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

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

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

Silverlight上传图片保存二进制数据到数据库(支持bmp方法)Silverlight上传图片保存二进制数据到数据库(支持bmp方法)代码
   
   
   
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 .img*erPhoto.Source = image;
14 this .img*erPhoto.Visibility = Visibility.Visible;
15 inputStream.Close();
16 }
17 else
18 {
19 MessageBox.Show( " 请选择要上传的地图文件! " );
20 }

 

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

  

Silverlight上传图片保存二进制数据到数据库(支持bmp方法)Silverlight上传图片保存二进制数据到数据库(支持bmp方法)代码
   
   
   
1 if (mapFullName[mapFullName.Length - 1 ].Contains( " bmp " ))
2 {
3 // 如果是bmp文件
4 // bmp图片解码
5 DoBackgroundWork(DoLoad, inputStream);
6 }

 

 

Silverlight上传图片保存二进制数据到数据库(支持bmp方法)Silverlight上传图片保存二进制数据到数据库(支持bmp方法)代码
   
   
   
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 img*erPhoto.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

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

  

Silverlight上传图片保存二进制数据到数据库(支持bmp方法)Silverlight上传图片保存二进制数据到数据库(支持bmp方法)代码
   
   
   
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 .img*erPhoto.Source = image;
59 this .img*erPhoto.Visibility = Visibility.Visible;
60 inputStream.Close();
61 }
62 else
63 {
64 MessageBox.Show( " 请选择要上传的地图文件! " );
65 }
66 }
67 }
68 }

 

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

  BMPDecoder.cs

  

Silverlight上传图片保存二进制数据到数据库(支持bmp方法)Silverlight上传图片保存二进制数据到数据库(支持bmp方法)代码
   
   
   
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

 

Silverlight上传图片保存二进制数据到数据库(支持bmp方法)Silverlight上传图片保存二进制数据到数据库(支持bmp方法)代码
   
   
   
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

http://www.cnblogs.com/lichence/archive/2010/09/11/1824157.html