diff --git a/src/main/scala/net/kogics/kojo/core/Picture.scala b/src/main/scala/net/kogics/kojo/core/Picture.scala index 1a66ad00..829b8e3c 100644 --- a/src/main/scala/net/kogics/kojo/core/Picture.scala +++ b/src/main/scala/net/kogics/kojo/core/Picture.scala @@ -218,5 +218,6 @@ trait Picture extends InputAware { def withZIndex(idx: Int): Picture def withClipping(clipShape: Shape): Picture def withClipping(clipPic: Picture): Picture + def withMask(maskPic: Picture): Picture def withPenCapJoin(capJoin: (Int, Int)): Picture } diff --git a/src/main/scala/net/kogics/kojo/lite/Versions.scala b/src/main/scala/net/kogics/kojo/lite/Versions.scala index 10b2c4e3..2f478abf 100644 --- a/src/main/scala/net/kogics/kojo/lite/Versions.scala +++ b/src/main/scala/net/kogics/kojo/lite/Versions.scala @@ -3,8 +3,8 @@ package net.kogics.kojo.lite object Versions { val KojoMajorVersion = "2.9" val KojoVersion = "2.9.26" - val KojoRevision = "r4" - val KojoBuildDate = "17 August 2023" + val KojoRevision = "r5" + val KojoBuildDate = "18 August 2023" val JavaVersion = { val jrv = System.getProperty("java.runtime.version") val arch = System.getProperty("os.arch") diff --git a/src/main/scala/net/kogics/kojo/picture/package.scala b/src/main/scala/net/kogics/kojo/picture/package.scala index fcdf02da..ceb95b66 100644 --- a/src/main/scala/net/kogics/kojo/picture/package.scala +++ b/src/main/scala/net/kogics/kojo/picture/package.scala @@ -16,7 +16,9 @@ package net.kogics.kojo import java.awt.event.KeyEvent import java.awt.geom.GeneralPath +import java.awt.image.BufferedImage import java.awt.image.BufferedImageOp +import java.awt.image.DataBufferInt import java.awt.Color import java.awt.Font import java.awt.Image @@ -30,6 +32,7 @@ import scala.swing.Graphics2D import com.jhlabs.image.LightFilter import com.jhlabs.image.LightFilter.Light +import com.jhlabs.image.PointFilter import com.vividsolutions.jts.geom.Coordinate import com.vividsolutions.jts.geom.GeometryFactory import com.vividsolutions.jts.geom.PrecisionModel @@ -484,7 +487,7 @@ package object picture { } def toShape(p: Picture): Shape = { - p.invisible(); p.draw() + p.draw() val coords = p.picGeom.getCoordinates p.erase() if (coords.length > 0) { @@ -499,4 +502,48 @@ package object picture { throw new RuntimeException("Unable to convert picture to shape") } } + + class MaskOp(maskPic: Picture) extends PointFilter { +// var maskImg: BufferedImage = _ + var maskPixels: Array[Int] = _ + var maskWidth: Int = 0 + var maskHeight: Int = 0 + + def initMaskImg(): Unit = { + maskPic.draw() + val maskImg = maskPic.toImage + maskPic.erase() + maskWidth = maskImg.getWidth; maskHeight = maskImg.getHeight +// maskPixels = new Array[Int](maskWidth * maskHeight) +// maskImg.getRaster.getDataElements(0, 0, maskWidth, maskHeight, maskPixels) + maskPixels = maskImg.getRaster.getDataBuffer.asInstanceOf[DataBufferInt].getData + } + + def checkSizes(src: BufferedImage): Unit = { + require( + src.getWidth <= maskWidth && src.getHeight <= maskHeight, + "The mask cannot be smaller than the masked pic" + ) + } + + override def filter(src: BufferedImage, dest: BufferedImage): BufferedImage = { + initMaskImg() + checkSizes(src) + super.filter(src, dest) + } + + def filterRGB(x: Int, y: Int, pixel: Int): Int = { + val red = (pixel >> 16) & 0xff + val green = (pixel >> 8) & 0xff + val blue = pixel & 0xff + + val maskPixel = maskPixels(x + y * maskWidth) // maskImg.getRGB(x, y) + val mred = (maskPixel >> 16) & 0xff + val mgreen = (maskPixel >> 8) & 0xff + val mblue = maskPixel & 0xff + val mgray = (mred + mgreen + mblue) / 3 + val outPixel = mgray << 24 | red << 16 | green << 8 | blue + outPixel + } + } } diff --git a/src/main/scala/net/kogics/kojo/picture/pics.scala b/src/main/scala/net/kogics/kojo/picture/pics.scala index 11b09668..697af51a 100644 --- a/src/main/scala/net/kogics/kojo/picture/pics.scala +++ b/src/main/scala/net/kogics/kojo/picture/pics.scala @@ -462,6 +462,7 @@ trait CorePicOps2 extends GeomPolygon { self: Picture => def withZIndex(zIndex: Int): Picture = PostDrawTransform { pic => pic.setZIndex(zIndex) }(this) def withClipping(clipShape: Shape): Picture = new ClipPic(this, clipShape)(canvas) def withClipping(clipPic: Picture): Picture = new ClipPicWithPic(this, clipPic)(canvas) + def withMask(maskPic: Picture): Picture = this.withEffect(new MaskOp(maskPic)) def withPenCapJoin(capJoin: (Int, Int)): Picture = PostDrawTransform { pic => pic.setPenCapJoin(capJoin) }(this) }