You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

154 lines
4.6 KiB

  1. package com.sothr.imagetools
  2. import grizzled.slf4j.Logging
  3. import java.awt.image.{DataBufferByte, BufferedImage, ColorConvertOp}
  4. import net.coobird.thumbnailator.Thumbnails
  5. import java.io.File
  6. import com.sothr.imagetools.image.Image
  7. import com.sothr.imagetools.hash.HashService
  8. import javax.imageio.ImageIO
  9. import java.io.IOException
  10. object ImageService extends Logging {
  11. def getImage(file:File):Image = {
  12. try {
  13. val thumbnailPath = getThumbnailPath(file)
  14. val bufferedImage = ImageIO.read(file)
  15. val hashes = HashService.getImageHashes(bufferedImage, file.getAbsolutePath)
  16. val imageSize = { (bufferedImage.getWidth, bufferedImage.getHeight) }
  17. val image = new Image(file.getAbsolutePath, thumbnailPath, imageSize, hashes)
  18. debug(s"Created image: $image")
  19. return image
  20. } catch {
  21. case ioe:IOException => error(s"Error processing ${file.getAbsolutePath}", ioe)
  22. case ex:Exception => error(s"Error processing ${file.getAbsolutePath}", ex)
  23. }
  24. null
  25. }
  26. def getThumbnailPath(file:File):String = {
  27. "."
  28. }
  29. /**
  30. * Get the raw data for an image
  31. */
  32. def getImageData(image:BufferedImage):Array[Array[Int]] = {
  33. return convertTo2DWithoutUsingGetRGB(image)
  34. }
  35. /**
  36. * Quickly convert an image to grayscale
  37. *
  38. * @param image
  39. * @return
  40. */
  41. def convertToGray(image:BufferedImage):BufferedImage = {
  42. debug("Converting an image to grayscale")
  43. val grayImage = new BufferedImage(image.getWidth, image.getHeight, BufferedImage.TYPE_BYTE_GRAY)
  44. //create a color conversion operation
  45. val op = new ColorConvertOp(
  46. image.getColorModel.getColorSpace,
  47. grayImage.getColorModel.getColorSpace, null)
  48. //convert the image to grey
  49. val result = op.filter(image, grayImage)
  50. //val g = image.getGraphics
  51. //g.drawImage(image,0,0,null)
  52. //g.dispose()
  53. result
  54. }
  55. def resize(image:BufferedImage, size:Int, forced:Boolean=false):BufferedImage = {
  56. debug(s"Resizing an image to size: ${size}x${size} forced: $forced")
  57. if (forced) {
  58. Thumbnails.of(image).forceSize(size,size).asBufferedImage
  59. } else {
  60. Thumbnails.of(image).size(size,size).asBufferedImage
  61. }
  62. }
  63. /**
  64. * Convert a buffered image into a 2d pixel data array
  65. *
  66. * @param image
  67. * @return
  68. */
  69. private def convertTo2DWithoutUsingGetRGB(image:BufferedImage):Array[Array[Int]] = {
  70. val pixels = image.getRaster.getDataBuffer.asInstanceOf[DataBufferByte].getData
  71. val numPixels = pixels.length
  72. val width = image.getWidth
  73. val height = image.getHeight
  74. val isSingleChannel = if(numPixels == (width * height)) true else false
  75. val hasAlphaChannel = image.getAlphaRaster != null
  76. debug(s"Converting image to 2d. width:$width height:$height")
  77. val result = Array.ofDim[Int](height,width)
  78. if (isSingleChannel) {
  79. debug(s"Processing Single Channel Image")
  80. val pixelLength = 1
  81. var row = 0
  82. var col = 0
  83. debug(s"Processing pixels 0 until $numPixels by $pixelLength")
  84. for (pixel <- 0 until numPixels by pixelLength) {
  85. //debug(s"Processing pixel: $pixel/${numPixels - 1}")
  86. val argb:Int = pixels(pixel).toInt //singleChannel
  87. //debug(s"Pixel data: $argb")
  88. result(row)(col) = argb
  89. col += 1
  90. if (col == width) {
  91. col = 0
  92. row += 1
  93. }
  94. }
  95. }
  96. else if (hasAlphaChannel) {
  97. debug(s"Processing Four Channel Image")
  98. val pixelLength = 4
  99. var row = 0
  100. var col = 0
  101. debug(s"Processing pixels 0 until $numPixels by $pixelLength")
  102. for (pixel <- 0 until numPixels by pixelLength) {
  103. //debug(s"Processing pixel: $pixel/${numPixels - 1}")
  104. var argb:Int = 0
  105. argb += pixels(pixel).toInt << 24 //alpha
  106. argb += pixels(pixel + 1).toInt //blue
  107. argb += pixels(pixel + 2).toInt << 8 //green
  108. argb += pixels(pixel + 3).toInt << 16 //red
  109. result(row)(col) = argb
  110. col += 1
  111. if (col == width) {
  112. col = 0
  113. row += 1
  114. }
  115. }
  116. } else {
  117. debug(s"Processing Three Channel Image")
  118. val pixelLength = 3
  119. var row = 0
  120. var col = 0
  121. debug(s"Processing pixels 0 until $numPixels by $pixelLength")
  122. for (pixel <- 0 until numPixels by pixelLength) {
  123. //debug(s"Processing pixel: $pixel/${numPixels - 1}")
  124. var argb:Int = 0
  125. argb += -16777216; // 255 alpha
  126. argb += pixels(pixel).toInt //blue
  127. argb += pixels(pixel + 1).toInt << 8 //green
  128. argb += pixels(pixel + 2).toInt << 16 //red
  129. result(row)(col) = argb
  130. col += 1
  131. if (col == width) {
  132. col = 0
  133. row += 1
  134. }
  135. }
  136. }
  137. result
  138. }
  139. }