diff --git a/images/src/org/intellij/images/scientific/ScientificUtils.kt b/images/src/org/intellij/images/scientific/ScientificUtils.kt index 6657d9f51513..b574ef1f002e 100644 --- a/images/src/org/intellij/images/scientific/ScientificUtils.kt +++ b/images/src/org/intellij/images/scientific/ScientificUtils.kt @@ -2,7 +2,17 @@ package org.intellij.images.scientific import com.intellij.openapi.util.Key +import java.awt.image.BufferedImage +import java.io.ByteArrayOutputStream +import javax.imageio.ImageIO object ScientificUtils { val SCIENTIFIC_MODE_KEY: Key = Key("SCIENTIFIC_MODE") + val ORIGINAL_IMAGE_KEY: Key = Key("ORIGINAL_IMAGE") +} + +internal fun convertToByteArray(image: BufferedImage, imageType: String): ByteArray { + val outputStream = ByteArrayOutputStream() + ImageIO.write(image, imageType, outputStream) + return outputStream.toByteArray() } \ No newline at end of file diff --git a/images/src/org/intellij/images/scientific/action/GrayscaleAction.kt b/images/src/org/intellij/images/scientific/action/GrayscaleAction.kt deleted file mode 100644 index a2c974f34175..000000000000 --- a/images/src/org/intellij/images/scientific/action/GrayscaleAction.kt +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. -package org.intellij.images.scientific.action - -import com.intellij.openapi.actionSystem.ActionUpdateThread -import com.intellij.openapi.actionSystem.AnActionEvent -import com.intellij.openapi.actionSystem.CommonDataKeys -import com.intellij.openapi.project.DumbAwareAction -import org.intellij.images.editor.ImageEditor -import org.intellij.images.scientific.ScientificUtils -import org.intellij.images.ui.ImageComponent -import java.awt.Color -import java.awt.image.BufferedImage - -class GrayscaleAction : DumbAwareAction() { - - override fun getActionUpdateThread(): ActionUpdateThread = ActionUpdateThread.BGT - - override fun update(e: AnActionEvent) { - val imageFile = e.getData(CommonDataKeys.VIRTUAL_FILE) - e.presentation.isEnabledAndVisible = imageFile?.getUserData(ScientificUtils.SCIENTIFIC_MODE_KEY) != null - } - - override fun actionPerformed(e: AnActionEvent) { - - val imageEditor = getImageEditor(e) ?: return - val imageComponent = getImageComponent(imageEditor) ?: return - val document = imageComponent.document - val originalImage = document.value ?: return - val grayscaleImage = applyGrayscale(originalImage) - document.setValue(grayscaleImage) // TODO: how to view result without changing original image? - } - - private fun getImageEditor(e: AnActionEvent): ImageEditor? { - return null - } - - private fun getImageComponent(imageEditor: ImageEditor): ImageComponent? { - return null - } - - // TODO: maybe redo logic, its just a stub! - private fun applyGrayscale(image: BufferedImage): BufferedImage { - val grayscaleImage = BufferedImage(image.width, image.height, BufferedImage.TYPE_INT_RGB) - for (x in 0 until image.width) { - for (y in 0 until image.height) { - val pixel = Color(image.getRGB(x, y)) - val gray = (pixel.red * 0.299 + pixel.green * 0.587 + pixel.blue * 0.114).toInt() - val grayColor = Color(gray, gray, gray) - grayscaleImage.setRGB(x, y, grayColor.rgb) - } - } - return grayscaleImage - } -} \ No newline at end of file diff --git a/images/src/org/intellij/images/scientific/action/GrayscaleImageAction.kt b/images/src/org/intellij/images/scientific/action/GrayscaleImageAction.kt new file mode 100644 index 000000000000..25135cb4342e --- /dev/null +++ b/images/src/org/intellij/images/scientific/action/GrayscaleImageAction.kt @@ -0,0 +1,36 @@ +package org.intellij.images.scientific.action + +import com.intellij.openapi.actionSystem.ActionUpdateThread +import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.actionSystem.CommonDataKeys +import com.intellij.openapi.project.DumbAwareAction +import org.intellij.images.scientific.ScientificUtils +import org.intellij.images.scientific.ScientificUtils.ORIGINAL_IMAGE_KEY +import org.intellij.images.scientific.convertToByteArray +import java.awt.image.BufferedImage + +class GrayscaleImageAction : DumbAwareAction() { + override fun getActionUpdateThread(): ActionUpdateThread = ActionUpdateThread.BGT + + override fun update(e: AnActionEvent) { + val imageFile = e.getData(CommonDataKeys.VIRTUAL_FILE) + e.presentation.isEnabledAndVisible = imageFile?.getUserData(ScientificUtils.SCIENTIFIC_MODE_KEY) != null + } + + override fun actionPerformed(e: AnActionEvent) { + val imageFile = e.getData(CommonDataKeys.VIRTUAL_FILE) ?: return + val originalImage = imageFile.getUserData(ORIGINAL_IMAGE_KEY) ?: return + val grayscaleImage = applyGrayscale(originalImage) + imageFile.setBinaryContent(convertToByteArray(grayscaleImage, imageFile.fileType.defaultExtension)) + } + + private fun applyGrayscale(image: BufferedImage): BufferedImage { + val grayscaleImage = BufferedImage(image.width, image.height, BufferedImage.TYPE_BYTE_GRAY) + + val graphics = grayscaleImage.createGraphics() + graphics.drawImage(image, 0, 0, null) + graphics.dispose() + + return grayscaleImage + } +} \ No newline at end of file diff --git a/images/src/org/intellij/images/scientific/action/ImageOperationsActionGroup.kt b/images/src/org/intellij/images/scientific/action/ImageOperationsActionGroup.kt index 21e4d44be0b4..160d09f299c5 100644 --- a/images/src/org/intellij/images/scientific/action/ImageOperationsActionGroup.kt +++ b/images/src/org/intellij/images/scientific/action/ImageOperationsActionGroup.kt @@ -13,7 +13,6 @@ import javax.swing.JComponent import javax.swing.JPanel class ImageOperationsActionGroup : DefaultActionGroup(), CustomComponentAction, DumbAware { - private var selectedMode: String = ORIGINAL_IMAGE private val availableModes = listOf(ORIGINAL_IMAGE, INVERTED_IMAGE, GRAYSCALE_IMAGE) @@ -61,18 +60,18 @@ class ImageOperationsActionGroup : DefaultActionGroup(), CustomComponentAction, private fun createPopupActionGroup(): DefaultActionGroup { val actionGroup = DefaultActionGroup() - actionGroup.add(RGBAction()) - actionGroup.add(BGRAction()) - actionGroup.add(GrayscaleAction()) + actionGroup.add(RestoreOriginalImageAction()) + actionGroup.add(InvertChannelsAction()) + actionGroup.add(GrayscaleImageAction()) return actionGroup } private fun triggerModeAction(mode: String) { val actionManager = ActionManager.getInstance() when (mode) { - ORIGINAL_IMAGE -> actionManager.tryToExecute(RGBAction(), null, null, null, true) - INVERTED_IMAGE -> actionManager.tryToExecute(BGRAction(), null, null, null, true) - GRAYSCALE_IMAGE -> actionManager.tryToExecute(GrayscaleAction(), null, null, null, true) + ORIGINAL_IMAGE -> actionManager.tryToExecute(RestoreOriginalImageAction(), null, null, null, true) + INVERTED_IMAGE -> actionManager.tryToExecute(InvertChannelsAction(), null, null, null, true) + GRAYSCALE_IMAGE -> actionManager.tryToExecute(GrayscaleImageAction(), null, null, null, true) } } diff --git a/images/src/org/intellij/images/scientific/action/BGRAction.kt b/images/src/org/intellij/images/scientific/action/InvertChannelsAction.kt similarity index 67% rename from images/src/org/intellij/images/scientific/action/BGRAction.kt rename to images/src/org/intellij/images/scientific/action/InvertChannelsAction.kt index feb1967a9f2d..f582db2a341e 100644 --- a/images/src/org/intellij/images/scientific/action/BGRAction.kt +++ b/images/src/org/intellij/images/scientific/action/InvertChannelsAction.kt @@ -5,13 +5,14 @@ import com.intellij.openapi.actionSystem.ActionUpdateThread import com.intellij.openapi.actionSystem.AnActionEvent import com.intellij.openapi.actionSystem.CommonDataKeys import com.intellij.openapi.project.DumbAwareAction -import org.intellij.images.editor.ImageEditor import org.intellij.images.scientific.ScientificUtils -import org.intellij.images.ui.ImageComponent +import org.intellij.images.scientific.ScientificUtils.ORIGINAL_IMAGE_KEY +import org.intellij.images.scientific.convertToByteArray import java.awt.image.BufferedImage +import java.io.ByteArrayOutputStream +import javax.imageio.ImageIO -class BGRAction : DumbAwareAction() { - +class InvertChannelsAction : DumbAwareAction() { override fun getActionUpdateThread(): ActionUpdateThread = ActionUpdateThread.BGT override fun update(e: AnActionEvent) { @@ -20,14 +21,13 @@ class BGRAction : DumbAwareAction() { } override fun actionPerformed(e: AnActionEvent) { - val imageEditor = getImageEditor(e) ?: return - val imageComponent = getImageComponent(imageEditor) ?: return - val document = imageComponent.document - val originalImage = document.value ?: return - val bgrImage = applyInvertChannels(originalImage) - document.setValue(bgrImage) // TODO: how to view result without changing original image? + val imageFile = e.getData(CommonDataKeys.VIRTUAL_FILE) ?: return + val originalImage = imageFile.getUserData(ORIGINAL_IMAGE_KEY) ?: return + val invertedImage = applyInvertChannels(originalImage) + imageFile.setBinaryContent(convertToByteArray(invertedImage, imageFile.fileType.defaultExtension)) } + private fun applyInvertChannels(image: BufferedImage): BufferedImage { val invertedImage = BufferedImage(image.width, image.height, image.type) for (x in 0 until image.width) { @@ -42,12 +42,4 @@ class BGRAction : DumbAwareAction() { } return invertedImage } - - private fun getImageEditor(e: AnActionEvent): ImageEditor? { - return null - } - - private fun getImageComponent(imageEditor: ImageEditor): ImageComponent? { - return null - } } \ No newline at end of file diff --git a/images/src/org/intellij/images/scientific/action/RGBAction.kt b/images/src/org/intellij/images/scientific/action/RestoreOriginalImageAction.kt similarity index 57% rename from images/src/org/intellij/images/scientific/action/RGBAction.kt rename to images/src/org/intellij/images/scientific/action/RestoreOriginalImageAction.kt index cbc734d0fa96..b1f3c33dc643 100644 --- a/images/src/org/intellij/images/scientific/action/RGBAction.kt +++ b/images/src/org/intellij/images/scientific/action/RestoreOriginalImageAction.kt @@ -5,12 +5,14 @@ import com.intellij.openapi.actionSystem.ActionUpdateThread import com.intellij.openapi.actionSystem.AnActionEvent import com.intellij.openapi.actionSystem.CommonDataKeys import com.intellij.openapi.project.DumbAwareAction -import org.intellij.images.editor.ImageEditor import org.intellij.images.scientific.ScientificUtils -import org.intellij.images.ui.ImageComponent - -class RGBAction : DumbAwareAction() { +import org.intellij.images.scientific.ScientificUtils.ORIGINAL_IMAGE_KEY +import org.intellij.images.scientific.convertToByteArray +import java.awt.image.BufferedImage +import java.io.ByteArrayOutputStream +import javax.imageio.ImageIO +class RestoreOriginalImageAction : DumbAwareAction() { override fun getActionUpdateThread(): ActionUpdateThread = ActionUpdateThread.BGT override fun update(e: AnActionEvent) { @@ -19,18 +21,8 @@ class RGBAction : DumbAwareAction() { } override fun actionPerformed(e: AnActionEvent) { - val imageEditor = getImageEditor(e) ?: return - val imageComponent = getImageComponent(imageEditor) ?: return - val document = imageComponent.document - val originalImage = document.value ?: return - document.setValue(originalImage) // TODO: restore original image! - } - - private fun getImageEditor(e: AnActionEvent): ImageEditor? { - return null - } - - private fun getImageComponent(imageEditor: ImageEditor): ImageComponent? { - return null + val imageFile = e.getData(CommonDataKeys.VIRTUAL_FILE) ?: return + val originalImage = imageFile.getUserData(ORIGINAL_IMAGE_KEY) ?: return + imageFile.setBinaryContent(convertToByteArray(originalImage, imageFile.fileType.defaultExtension)) } } \ No newline at end of file