BitmapUtils.uts 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734
  1. // nativeplugins/opencv/android/uts/BitmapUtils.uts
  2. import Bitmap from 'android.graphics.Bitmap'
  3. import Base64 from 'android.util.Base64'
  4. import BitmapFactory from 'android.graphics.BitmapFactory'
  5. // 定义类型接口
  6. type ImageClarityScore = {
  7. score: number
  8. level: string
  9. }
  10. type ImageClarityResult = {
  11. score: number
  12. level: string
  13. isClear: boolean
  14. }
  15. /**
  16. * 图像清晰度检测工具类
  17. */
  18. export class BitmapUtils {
  19. /**
  20. * 计算图像的亮度方差作为清晰度指标
  21. */
  22. static calculateBrightnessVariance(bitmap: Bitmap): number {
  23. try {
  24. const width = bitmap.getWidth()
  25. const height = bitmap.getHeight()
  26. // 根据原始尺寸动态计算采样尺寸
  27. // 目标采样区域的总像素数,控制在合理范围内
  28. const targetPixelCount = 2500 // 50x50 = 2500像素
  29. // 计算合适的采样尺寸,保持宽高比
  30. let sampleWidth: number
  31. let sampleHeight: number
  32. if (width > height) {
  33. // 宽图
  34. sampleWidth = Math.min(width, Math.sqrt(targetPixelCount * width / height).toInt())
  35. sampleHeight = Math.min(height, (sampleWidth * height / width).toInt())
  36. } else {
  37. // 高图或方图
  38. sampleHeight = Math.min(height, Math.sqrt(targetPixelCount * height / width).toInt())
  39. sampleWidth = Math.min(width, (sampleHeight * width / height).toInt())
  40. }
  41. // 确保最小尺寸
  42. sampleWidth = Math.max(sampleWidth, 32)
  43. sampleHeight = Math.max(sampleHeight, 32)
  44. const scaledBitmap = Bitmap.createScaledBitmap(
  45. bitmap,
  46. sampleWidth.toInt(),
  47. sampleHeight.toInt(),
  48. false
  49. )
  50. let totalBrightness = 0.0
  51. let brightnessSquares = 0.0
  52. const pixelCount = sampleWidth * sampleHeight
  53. // 计算平均亮度
  54. for (let i: number = 0; i < sampleWidth; i++) {
  55. for (let j: number = 0; j < sampleHeight; j++) {
  56. const pixel = scaledBitmap.getPixel(i.toInt(), j.toInt())
  57. const brightness = this.getPixelBrightness(pixel)
  58. totalBrightness += brightness
  59. }
  60. }
  61. const meanBrightness = totalBrightness / pixelCount
  62. // 计算亮度方差
  63. for (let i: number = 0; i < sampleWidth; i++) {
  64. for (let j: number = 0; j < sampleHeight; j++) {
  65. const pixel = scaledBitmap.getPixel(i.toInt(), j.toInt())
  66. const brightness = this.getPixelBrightness(pixel)
  67. const diff = brightness - meanBrightness
  68. brightnessSquares += diff * diff
  69. }
  70. }
  71. const variance = brightnessSquares / pixelCount
  72. // 回收临时Bitmap
  73. if (!scaledBitmap.isRecycled()) {
  74. scaledBitmap.recycle()
  75. }
  76. return variance
  77. } catch (error) {
  78. console.error('清晰度计算失败:', error)
  79. return -1
  80. }
  81. }
  82. // 在calculateBrightnessVariance方法中使用多尺度采样
  83. static calculateBrightnessVariance2(bitmap: Bitmap): number {
  84. try {
  85. const width = bitmap.getWidth()
  86. const height = bitmap.getHeight()
  87. // 对2048×1536的图片,使用多个采样尺度
  88. const scales = [
  89. { width: 200, height: 150 }, // 约10%尺度
  90. { width: 100, height: 75 }, // 约5%尺度
  91. { width: 50, height: 38 } // 约2.5%尺度
  92. ]
  93. let totalVariance = 0.0
  94. let scaleCount = 0
  95. for (const scale of scales) {
  96. const sampleWidth = Math.min(width, scale.width as number)
  97. const sampleHeight = Math.min(height, scale.height as number)
  98. if (sampleWidth < 32 || sampleHeight < 32) continue
  99. const scaledBitmap = Bitmap.createScaledBitmap(
  100. bitmap,
  101. sampleWidth.toInt(),
  102. sampleHeight.toInt(),
  103. false
  104. )
  105. const variance = this.calculateVarianceForBitmap(scaledBitmap)
  106. totalVariance += variance
  107. scaleCount++
  108. if (!scaledBitmap.isRecycled()) {
  109. scaledBitmap.recycle()
  110. }
  111. }
  112. return scaleCount > 0 ? totalVariance / scaleCount : -1
  113. } catch (error) {
  114. console.error('多尺度清晰度计算失败:', error)
  115. return -1
  116. }
  117. }
  118. // 提取方差计算为独立方法
  119. private static calculateVarianceForBitmap(bitmap: Bitmap): number {
  120. const width = bitmap.getWidth()
  121. const height = bitmap.getHeight()
  122. let totalBrightness = 0.0
  123. let brightnessSquares = 0.0
  124. const pixelCount = width * height
  125. // 计算平均亮度
  126. for (let i: number = 0; i < width; i++) {
  127. for (let j: number = 0; j < height; j++) {
  128. const pixel = bitmap.getPixel(i.toInt(), j.toInt())
  129. const brightness = this.getPixelBrightness(pixel)
  130. totalBrightness += brightness
  131. }
  132. }
  133. const meanBrightness = totalBrightness / pixelCount
  134. // 计算亮度方差
  135. for (let i: number = 0; i < width; i++) {
  136. for (let j: number = 0; j < height; j++) {
  137. const pixel = bitmap.getPixel(i.toInt(), j.toInt())
  138. const brightness = this.getPixelBrightness(pixel)
  139. const diff = brightness - meanBrightness
  140. brightnessSquares += diff * diff
  141. }
  142. }
  143. return brightnessSquares / pixelCount
  144. }
  145. /**
  146. * 基于边缘梯度的清晰度检测(对模糊更敏感)
  147. */
  148. static calculateEdgeGradientClarity(bitmap: Bitmap): number {
  149. try {
  150. const width = bitmap.getWidth()
  151. const height = bitmap.getHeight()
  152. // 取中心区域
  153. const centerRatio = 0.7
  154. const centerWidth = (width * centerRatio).toInt()
  155. const centerHeight = (height * centerRatio).toInt()
  156. const startX = ((width - centerWidth) / 2).toInt()
  157. const startY = ((height - centerHeight) / 2).toInt()
  158. const centerBitmap = Bitmap.createBitmap(
  159. bitmap,
  160. startX,
  161. startY,
  162. centerWidth,
  163. centerHeight
  164. )
  165. if (centerBitmap == null) {
  166. return -1
  167. }
  168. // 缩放以提高性能
  169. const sampleWidth = Math.min(centerWidth, 300)
  170. const sampleHeight = Math.min(centerHeight, (300 * centerHeight / centerWidth).toInt())
  171. const scaledBitmap = Bitmap.createScaledBitmap(
  172. centerBitmap,
  173. sampleWidth.toInt(),
  174. sampleHeight.toInt(),
  175. false
  176. )
  177. let totalGradient = 0.0
  178. let gradientCount = 0
  179. // 计算梯度(边缘强度)
  180. for (let i: number = 1; i < sampleWidth - 1; i++) {
  181. for (let j: number = 1; j < sampleHeight - 1; j++) {
  182. const iInt = i.toInt()
  183. const jInt = j.toInt()
  184. // 获取3x3区域的像素
  185. const p00 = this.getPixelBrightness(scaledBitmap.getPixel(iInt - 1, jInt - 1))
  186. const p01 = this.getPixelBrightness(scaledBitmap.getPixel(iInt, jInt - 1))
  187. const p02 = this.getPixelBrightness(scaledBitmap.getPixel(iInt + 1, jInt - 1))
  188. const p10 = this.getPixelBrightness(scaledBitmap.getPixel(iInt - 1, jInt))
  189. const p12 = this.getPixelBrightness(scaledBitmap.getPixel(iInt + 1, jInt))
  190. const p20 = this.getPixelBrightness(scaledBitmap.getPixel(iInt - 1, jInt + 1))
  191. const p21 = this.getPixelBrightness(scaledBitmap.getPixel(iInt, jInt + 1))
  192. const p22 = this.getPixelBrightness(scaledBitmap.getPixel(iInt + 1, jInt + 1))
  193. // 计算Sobel梯度
  194. const gx = (p02 + 2 * p12 + p22) - (p00 + 2 * p10 + p20)
  195. const gy = (p20 + 2 * p21 + p22) - (p00 + 2 * p01 + p02)
  196. const gradient = Math.sqrt(gx * gx + gy * gy)
  197. // 只考虑明显的边缘(避免噪声)
  198. if (gradient > 10) {
  199. totalGradient += gradient
  200. gradientCount++
  201. }
  202. }
  203. }
  204. const avgGradient = gradientCount > 0 ? totalGradient / gradientCount : 0
  205. // 回收Bitmap
  206. if (!scaledBitmap.isRecycled()) {
  207. scaledBitmap.recycle()
  208. }
  209. if (!centerBitmap.isRecycled()) {
  210. centerBitmap.recycle()
  211. }
  212. return avgGradient
  213. } catch (error) {
  214. console.error('边缘梯度清晰度计算失败:', error)
  215. return -1
  216. }
  217. }
  218. /**
  219. * 快速拉普拉斯方差 - 对模糊敏感且计算效率高
  220. */
  221. static calculateLaplacianVariance(bitmap: Bitmap): number {
  222. try {
  223. const width = bitmap.getWidth()
  224. const height = bitmap.getHeight()
  225. // 取中心区域,但使用更小的采样
  226. const centerRatio = 0.6
  227. const centerWidth = (width * centerRatio).toInt()
  228. const centerHeight = (height * centerRatio).toInt()
  229. const startX = ((width - centerWidth) / 2).toInt()
  230. const startY = ((height - centerHeight) / 2).toInt()
  231. const centerBitmap = Bitmap.createBitmap(
  232. bitmap,
  233. startX,
  234. startY,
  235. centerWidth,
  236. centerHeight
  237. )
  238. if (centerBitmap == null) {
  239. return -1
  240. }
  241. // 使用较小的采样尺寸
  242. const sampleWidth = Math.min(centerWidth, 150)
  243. const sampleHeight = Math.min(centerHeight, 100)
  244. const scaledBitmap = Bitmap.createScaledBitmap(
  245. centerBitmap,
  246. sampleWidth.toInt(),
  247. sampleHeight.toInt(),
  248. false
  249. )
  250. let laplacianSum = 0.0
  251. let pixelCount = 0
  252. // 简化的拉普拉斯算子 - 只计算中心与四邻域的差异
  253. for (let i: number = 1; i < sampleWidth - 1; i++) {
  254. for (let j: number = 1; j < sampleHeight - 1; j++) {
  255. const iInt = i.toInt()
  256. const jInt = j.toInt()
  257. const center = this.getPixelBrightness(scaledBitmap.getPixel(iInt, jInt))
  258. const left = this.getPixelBrightness(scaledBitmap.getPixel(iInt - 1, jInt))
  259. const right = this.getPixelBrightness(scaledBitmap.getPixel(iInt + 1, jInt))
  260. const top = this.getPixelBrightness(scaledBitmap.getPixel(iInt, jInt - 1))
  261. const bottom = this.getPixelBrightness(scaledBitmap.getPixel(iInt, jInt + 1))
  262. // 拉普拉斯值 = 4*中心 - 上下左右
  263. const laplacianValue = Math.abs(4 * center - left - right - top - bottom)
  264. if (laplacianValue > 5) { // 忽略微小变化
  265. laplacianSum += laplacianValue
  266. pixelCount++
  267. }
  268. }
  269. }
  270. const avgLaplacian = pixelCount > 0 ? laplacianSum / pixelCount : 0
  271. // 回收Bitmap
  272. if (!scaledBitmap.isRecycled()) {
  273. scaledBitmap.recycle()
  274. }
  275. if (!centerBitmap.isRecycled()) {
  276. centerBitmap.recycle()
  277. }
  278. return avgLaplacian
  279. } catch (error) {
  280. console.error('拉普拉斯方差计算失败:', error)
  281. return -1
  282. }
  283. }
  284. /**
  285. * 快速局部对比度检测 - 优化性能
  286. */
  287. static calculateFastLocalContrast(bitmap: Bitmap): number {
  288. try {
  289. const width = bitmap.getWidth()
  290. const height = bitmap.getHeight()
  291. // 直接使用缩放后的整个图像,不裁剪中心区域
  292. const sampleWidth = Math.min(width, 200)
  293. const sampleHeight = Math.min(height, 150)
  294. const scaledBitmap = Bitmap.createScaledBitmap(
  295. bitmap,
  296. sampleWidth.toInt(),
  297. sampleHeight.toInt(),
  298. false
  299. )
  300. let contrastSum = 0.0
  301. let sampleCount = 0
  302. // 使用步长采样,减少计算量
  303. const step = 2
  304. for (let i: number = 1; i < sampleWidth - 1; i += step) {
  305. for (let j: number = 1; j < sampleHeight - 1; j += step) {
  306. const iInt = i.toInt()
  307. const jInt = j.toInt()
  308. // 只检查水平和垂直方向的对比度
  309. const center = this.getPixelBrightness(scaledBitmap.getPixel(iInt, jInt))
  310. const left = this.getPixelBrightness(scaledBitmap.getPixel(iInt - 1, jInt))
  311. const right = this.getPixelBrightness(scaledBitmap.getPixel(iInt + 1, jInt))
  312. const top = this.getPixelBrightness(scaledBitmap.getPixel(iInt, jInt - 1))
  313. const bottom = this.getPixelBrightness(scaledBitmap.getPixel(iInt, jInt + 1))
  314. // 计算最大相邻对比度
  315. const horizontalContrast = Math.max(Math.abs(center - left), Math.abs(center - right))
  316. const verticalContrast = Math.max(Math.abs(center - top), Math.abs(center - bottom))
  317. const maxContrast = Math.max(horizontalContrast, verticalContrast)
  318. if (maxContrast > 15) { // 只考虑明显的对比度
  319. contrastSum += maxContrast
  320. sampleCount++
  321. }
  322. }
  323. }
  324. const avgContrast = sampleCount > 0 ? contrastSum / sampleCount : 0
  325. if (!scaledBitmap.isRecycled()) {
  326. scaledBitmap.recycle()
  327. }
  328. return avgContrast
  329. } catch (error) {
  330. console.error('快速局部对比度计算失败:', error)
  331. return -1
  332. }
  333. }
  334. /**
  335. * 自适应阈值清晰度检测
  336. * 根据图像内容动态调整判断标准
  337. */
  338. static calculateAdaptiveClarity(bitmap: Bitmap): number {
  339. try {
  340. const width = bitmap.getWidth()
  341. const height = bitmap.getHeight()
  342. // 使用小尺寸采样
  343. const sampleWidth = Math.min(width, 150)
  344. const sampleHeight = Math.min(height, 100)
  345. const scaledBitmap = Bitmap.createScaledBitmap(
  346. bitmap,
  347. sampleWidth.toInt(),
  348. sampleHeight.toInt(),
  349. false
  350. )
  351. // 第一步:分析图像的整体对比度特征
  352. let highContrastCount = 0
  353. let totalSamples = 0
  354. for (let i: number = 2; i < sampleWidth - 2; i += 2) {
  355. for (let j: number = 2; j < sampleHeight - 2; j += 2) {
  356. const iInt = i.toInt()
  357. const jInt = j.toInt()
  358. const center = this.getPixelBrightness(scaledBitmap.getPixel(iInt, jInt))
  359. const neighbors = [
  360. this.getPixelBrightness(scaledBitmap.getPixel(iInt - 1, jInt)),
  361. this.getPixelBrightness(scaledBitmap.getPixel(iInt + 1, jInt)),
  362. this.getPixelBrightness(scaledBitmap.getPixel(iInt, jInt - 1)),
  363. this.getPixelBrightness(scaledBitmap.getPixel(iInt, jInt + 1))
  364. ]
  365. // 检查是否有高对比度边缘
  366. for (const neighbor of neighbors) {
  367. if (Math.abs(center - neighbor) > 25) {
  368. highContrastCount++
  369. break
  370. }
  371. }
  372. totalSamples++
  373. }
  374. }
  375. const highContrastRatio = highContrastCount / totalSamples
  376. // 第二步:基于对比度特征调整清晰度评分
  377. let clarityScore: number
  378. if (highContrastRatio < 0.05) {
  379. // 低对比度图像 - 可能是模糊或单色
  380. clarityScore = highContrastRatio * 500
  381. } else if (highContrastRatio < 0.15) {
  382. // 中等对比度
  383. clarityScore = 25 + (highContrastRatio - 0.05) * 250
  384. } else {
  385. // 高对比度 - 可能是清晰图像
  386. clarityScore = 50 + (highContrastRatio - 0.15) * 200
  387. }
  388. if (!scaledBitmap.isRecycled()) {
  389. scaledBitmap.recycle()
  390. }
  391. return clarityScore
  392. } catch (error) {
  393. console.error('自适应清晰度计算失败:', error)
  394. return -1
  395. }
  396. }
  397. /**
  398. * 优化的快速清晰度检测方案
  399. * 平衡准确性和性能
  400. */
  401. static calculateOptimizedClarity(bitmap: Bitmap): number {
  402. try {
  403. // 使用两种快速方法,权重偏向对模糊更敏感的方法
  404. const laplacianScore = this.calculateAdaptiveClarity(bitmap)
  405. const contrastScore = this.calculateFastLocalContrast(bitmap)
  406. // 如果两种方法都返回有效结果,取加权平均
  407. if (laplacianScore > 0 && contrastScore > 0) {
  408. // 自适应阈值清晰度检测
  409. return laplacianScore * 0.3 + contrastScore * 0.7
  410. }
  411. // 如果只有一种方法有效,返回该结果
  412. return Math.max(laplacianScore, contrastScore)
  413. } catch (error) {
  414. console.error('优化清晰度计算失败:', error)
  415. return -1
  416. }
  417. }
  418. /**
  419. * 超快速清晰度检测(最低计算量)
  420. */
  421. static calculateUltraFastClarity(bitmap: Bitmap): number {
  422. try {
  423. const width = bitmap.getWidth()
  424. const height = bitmap.getHeight()
  425. // 极小的采样尺寸
  426. const sampleWidth = 80
  427. const sampleHeight = 60
  428. const scaledBitmap = Bitmap.createScaledBitmap(
  429. bitmap,
  430. sampleWidth.toInt(),
  431. sampleHeight.toInt(),
  432. false
  433. )
  434. let edgeStrength = 0.0
  435. let sampleCount = 0
  436. // 极简的边缘检测 - 只检查少数关键点
  437. const checkPoints = [
  438. { x: 20, y: 15 }, { x: 40, y: 15 }, { x: 60, y: 15 },
  439. { x: 20, y: 30 }, { x: 40, y: 30 }, { x: 60, y: 30 },
  440. { x: 20, y: 45 }, { x: 40, y: 45 }, { x: 60, y: 45 }
  441. ]
  442. for (const point of checkPoints) {
  443. const x = point.x as number
  444. const y = point.y as number
  445. if (x >= 1 && x < sampleWidth - 1 && y >= 1 && y < sampleHeight - 1) {
  446. const center = this.getPixelBrightness(scaledBitmap.getPixel(x.toInt(), y.toInt()))
  447. const right = this.getPixelBrightness(scaledBitmap.getPixel(x.toInt() + 1, y.toInt()))
  448. const bottom = this.getPixelBrightness(scaledBitmap.getPixel(x.toInt(), y.toInt() + 1))
  449. const edgeValue = Math.abs(center - right) + Math.abs(center - bottom)
  450. if (edgeValue > 10) {
  451. edgeStrength += edgeValue
  452. sampleCount++
  453. }
  454. }
  455. }
  456. const avgEdgeStrength = sampleCount > 0 ? edgeStrength / sampleCount : 0
  457. if (!scaledBitmap.isRecycled()) {
  458. scaledBitmap.recycle()
  459. }
  460. return avgEdgeStrength
  461. } catch (error) {
  462. console.error('超快速清晰度计算失败:', error)
  463. return -1
  464. }
  465. }
  466. /**
  467. * 获取像素亮度
  468. */
  469. private static getPixelBrightness(pixel: number): number {
  470. const r = (pixel >> 16) & 0xff
  471. const g = (pixel >> 8) & 0xff
  472. const b = pixel & 0xff
  473. return (r + g + b) / 3.0
  474. }
  475. /**
  476. * 判断图像是否清晰
  477. */
  478. static isImageClear(bitmap: Bitmap, threshold: number = 500): boolean {
  479. const variance = this.calculateOptimizedClarity(bitmap)
  480. return variance > threshold
  481. }
  482. /**
  483. * 获取图像清晰度评分
  484. */
  485. static getImageClarityScore(bitmap: Bitmap): ImageClarityScore {
  486. const variance = this.calculateOptimizedClarity(bitmap)
  487. let level: string
  488. if (variance < 0) {
  489. level = "处理失败"
  490. } else if (variance < 15) {
  491. level = "非常模糊"
  492. } else if (variance < 35) {
  493. level = "模糊"
  494. } else if (variance < 45) {
  495. level = "一般"
  496. } else if (variance < 60) {
  497. level = "清晰"
  498. } else {
  499. level = "非常清晰"
  500. }
  501. return {
  502. score: Math.round(variance * 100) / 100,
  503. level: level
  504. }
  505. }
  506. /**
  507. * 从Base64数据检测清晰度
  508. */
  509. static checkImageClarityFromBase64(base64Data: string): ImageClarityResult {
  510. try {
  511. const bitmap = this.base64ToBitmap(base64Data)
  512. if (bitmap == null) {
  513. return { score: -1, level: "加载失败", isClear: false }
  514. }
  515. const clarityInfo = this.getImageClarityScore(bitmap)
  516. const isClear = this.isImageClear(bitmap)
  517. if (!bitmap.isRecycled()) {
  518. bitmap.recycle()
  519. }
  520. return {
  521. score: clarityInfo.score,
  522. level: clarityInfo.level,
  523. isClear: isClear
  524. }
  525. } catch (error) {
  526. console.error('图像清晰度检测失败:', error)
  527. return { score: -1, level: "检测失败", isClear: false }
  528. }
  529. }
  530. /**
  531. * 从文件路径检测清晰度
  532. */
  533. static checkImageClarityFromPath(imagePath: string): ImageClarityResult {
  534. try {
  535. const bitmap = BitmapFactory.decodeFile(imagePath)
  536. if (bitmap == null) {
  537. return { score: -1, level: "加载失败", isClear: false }
  538. }
  539. const clarityInfo = this.getImageClarityScore(bitmap)
  540. const isClear = this.isImageClear(bitmap)
  541. if (!bitmap.isRecycled()) {
  542. bitmap.recycle()
  543. }
  544. return {
  545. score: clarityInfo.score,
  546. level: clarityInfo.level,
  547. isClear: isClear
  548. }
  549. } catch (error) {
  550. console.error('图像清晰度检测失败:', error)
  551. return { score: -1, level: "检测失败", isClear: false }
  552. }
  553. }
  554. /**
  555. * 简化的Base64转Bitmap方法
  556. */
  557. private static base64ToBitmap(base64Data: string): Bitmap | null {
  558. try {
  559. // 移除Base64前缀
  560. let pureBase64 = base64Data
  561. if (base64Data.includes(',')) {
  562. pureBase64 = base64Data.split(',')[1]
  563. }
  564. // 解码Base64
  565. const decodedBytes = Base64.decode(pureBase64, Base64.DEFAULT)
  566. // 获取字节数组长度
  567. const bitmap = BitmapFactory.decodeByteArray(decodedBytes, 0, decodedBytes.size)
  568. return bitmap
  569. } catch (error) {
  570. console.error('Base64转Bitmap失败:', error)
  571. return null
  572. }
  573. }
  574. /**
  575. * 备用方法:直接返回清晰度分数(避免复杂对象类型)
  576. */
  577. static getSimpleClarityScore(bitmap: Bitmap): number {
  578. return this.calculateBrightnessVariance(bitmap)
  579. }
  580. /**
  581. * 从Base64获取简单清晰度分数
  582. */
  583. static getSimpleClarityScoreFromBase64(base64Data: string): number {
  584. try {
  585. const bitmap = this.base64ToBitmap(base64Data)
  586. if (bitmap == null) {
  587. return -1
  588. }
  589. const score = this.calculateBrightnessVariance(bitmap)
  590. if (!bitmap.isRecycled()) {
  591. bitmap.recycle()
  592. }
  593. return score
  594. } catch (error) {
  595. console.error('清晰度检测失败:', error)
  596. return -1
  597. }
  598. }
  599. }