1. 程式人生 > >.net core 的圖片處理及二維碼的生成及解析

.net core 的圖片處理及二維碼的生成及解析

寫程式碼這事,掐指算來已經十有餘年。

 

從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.p