写代码这事,掐指算来已经十有余年。

 

从html到css到javascript到vbscript到c#,从兴趣到职业,生活总是失落与惊喜并存。

 

绝大部分时候,出发并不是因为知道该到哪里去,只是知道不能再逗留下去了,如此而已。受过风吹雨打之后会有很多独有的感受及思考,主见开始生发并在摇摆中坚定,想来这就是成长了,嗯……就算是成长吧,呵呵!

 

话说微软的 .net core 3.0 即将发布了,作为一个码农,还是要关心一下的。从 .net core 2.0 及MySql官方开始支持 .net core 起,我尝试将自己的类库转成 .net standard 类库,开始了解 .net core 的成熟度,写了几个 demo ,之后就放弃了,因为我做的项目还是以web(asp.net core)为主,但是 .net core 对图片的处理是空白的,System.Drawing只是一个摆设(估计以后也是一样),即便是有很多人推崇的 ImageSharp 也因为接口变化过大且缺少文档在稍作尝试之后放弃了,我想,在 .net core 下应该还没有一个成熟的图片处理类库,还不足以迁移项目。如果按微软官方的意思要搞一个独立的图片处理应用来进行图片处理,那 asp.net core 只是作为一个简单的数据接口来用,这就很值得权衡一下了,毕竟中小型项目要去搞一个专门的图片处理应用是得不偿失的,不知道微软的产品和工程师们是否有过这些思量?又或者只是所谓的企业级应用才是他们的目标?

 

我假设 System.Drawing 在 .net core 中的下场就像 IE 浏览器和 Edge 浏览器在Win10 后的下场一样,也许该放弃了。那就找个替代方案吧,所以最终决定采用 SkiaSharp 来做图片处理,顺便处理一下二维码,毕竟也是图片嘛,并且二维码在天朝是很有场景可用的,之前在 .net framework 中我一致习惯用 ThoughtWorks.QRCode 来处理二维码的生成和解析,不过目前 ThoughtWorks.QRCode 好像还不支持在 .net core 中工作,因此二维码的生成和解析最后采用 ZXing.Net 来处理。

 

用 ZXing.Net 生成的二维码默认是有一定比例的白边的,大概算是一种工业标准,但是在实际的应用场景中有时候可能不需要白边,所以我对白边做了一点逻辑处理,对白边可以指定要保留的宽度像素值也可以保留原始的默认白边。

 

通过引用 SkiaSharp(1.68.0) 和 ZXing.Net(0.16.4) ,之后写了一个静态类,用来对图片进行缩放和裁剪等基本操作以及生成和解析二维码,代码如下:

  1 public static class ImageHelper
  2     {
  3         static readonly long maxLength = 10485760;//10*1024*1024
  4         public static SkiaSharp.SKEncodedImageFormat GetImageFormatBySuffix(string suffix)
  5         {
  6             var format = SkiaSharp.SKEncodedImageFormat.Jpeg;
  7             if (string.IsNullOrEmpty(suffix))
  8             {
  9                 return format;
 10             }
 11             if (suffix[0] == '.')
 12             {
 13                 suffix = suffix.Substring(1);
 14             }
 15             if (string.IsNullOrEmpty(suffix))
 16             {
 17                 return format;
 18             }
 19             suffix = suffix.ToUpper();
 20             switch (suffix)
 21             {
 22                 case "PNG":
 23                     format = SkiaSharp.SKEncodedImageFormat.Png;
 24                     break;
 25                 case "GIF":
 26                     format = SkiaSharp.SKEncodedImageFormat.Gif;
 27                     break;
 28                 case "BMP":
 29                     format = SkiaSharp.SKEncodedImageFormat.Bmp;
 30                     break;
 31                 case "ICON":
 32                     format = SkiaSharp.SKEncodedImageFormat.Ico;
 33                     break;
 34                 case "ICO":
 35                     format = SkiaSharp.SKEncodedImageFormat.Ico;
 36                     break;
 37                 case "DNG":
 38                     format = SkiaSharp.SKEncodedImageFormat.Dng;
 39                     break;
 40                 case "WBMP":
 41                     format = SkiaSharp.SKEncodedImageFormat.Wbmp;
 42                     break;
 43                 case "WEBP":
 44                     format = SkiaSharp.SKEncodedImageFormat.Webp;
 45                     break;
 46                 case "PKM":
 47                     format = SkiaSharp.SKEncodedImageFormat.Pkm;
 48                     break;
 49                 case "KTX":
 50                     format = SkiaSharp.SKEncodedImageFormat.Ktx;
 51                     break;
 52                 case "ASTC":
 53                     format = SkiaSharp.SKEncodedImageFormat.Astc;
 54                     break;
 55             }
 56             return format;
 57         }
 58         public static SkiaSharp.SKEncodedImageFormat GetImageFormatByPath(string path)
 59         {
 60             var suffix = "";
 61             if (System.IO.Path.HasExtension(path))
 62             {
 63                 suffix = System.IO.Path.GetExtension(path);
 64             }
 65             return GetImageFormatBySuffix(suffix);
 66         }
 67         public static Tuple<int, int, long, SkiaSharp.SKEncodedImageFormat> GetImageInfo(string path)
 68         {
 69             if (string.IsNullOrEmpty(path))
 70             {
 71                 throw new Exception("路径不能为空");
 72             }
 73             if (!System.IO.File.Exists(path))
 74             {
 75                 throw new Exception("文件不存在");
 76             }
 77             var fileStream = new System.IO.FileStream(path, System.IO.FileMode.Open, System.IO.FileAccess.Read, System.IO.FileShare.Read); //fileInfo.OpenRead();
 78             var fileLength = fileStream.Length;
 79             if (fileLength > maxLength)
 80             {
 81                 fileStream.Dispose();
 82                 throw new Exception("文件过大");
 83             }
 84             var sKManagedStream = new SkiaSharp.SKManagedStream(fileStream, true);
 85             var sKBitmap = SkiaSharp.SKBitmap.Decode(sKManagedStream);
 86             sKManagedStream.Dispose();
 87 
 88             if (sKBitmap.IsEmpty)
 89             {
 90                 sKBitmap.Dispose();
 91                 throw new Exception("文件无效");
 92             }
 93             int w = sKBitmap.Width;
 94             int h = sKBitmap.Height;
 95             return new Tuple<int, int, long, SkiaSharp.SKEncodedImageFormat>(w, h, fileLength, GetImageFormatByPath(path));
 96         }
 97         public static void ImageMaxCutByCenter(string path, string savePath, int saveWidth, int saveHeight, int quality)
 98         {
 99             var bytes = ImageMaxCutByCenter(path, saveWidth, saveHeight, quality);
100             if (bytes == null || bytes.Length < 1)
101             {
102                 return;
103             }
104             string saveDirPath = System.IO.Path.GetDirectoryName(savePath);
105             if (!System.IO.Directory.Exists(saveDirPath))
106             {
107                 System.IO.Directory.CreateDirectory(saveDirPath);
108             }
109             System.IO.FileStream fs = new System.IO.FileStream(savePath, System.IO.FileMode.OpenOrCreate, System.IO.FileAccess.Write, System.IO.FileShare.None);
110             fs.Write(bytes, 0, bytes.Length);
111             fs.Close();
112         }
113         public static byte[] ImageMaxCutByCenter(string path, int saveWidth, int saveHeight, int quality)
114         {
115             byte[] bytes = null;
116             if (!System.IO.File.Exists(path))
117             {
118                 return bytes;
119             }
120             var fileStream = new System.IO.FileStream(path, System.IO.FileMode.Open, System.IO.FileAccess.Read, System.IO.FileShare.Read); //fileInfo.OpenRead();
121             if (fileStream.Length > maxLength)
122             {
123                 fileStream.Dispose();
124                 return bytes;
125             }
126             var sKManagedStream = new SkiaSharp.SKManagedStream(fileStream, true);
127             var sKBitmap = SkiaSharp.SKBitmap.Decode(sKManagedStream);
128             sKManagedStream.Dispose();
129 
130             if (sKBitmap.IsEmpty)
131             {
132                 return bytes;
133             }
134 
135             if (saveWidth < 1) { saveWidth = 1; }
136             if (saveHeight < 1) { saveHeight = 1; }
137             if (quality < 1) { quality = 1; }
138             if (quality > 100) { quality = 100; }
139 
140             int oW = sKBitmap.Width;
141             int oH = sKBitmap.Height;
142             int cutW = saveWidth;
143             int cutH = saveHeight;
144             double ratio = 1;
145             if (cutW > oW)
146             {
147                 ratio = (double)oW / (double)cutW;
148                 cutH = Convert.ToInt32((double)cutH * ratio);
149                 cutW = oW;
150                 if (cutH > oH)
151                 {
152                     ratio = (double)oH / (double)cutH;
153                     cutW = Convert.ToInt32((double)cutW * ratio);
154                     cutH = oH;
155                 }
156             }
157             else if (cutW < oW)
158             {
159                 ratio = (double)oW / (double)cutW;
160                 cutH = Convert.ToInt32(Convert.ToDouble(cutH) * ratio);
161                 cutW = oW;
162                 if (cutH > oH)
163                 {
164                     ratio = (double)oH / (double)cutH;
165                     cutW = Convert.ToInt32((double)cutW * ratio);
166                     cutH = oH;
167                 }
168             }
169             else
170             {
171                 if (cutH > oH)
172                 {
173                     ratio = (double)oH / (double)cutH;
174                     cutW = Convert.ToInt32((double)cutW * ratio);
175                     cutH = oH;
176                 }
177             }
178             int startX = oW > cutW ? (oW / 2 - cutW / 2) : (cutW / 2 - oW / 2);
179             int startY = oH > cutH ? (oH / 2 - cutH / 2) : (cutH / 2 - oH / 2);
180 
181             var sKBitmap2 = new SkiaSharp.SKBitmap(saveWidth, saveHeight);
182             var sKCanvas = new SkiaSharp.SKCanvas(sKBitmap2);
183             var sKPaint = new SkiaSharp.SKPaint
184             {
185                 FilterQuality = SkiaSharp.SKFilterQuality.Medium,
186                 IsAntialias = true
187             };
188             sKCanvas.DrawBitmap(
189                 sKBitmap,
190                 new SkiaSharp.SKRect
191                 {
192                     Location = new SkiaSharp.SKPoint { X = startX, Y = startY },
193                     Size = new SkiaSharp.SKSize { Height = cutH, Width = cutW }
194                 },
195                 new SkiaSharp.SKRect
196                 {
197                     Location = new SkiaSharp.SKPoint { X = 0, Y = 0 },
198                     Size = new SkiaSharp.SKSize { Height = saveHeight, Width = saveWidth }
199                 }, sKPaint);
200             sKCanvas.Dispose();
201             var sKImage2 = SkiaSharp.SKImage.FromBitmap(sKBitmap2);
202             sKBitmap2.Dispose();
203             var data = sKImage2.Encode(GetImageFormatByPath(path), quality);
204             sKImage2.Dispose();
205             bytes = data.ToArray();
206             data.Dispose();
207 
208             return bytes;
209         }
210         public static void ImageScalingToRange(string path, string savePath, int maxWidth, int maxHeight, int quality)
211         {
212             var bytes = ImageScalingToRange(path, maxWidth, maxHeight, quality);
213             if (bytes == null || bytes.Length < 1)
214             {
215                 return;
216             }
217             string saveDirPath = System.IO.Path.GetDirectoryName(savePath);
218             if (!System.IO.Directory.Exists(saveDirPath))
219             {
220                 System.IO.Directory.CreateDirectory(saveDirPath);
221             }
222             System.IO.FileStream fs = new System.IO.FileStream(savePath, System.IO.FileMode.OpenOrCreate, System.IO.FileAccess.Write, System.IO.FileShare.None);
223             fs.Write(bytes, 0, bytes.Length);
224             fs.Close();
225         }
226         public static byte[] ImageScalingToRange(string path, int maxWidth, int maxHeight, int quality)
227         {
228             byte[] bytes = null;
229             if (!System.IO.File.Exists(path))
230             {
231                 return bytes;
232             }
233             var fileStream = new System.IO.FileStream(path, System.IO.FileMode.Open, System.IO.FileAccess.Read, System.IO.FileShare.Read); //fileInfo.OpenRead();
234             if (fileStream.Length > maxLength)
235             {
236                 fileStream.Dispose();
237                 return bytes;
238             }
239             var sKManagedStream = new SkiaSharp.SKManagedStream(fileStream, true);
240             var sKBitmap = SkiaSharp.SKBitmap.Decode(sKManagedStream);
241             sKManagedStream.Dispose();
242 
243             if (sKBitmap.IsEmpty)
244             {
245                 return bytes;
246             }
247 
248             if (maxWidth < 1) { maxWidth = 1; }
249             if (maxHeight < 1) { maxHeight = 1; }
250             if (quality < 1) { quality = 1; }
251             if (quality > 100) { quality = 100; }
252 
253             int oW = sKBitmap.Width;
254             int oH = sKBitmap.Height;
255             int nW = oW;
256             int nH = oH;
257 
258             if (nW < maxWidth && nH < maxHeight)//放大
259             {
260                 if (nW < maxWidth)
261                 {
262                     var r = (double)maxWidth / (double)nW;
263                     nW = maxWidth;
264                     nH = (int)Math.Floor((double)nH * r);
265                 }
266                 if (nH < maxHeight)
267                 {
268                     var r = (double)maxHeight / (double)nH;
269                     nH = maxHeight;
270                     nW = (int)Math.Floor((double)nW * r);
271                 }
272             }
273             //限制超出(缩小)
274             if (nW > maxWidth)
275             {
276                 var r = (double)maxWidth / (double)nW;
277                 nW = maxWidth;
278                 nH = (int)Math.Floor((double)nH * r);
279             }
280             if (nH > maxHeight)
281             {
282                 var r = (double)maxHeight / (double)nH;
283                 nH = maxHeight;
284                 nW = (int)Math.Floor((double)nW * r);
285             }
286 
287 
288             var sKBitmap2 = new SkiaSharp.SKBitmap(nW, nH);
289             var sKCanvas = new SkiaSharp.SKCanvas(sKBitmap2);
290             var sKPaint = new SkiaSharp.SKPaint
291             {
292                 FilterQuality = SkiaSharp.SKFilterQuality.Medium,
293                 IsAntialias = true
294             };
295             sKCanvas.DrawBitmap(
296                 sKBitmap,
297                 new SkiaSharp.SKRect
298                 {
299                     Location = new SkiaSharp.SKPoint { X = 0, Y = 0 },
300                     Size = new SkiaSharp.SKSize { Height = oH, Width = oW }
301                 },
302                 new SkiaSharp.SKRect
303                 {
304                     Location = new SkiaSharp.SKPoint { X = 0, Y = 0 },
305                     Size = new SkiaSharp.SKSize { Height = nH, Width = nW }
306                 }, sKPaint);
307             sKCanvas.Dispose();
308             var sKImage2 = SkiaSharp.SKImage.FromBitmap(sKBitmap2);
309             sKBitmap2.Dispose();
310             var data = sKImage2.Encode(GetImageFormatByPath(path), quality);
311             sKImage2.Dispose();
312             bytes = data.ToArray();
313             data.Dispose();
314 
315             return bytes;
316         }
317         public static void ImageScalingByOversized(string path, string savePath, int maxWidth, int maxHeight, int quality)
318         {
319             var bytes = ImageScalingByOversized(path, maxWidth, maxHeight, quality);
320             if (bytes == null || bytes.Length < 1)
321             {
322                 return;
323             }
324             string saveDirPath = System.IO.Path.GetDirectoryName(savePath);
325             if (!System.IO.Directory.Exists(saveDirPath))
326             {
327                 System.IO.Directory.CreateDirectory(saveDirPath);
328             }
329             System.IO.FileStream fs = new System.IO.FileStream(savePath, System.IO.FileMode.OpenOrCreate, System.IO.FileAccess.Write, System.IO.FileShare.None);
330             fs.Write(bytes, 0, bytes.Length);
331             fs.Close();
332         }
333         public static byte[] ImageScalingByOversized(string path, int maxWidth, int maxHeight, int quality)
334         {
335             byte[] bytes = null;
336             if (!System.IO.File.Exists(path))
337             {
338                 return bytes;
339             }
340             var fileStream = new System.IO.FileStream(path, System.IO.FileMode.Open, System.IO.FileAccess.Read, System.IO.FileShare.Read);
341             if (fileStream.Length > maxLength)
342             {
343                 fileStream.Dispose();
344                 return bytes;
345             }
346             var sKManagedStream = new SkiaSharp.SKManagedStream(fileStream, true);
347             var sKBitmap = SkiaSharp.SKBitmap.Decode(sKManagedStream);
348             sKManagedStream.Dispose();
349 
350             if (sKBitmap.IsEmpty)
351             {
352                 return bytes;
353             }
354 
355             if (maxWidth < 1) { maxWidth = 1; }
356             if (maxHeight < 1) { maxHeight = 1; }
357             if (quality < 1) { quality = 1; }
358             if (quality > 100) { quality = 100; }
359 
360             int oW = sKBitmap.Width;
361             int oH = sKBitmap.Height;
362             int nW = oW;
363             int nH = oH;
364 
365             if (oW > maxWidth || oH > maxHeight)
366             {
367                 nW = maxWidth;
368                 nH = maxHeight;
369                 double ratio = 1;
370 
371                 if (nW > 0 && nH > 0)
372                 {
373                     ratio = (double)nW / oW;
374                     nH = Convert.ToInt32(oH * ratio);
375                     if (maxHeight < nH)
376                     {
377                         ratio = (double)maxHeight / nH;
378                         nW = Convert.ToInt32(nW * ratio);
379                         nH = maxHeight;
380                     }
381                 }
382                 if (nW < 1 && nH < 1)
383                 {
384                     nW = oW;
385                     nH = oH;
386                 }
387                 if (nW < 1)
388                 {
389                     ratio = (double)nH / oH;
390                     nW = Convert.ToInt32(oW * ratio);
391                 }
392                 if (nH < 1)
393                 {
394                     ratio = (double)nW / oW;
395                     nH = Convert.ToInt32(oH * ratio);
396                 }
397                 var sKBitmap2 = new SkiaSharp.SKBitmap(nW, nH);
398                 var sKCanvas = new SkiaSharp.SKCanvas(sKBitmap2);
399                 var sKPaint = new SkiaSharp.SKPaint
400                 {
401                     FilterQuality = SkiaSharp.SKFilterQuality.Medium,
402                     IsAntialias = true
403                 };
404                 sKCanvas.DrawBitmap(
405                     sKBitmap,
406                     new SkiaSharp.SKRect
407                     {
408                         Location = new SkiaSharp.SKPoint { X = 0, Y = 0 },
409                         Size = new SkiaSharp.SKSize { Height = oH, Width = oW }
410                     },
411                     new SkiaSharp.SKRect
412                     {
413                         Location = new SkiaSharp.SKPoint { X = 0, Y = 0 },
414                         Size = new SkiaSharp.SKSize { Height = nH, Width = nW }
415                     }, sKPaint);
416                 sKCanvas.Dispose();
417                 sKBitmap.Dispose();
418                 sKBitmap = sKBitmap2;
419             }
420 
421             var sKImage = SkiaSharp.SKImage.FromBitmap(sKBitmap);
422             sKBitmap.Dispose();
423             var data = sKImage.Encode(GetImageFormatByPath(path), quality);
424             sKImage.Dispose();
425             bytes = data.ToArray();
426             data.Dispose();
427 
428             return bytes;
429         }
430 
431         /// <summary>
432         /// 生成二维码(320*320)
433         /// </summary>
434         /// <param name="text">文本内容</param>
435         /// <param name="savePath">保存路径</param>
436         /// <param name="logoPath">Logo图片路径(缩放到真实二维码区域尺寸的1/6)</param>
437         /// <param name="keepWhiteBorderPixelVal">白边处理(负值表示不做处理,最大值不超过真实二维码区域的1/10)</param>
438         public static void QRCoder(string text, string savePath, string logoPath = "", int keepWhiteBorderPixelVal = -1)
439         {
440             var format = GetImageFormatByPath(savePath);
441             byte[] bytesLogo = null;
442             if (!string.IsNullOrEmpty(logoPath) && System.IO.File.Exists(logoPath))
443             {
444                 var fsLogo = new System.IO.FileStream(logoPath, System.IO.FileMode.Open, System.IO.FileAccess.Read, System.IO.FileShare.Read);
445                 System.IO.MemoryStream ms = new System.IO.MemoryStream();
446                 fsLogo.CopyTo(ms);
447                 fsLogo.Dispose();
448                 bytesLogo = ms.ToArray();
449                 ms.Dispose();
450             }
451 
452             var bytes = QRCoder(text, format, bytesLogo, keepWhiteBorderPixelVal);
453 
454             if (bytes == null || bytes.Length < 1)
455             {
456                 return;
457             }
458 
459             var saveDirPath = System.IO.Path.GetDirectoryName(savePath);
460             if (!System.IO.Directory.Exists(saveDirPath))
461             {
462                 System.IO.Directory.CreateDirectory(saveDirPath);
463             }
464             var fs = new System.IO.FileStream(savePath, System.IO.FileMode.OpenOrCreate, System.IO.FileAccess.Write, System.IO.FileShare.None);
465             fs.Write(bytes, 0, bytes.Length);
466             fs.Close();
467         }
468         /// <summary>
469         /// 生成二维码(320*320)
470         /// </summary>
471         /// <param name="text">文本内容</param>
472         /// <param name="format">保存格式</param>
473         /// <param name="logoImgae">Logo图片(缩放到真实二维码区域尺寸的1/6)</param>
474         /// <param name="keepWhiteBorderPixelVal">白边处理(负值表示不做处理,最大值不超过真实二维码区域的1/10)</param>
475         /// <returns></returns>
476         public static byte[] QRCoder(string text, SkiaSharp.SKEncodedImageFormat format, byte[] logoImgae = null, int keepWhiteBorderPixelVal = -1)
477         {
478             byte[] reval = null;
479             int width = 320;
480             int height = 320;
481             var qRCodeWriter = new ZXing.QrCode.QRCodeWriter();
482             var hints = new Dictionary<ZXing.EncodeHintType, object>();
483             hints.Add(ZXing.EncodeHintType.CHARACTER_SET, "utf-8");
484             hints.Add(ZXing.EncodeHintType.QR_VERSION, 8);
485             hints.Add(ZXing.EncodeHintType.ERROR_CORRECTION, ZXing.QrCode.Internal.ErrorCorrectionLevel.Q);
486             var bitMatrix = qRCodeWriter.encode(text, ZXing.BarcodeFormat.QR_CODE, width, height, hints);
487             var w = bitMatrix.Width;
488             var h = bitMatrix.Height;
489             var sKBitmap = new SkiaSharp.SKBitmap(w, h);
490 
491             int blackStartPointX = 0;
492             int blackStartPointY = 0;
493             int blackEndPointX = w;
494             int blackEndPointY = h;
495 
496             #region --绘制二维码(同时获取真实的二维码区域起绘点和结束点的坐标)--
497             var sKCanvas = new SkiaSharp.SKCanvas(sKBitmap);
498             var sKColorBlack = SkiaSharp.SKColor.Parse("000000");
499             var sKColorWihte = SkiaSharp.SKColor.Parse("ffffff");
500             sKCanvas.Clear(sKColorWihte);
501             bool blackStartPointIsNotWriteDown = true;
502             for (var y = 0; y < h; y++)
503             {
504                 for (var x = 0; x < w; x++)
505                 {
506                     var flag = bitMatrix[x, y];
507                     if (flag)
508                     {
509                         if (blackStartPointIsNotWriteDown)
510                         {
511                             blackStartPointX = x;
512                             blackStartPointY = y;
513                             blackStartPointIsNotWriteDown = false;
514                         }
515                         blackEndPointX = x;
516                         blackEndPointY = y;
517                         sKCanvas.DrawPoint(x, y, sKColorBlack);
518                     }
519                     else
520                     {
521                         //sKCanvas.DrawPoint(x, y, sKColorWihte);//不用绘制(背景是白色的)
522                     }
523                 }
524             }
525             sKCanvas.Dispose();
526             #endregion
527 
528             int qrcodeRealWidth = blackEndPointX - blackStartPointX;
529             int qrcodeRealHeight = blackEndPointY - blackStartPointY;
530 
531             #region -- 处理白边 --
532             if (keepWhiteBorderPixelVal > -1)//指定了边框宽度
533             {
534                 var borderMaxWidth = (int)Math.Floor((double)qrcodeRealWidth / 10);
535                 if (keepWhiteBorderPixelVal > borderMaxWidth)
536                 {
537                     keepWhiteBorderPixelVal = borderMaxWidth;
538                 }
539                 var nQrcodeRealWidth = width - keepWhiteBorderPixelVal - keepWhiteBorderPixelVal;
540                 var nQrcodeRealHeight = height - keepWhiteBorderPixelVal - keepWhiteBorderPixelVal;
541 
542                 var sKBitmap2 = new SkiaSharp.SKBitmap(width, height);
543                 var sKCanvas2 = new SkiaSharp.SKCanvas(sKBitmap2);
544                 sKCanvas2.Clear(sKColorWihte);
545                 //二维码绘制到临时画布上时无需抗锯齿等处理(避免文件增大)
546                 sKCanvas2.DrawBitmap(
547                     sKBitmap,
548                     new SkiaSharp.SKRect
549                     {
550                         Location = new SkiaSharp.SKPoint { X = blackStartPointX, Y = blackStartPointY },
551                         Size = new SkiaSharp.SKSize { Height = qrcodeRealHeight, Width = qrcodeRealWidth }
552                     },
553                     new SkiaSharp.SKRect
554                     {
555                         Location = new SkiaSharp.SKPoint { X = keepWhiteBorderPixelVal, Y = keepWhiteBorderPixelVal },
556                         Size = new SkiaSharp.SKSize { Width = nQrcodeRealWidth, Height = nQrcodeRealHeight }
557                     });
558 
559                 blackStartPointX = keepWhiteBorderPixelVal;
560                 blackStartPointY = keepWhiteBorderPixelVal;
561                 qrcodeRealWidth = nQrcodeRealWidth;
562                 qrcodeRealHeight = nQrcodeRealHeight;
563 
564                 sKCanvas2.Dispose();
565                 sKBitmap.Dispose();
566                 sKBitmap = sKBitmap2;
567             }
568             #endregion
569 
570             #region -- 绘制LOGO --
571             if (logoImgae != null && logoImgae.Length > 0)
572             {
573                 SkiaSharp.SKBitmap sKBitmapLogo = SkiaSharp.SKBitmap.Decode(logoImgae);
574                 if (!sKBitmapLogo.IsEmpty)
575                 {
576                     var sKPaint2 = new SkiaSharp.SKPaint
577                     {
578                         FilterQuality = SkiaSharp.SKFilterQuality.None,
579                         IsAntialias = true
580                     };
581                     var logoTargetMaxWidth = (int)Math.Floor((double)qrcodeRealWidth / 6);
582                     var logoTargetMaxHeight = (int)Math.Floor((double)qrcodeRealHeight / 6);
583                     var qrcodeCenterX = (int)Math.Floor((double)qrcodeRealWidth / 2);
584                     var qrcodeCenterY = (int)Math.Floor((double)qrcodeRealHeight / 2);
585                     var logoResultWidth = sKBitmapLogo.Width;
586                     var logoResultHeight = sKBitmapLogo.Height;
587                     if (logoResultWidth > logoTargetMaxWidth)
588                     {
589                         var r = (double)logoTargetMaxWidth / logoResultWidth;
590                         logoResultWidth = logoTargetMaxWidth;
591                         logoResultHeight = (int)Math.Floor(logoResultHeight * r);
592                     }
593                     if (logoResultHeight > logoTargetMaxHeight)
594                     {
595                         var r = (double)logoTargetMaxHeight / logoResultHeight;
596                         logoResultHeight = logoTargetMaxHeight;
597                         logoResultWidth = (int)Math.Floor(logoResultWidth * r);
598                     }
599                     var pointX = qrcodeCenterX - (int)Math.Floor((double)logoResultWidth / 2) + blackStartPointX;
600                     var pointY = qrcodeCenterY - (int)Math.Floor((double)logoResultHeight / 2) + blackStartPointY;
601 
602                     var sKCanvas3 = new SkiaSharp.SKCanvas(sKBitmap);
603                     var sKPaint = new SkiaSharp.SKPaint
604                     {
605                         FilterQuality = SkiaSharp.SKFilterQuality.Medium,
606                         IsAntialias = true
607                     };
608                     sKCanvas3.DrawBitmap(
609                         sKBitmapLogo,
610                         new SkiaSharp.SKRect
611                         {
612                             Location = new SkiaSharp.SKPoint { X = 0, Y = 0 },
613                             Size = new SkiaSharp.SKSize { Height = sKBitmapLogo.Height, Width = sKBitmapLogo.Width }
614                         },
615                         new SkiaSharp.SKRect
616                         {
617                             Location = new SkiaSharp.SKPoint { X = pointX, Y = pointY },
618                             Size = new SkiaSharp.SKSize { Height = logoResultHeight, Width = logoResultWidth }
619                         }, sKPaint);
620                     sKCanvas3.Dispose();
621                     sKPaint.Dispose();
622                     sKBitmapLogo.Dispose();
623                 }
624                 else
625                 {
626                     sKBitmapLogo.Dispose();
627                 }
628             }
629             #endregion
630 
631             SkiaSharp.SKImage sKImage = SkiaSharp.SKImage.FromBitmap(sKBitmap);
632             sKBitmap.Dispose();
633             var data = sKImage.Encode(format, 75);
634             sKImage.Dispose();
635             reval = data.ToArray();
636             data.Dispose();
637 
638             return reval;
639         }
640         public static string QRDecoder(string qrCodeFilePath)
641         {
642             if (!System.IO.File.Exists(qrCodeFilePath))
643             {
644                 throw new Exception("文件不存在");
645             }
646 
647             System.IO.FileStream fileStream = new System.IO.FileStream(qrCodeFilePath, System.IO.FileMode.Open, System.IO.FileAccess.Read, System.IO.FileShare.Read);
648             if (fileStream.Length > maxLength)
649             {
650                 fileStream.Dispose();
651                 throw new Exception("图片文件太大");
652             }
653             return QRDecoder(fileStream);
654         }
655         public static string QRDecoder(byte[] qrCodeBytes)
656         {
657             if(qrCodeBytes==null|| qrCodeBytes.Length<1)
658             {
659                 throw new Exception("参数qrCodeBytes不存在");
660             }
661             if (qrCodeBytes.Length > maxLength)
662             {
663                 throw new Exception("图片文件太大");
664             }
665             System.IO.MemoryStream ms = new System.IO.MemoryStream(qrCodeBytes);
666             return QRDecoder(ms);
667         }
668         public static string QRDecoder(System.IO.Stream qrCodeFileStream)
669         {
670             var sKManagedStream = new SkiaSharp.SKManagedStream(qrCodeFileStream, true);
671             var sKBitmap = SkiaSharp.SKBitmap.Decode(sKManagedStream);
672             sKManagedStream.Dispose();
673             if (sKBitmap.IsEmpty)
674             {
675                 sKBitmap.Dispose();
676                 throw new Exception("未识别的图片文件");
677             }
678 
679             var w = sKBitmap.Width;
680             var h = sKBitmap.Height;
681             int ps = w * h;
682             byte[] bytes = new byte[ps * 3];
683             int byteIndex = 0;
684             for (var x = 0; x < w; x++)
685             {
686                 for (var y = 0; y < h; y++)
687                 {
688                     var color = sKBitmap.GetPixel(x, y);
689                     bytes[byteIndex + 0] = color.Red;
690                     bytes[byteIndex + 1] = color.Green;
691                     bytes[byteIndex + 2] = color.Blue;
692                     byteIndex += 3;
693                 }
694             }
695             sKBitmap.Dispose();
696 
697             var qRCodeReader = new ZXing.QrCode.QRCodeReader();
698             var rGBLuminanceSource = new ZXing.RGBLuminanceSource(bytes, w, h);
699             var hybridBinarizer = new ZXing.Common.HybridBinarizer(rGBLuminanceSource);
700             var binaryBitmap = new ZXing.BinaryBitmap(hybridBinarizer);
701             var hints = new Dictionary<ZXing.DecodeHintType, object>();
702             hints.Add(ZXing.DecodeHintType.CHARACTER_SET, "utf-8");
703             var result = qRCodeReader.decode(binaryBitmap, hints);
704 
705             return result != null ? result.Text : "";
706         }
707     }
View Code

开个控制台程序测试一下,测试代码:

 1 static void Main(string[] args)
 2         {
 3             var path = @"d:\a\文字设计.png";//size=595*842
 4             ImageHelper.ImageMaxCutByCenter(path, @"d:\a\文字设计002.png", 1024, 768, 75);//size=1024*768
 5             ImageHelper.ImageMaxCutByCenter(path, @"d:\a\文字设计003.png", 768, 1024, 75);//size=768*1024
 6             ImageHelper.ImageScalingToRange(path, @"d:\a\文字设计004.png", 1024, 768, 75);//size=542*768
 7             ImageHelper.ImageScalingToRange(path, @"d:\a\文字设计005.png", 768, 1024, 75);//size=724*1024
 8             ImageHelper.ImageScalingByOversized(path, @"d:\a\文字设计006.png", 640, 320, 75);//size=226*320
 9             ImageHelper.ImageScalingByOversized(path, @"d:\a\文字设计007.png", 320, 640, 75);//size=320*453
10 
11             var qrcodeSavePath = @"d:\a\hello.png";
12             var qrcodeLogoPath = @"d:\a\logo.png";
13             var qrcodeWhiteBorderPixelVal = 5;
14             var qrcodeText = "高堂明镜悲白发,朝如青丝暮成雪!";
15             ImageHelper.QRCoder(qrcodeText, qrcodeSavePath, qrcodeLogoPath, qrcodeWhiteBorderPixelVal);
16             var result = ImageHelper.QRDecoder(qrcodeSavePath);
17             Console.WriteLine(result);
18 
19             var imageInfo = ImageHelper.GetImageInfo(qrcodeLogoPath);
20             Console.WriteLine($"WIDTH={imageInfo.Item1}&HEIGHT={imageInfo.Item2}&LENGTH={imageInfo.Item3}&FORMAT={imageInfo.Item4}");
21         }
View Code

程序运行结果:

图片处理结果:

 

最后的图片质量还是挺好的,如果你也有在 .net core 下的图片处理需求,可以试试这个处理方式!

 

以后会陆续将自己写的一些小东西发出来和大家一起分享,多半都是一些零零碎碎的东西,目的在于解决实实在在的具体的问题,希望对各位来过的朋友有所帮助!

 

posted on 2018-12-18 23:38  如兹  阅读(8238)  评论(11编辑  收藏  举报