mirror of
https://gitflic.ru/project/openide/openide.git
synced 2025-12-15 02:59:33 +07:00
[pycharm] PY-79113 PY-79603 PY-79243 Debugger: add coroutines + tiny refactoring
(cherry picked from commit 36fa13fea7007e57c19d2b267431eb685fd384cc) GitOrigin-RevId: ff4385a857b8e279b99c8a034b6fb7a67488394e
This commit is contained in:
committed by
intellij-monorepo-bot
parent
b15df32e19
commit
d889654caf
@@ -47,5 +47,6 @@
|
||||
<orderEntry type="module" module-name="intellij.platform.ui.jcef" />
|
||||
<orderEntry type="library" name="kotlin-stdlib" level="project" />
|
||||
<orderEntry type="module" module-name="intellij.platform.statistics" />
|
||||
<orderEntry type="module" module-name="intellij.platform.util.coroutines" />
|
||||
</component>
|
||||
</module>
|
||||
@@ -24,7 +24,7 @@
|
||||
serviceImplementation="org.intellij.images.fileTypes.impl.ImageFileTypeManagerImpl"/>
|
||||
<applicationService serviceInterface="org.intellij.images.options.OptionsManager"
|
||||
serviceImplementation="org.intellij.images.options.impl.OptionsManagerImpl"/>
|
||||
<applicationService serviceImplementation="org.intellij.images.scientific.BinarizationThresholdConfig"/>
|
||||
<applicationService serviceImplementation="org.intellij.images.scientific.utils.BinarizationThresholdConfig"/>
|
||||
<projectService serviceInterface="org.intellij.images.thumbnail.ThumbnailManager"
|
||||
serviceImplementation="org.intellij.images.thumbnail.impl.ThumbnailManagerImpl"/>
|
||||
<!-- ImageIO.getReaderFormatNames() -->
|
||||
|
||||
@@ -94,5 +94,4 @@ image.color.mode.inverted.image=Inverted
|
||||
image.color.mode.grayscale.image=Grayscale
|
||||
image.color.mode.binarize.image=Binary
|
||||
image.binarize.dialog.title=Set Binarization Threshold
|
||||
image.binarize.dialog.invalid=Please enter a valid integer between 0 and 255.
|
||||
image.color.mode.configure.actions=Configure...
|
||||
image.color.mode.configure.actions=Configure\u2026
|
||||
@@ -5,15 +5,19 @@ import com.intellij.openapi.actionSystem.ActionUpdateThread
|
||||
import com.intellij.openapi.actionSystem.AnAction
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent
|
||||
import com.intellij.openapi.actionSystem.CommonDataKeys
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.openapi.vfs.writeBytes
|
||||
import org.intellij.images.editor.ImageDocument
|
||||
import org.intellij.images.scientific.BinarizationThresholdConfig
|
||||
import org.intellij.images.scientific.ScientificUtils
|
||||
import org.intellij.images.scientific.utils.BinarizationThresholdConfig
|
||||
import org.intellij.images.scientific.utils.ScientificUtils
|
||||
import org.intellij.images.scientific.statistics.ScientificImageActionsCollector
|
||||
import org.intellij.images.scientific.utils.launchBackground
|
||||
import java.awt.image.BufferedImage
|
||||
import java.io.ByteArrayOutputStream
|
||||
import javax.imageio.ImageIO
|
||||
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.intellij.images.scientific.utils.ScientificUtils.DEFAULT_IMAGE_FORMAT
|
||||
|
||||
class BinarizeImageAction : AnAction() {
|
||||
override fun getActionUpdateThread(): ActionUpdateThread = ActionUpdateThread.BGT
|
||||
@@ -21,17 +25,18 @@ class BinarizeImageAction : AnAction() {
|
||||
override fun actionPerformed(e: AnActionEvent) {
|
||||
val imageFile = e.getData(CommonDataKeys.VIRTUAL_FILE) ?: return
|
||||
val originalImage = imageFile.getUserData(ScientificUtils.ORIGINAL_IMAGE_KEY) ?: return
|
||||
val thresholdConfig = BinarizationThresholdConfig.getInstance()
|
||||
val byteArrayOutputStream = ByteArrayOutputStream()
|
||||
val binarizedImage = applyBinarization(originalImage, thresholdConfig.threshold)
|
||||
ImageIO.write(binarizedImage, ScientificUtils.DEFAULT_IMAGE_FORMAT, byteArrayOutputStream)
|
||||
imageFile.writeBytes(byteArrayOutputStream.toByteArray())
|
||||
val document = e.getData(ImageDocument.IMAGE_DOCUMENT_DATA_KEY) ?: return
|
||||
document.value = binarizedImage
|
||||
ScientificImageActionsCollector.logBinarizeImageInvoked(this)
|
||||
val thresholdConfig = BinarizationThresholdConfig.getInstance()
|
||||
|
||||
launchBackground {
|
||||
val binarizedImage = applyBinarization(originalImage, thresholdConfig.threshold)
|
||||
saveImageToFile(imageFile, binarizedImage)
|
||||
document.value = binarizedImage
|
||||
ScientificImageActionsCollector.logBinarizeImageInvoked(this@BinarizeImageAction)
|
||||
}
|
||||
}
|
||||
|
||||
private fun applyBinarization(image: BufferedImage, threshold: Int): BufferedImage {
|
||||
private suspend fun applyBinarization(image: BufferedImage, threshold: Int): BufferedImage = withContext(Dispatchers.IO) {
|
||||
val binarizedImage = BufferedImage(image.width, image.height, BufferedImage.TYPE_INT_ARGB)
|
||||
for (y in 0 until image.height) {
|
||||
for (x in 0 until image.width) {
|
||||
@@ -51,6 +56,12 @@ class BinarizeImageAction : AnAction() {
|
||||
binarizedImage.setRGB(x, y, finalColor)
|
||||
}
|
||||
}
|
||||
return binarizedImage
|
||||
binarizedImage
|
||||
}
|
||||
|
||||
private suspend fun saveImageToFile(imageFile: VirtualFile, binarizedImage: BufferedImage) = withContext(Dispatchers.IO) {
|
||||
val byteArrayOutputStream = ByteArrayOutputStream()
|
||||
ImageIO.write(binarizedImage, DEFAULT_IMAGE_FORMAT, byteArrayOutputStream)
|
||||
imageFile.writeBytes(byteArrayOutputStream.toByteArray())
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,7 @@ import com.intellij.openapi.actionSystem.AnActionEvent
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.ui.DialogWrapper
|
||||
import org.intellij.images.ImagesBundle
|
||||
import org.intellij.images.scientific.BinarizationThresholdConfig
|
||||
import org.intellij.images.scientific.utils.BinarizationThresholdConfig
|
||||
import java.awt.BorderLayout
|
||||
import java.awt.Dimension
|
||||
import javax.swing.JComponent
|
||||
|
||||
@@ -6,7 +6,7 @@ import com.intellij.openapi.actionSystem.AnActionEvent
|
||||
import com.intellij.openapi.actionSystem.CommonDataKeys
|
||||
import com.intellij.openapi.actionSystem.PlatformDataKeys
|
||||
import com.intellij.openapi.project.DumbAwareAction
|
||||
import org.intellij.images.scientific.ScientificUtils
|
||||
import org.intellij.images.scientific.utils.ScientificUtils
|
||||
import org.intellij.images.scientific.statistics.ScientificImageActionsCollector
|
||||
|
||||
class CopyImageAction : DumbAwareAction() {
|
||||
|
||||
@@ -5,14 +5,18 @@ 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 com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.openapi.vfs.writeBytes
|
||||
import org.intellij.images.editor.ImageDocument.IMAGE_DOCUMENT_DATA_KEY
|
||||
import org.intellij.images.scientific.ScientificUtils.DEFAULT_IMAGE_FORMAT
|
||||
import org.intellij.images.scientific.ScientificUtils.ORIGINAL_IMAGE_KEY
|
||||
import org.intellij.images.scientific.utils.ScientificUtils.DEFAULT_IMAGE_FORMAT
|
||||
import org.intellij.images.scientific.utils.ScientificUtils.ORIGINAL_IMAGE_KEY
|
||||
import org.intellij.images.scientific.statistics.ScientificImageActionsCollector
|
||||
import org.intellij.images.scientific.utils.launchBackground
|
||||
import java.awt.image.BufferedImage
|
||||
import java.io.ByteArrayOutputStream
|
||||
import javax.imageio.ImageIO
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
class GrayscaleImageAction : DumbAwareAction() {
|
||||
override fun getActionUpdateThread(): ActionUpdateThread = ActionUpdateThread.BGT
|
||||
@@ -20,20 +24,27 @@ class GrayscaleImageAction : DumbAwareAction() {
|
||||
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)
|
||||
val byteArrayOutputStream = ByteArrayOutputStream()
|
||||
ImageIO.write(grayscaleImage, DEFAULT_IMAGE_FORMAT, byteArrayOutputStream)
|
||||
imageFile.writeBytes(byteArrayOutputStream.toByteArray())
|
||||
val document = e.getData(IMAGE_DOCUMENT_DATA_KEY) ?: return
|
||||
document.value = grayscaleImage
|
||||
ScientificImageActionsCollector.logGrayscaleImageInvoked(this)
|
||||
|
||||
launchBackground {
|
||||
val grayscaleImage = applyGrayscale(originalImage)
|
||||
saveImageToFile(imageFile, grayscaleImage)
|
||||
document.value = grayscaleImage
|
||||
ScientificImageActionsCollector.logGrayscaleImageInvoked(this@GrayscaleImageAction)
|
||||
}
|
||||
}
|
||||
|
||||
private fun applyGrayscale(image: BufferedImage): BufferedImage {
|
||||
private suspend fun applyGrayscale(image: BufferedImage): BufferedImage = withContext(Dispatchers.IO) {
|
||||
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
|
||||
grayscaleImage
|
||||
}
|
||||
|
||||
private suspend fun saveImageToFile(imageFile: VirtualFile, grayscaleImage: BufferedImage) = withContext(Dispatchers.IO) {
|
||||
val byteArrayOutputStream = ByteArrayOutputStream()
|
||||
ImageIO.write(grayscaleImage, DEFAULT_IMAGE_FORMAT, byteArrayOutputStream)
|
||||
imageFile.writeBytes(byteArrayOutputStream.toByteArray())
|
||||
}
|
||||
}
|
||||
@@ -11,7 +11,7 @@ import com.intellij.openapi.util.registry.Registry
|
||||
import com.intellij.ui.Gray
|
||||
import com.intellij.ui.JBColor
|
||||
import org.intellij.images.ImagesBundle
|
||||
import org.intellij.images.scientific.ScientificUtils
|
||||
import org.intellij.images.scientific.utils.ScientificUtils
|
||||
import org.jetbrains.annotations.Nls
|
||||
import java.awt.FlowLayout
|
||||
import javax.swing.*
|
||||
|
||||
@@ -5,14 +5,18 @@ 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 com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.openapi.vfs.writeBytes
|
||||
import org.intellij.images.editor.ImageDocument.IMAGE_DOCUMENT_DATA_KEY
|
||||
import org.intellij.images.scientific.ScientificUtils.DEFAULT_IMAGE_FORMAT
|
||||
import org.intellij.images.scientific.ScientificUtils.ORIGINAL_IMAGE_KEY
|
||||
import org.intellij.images.scientific.utils.ScientificUtils.DEFAULT_IMAGE_FORMAT
|
||||
import org.intellij.images.scientific.utils.ScientificUtils.ORIGINAL_IMAGE_KEY
|
||||
import org.intellij.images.scientific.statistics.ScientificImageActionsCollector
|
||||
import org.intellij.images.scientific.utils.launchBackground
|
||||
import java.awt.image.BufferedImage
|
||||
import java.io.ByteArrayOutputStream
|
||||
import javax.imageio.ImageIO
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
class InvertChannelsAction : DumbAwareAction() {
|
||||
override fun getActionUpdateThread(): ActionUpdateThread = ActionUpdateThread.BGT
|
||||
@@ -20,17 +24,17 @@ class InvertChannelsAction : DumbAwareAction() {
|
||||
override fun actionPerformed(e: AnActionEvent) {
|
||||
val imageFile = e.getData(CommonDataKeys.VIRTUAL_FILE) ?: return
|
||||
val originalImage = imageFile.getUserData(ORIGINAL_IMAGE_KEY) ?: return
|
||||
val invertedImage = applyInvertChannels(originalImage)
|
||||
val byteArrayOutputStream = ByteArrayOutputStream()
|
||||
ImageIO.write(invertedImage, DEFAULT_IMAGE_FORMAT, byteArrayOutputStream)
|
||||
imageFile.writeBytes(byteArrayOutputStream.toByteArray())
|
||||
val document = e.getData(IMAGE_DOCUMENT_DATA_KEY) ?: return
|
||||
document.value = invertedImage
|
||||
ScientificImageActionsCollector.logInvertChannelsInvoked(this)
|
||||
|
||||
launchBackground {
|
||||
val invertedImage = applyInvertChannels(originalImage)
|
||||
saveImageToFile(imageFile, invertedImage)
|
||||
document.value = invertedImage
|
||||
ScientificImageActionsCollector.logInvertChannelsInvoked(this@InvertChannelsAction)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun applyInvertChannels(image: BufferedImage): BufferedImage {
|
||||
private suspend fun applyInvertChannels(image: BufferedImage): BufferedImage = withContext(Dispatchers.IO) {
|
||||
val hasAlpha = image.colorModel.hasAlpha()
|
||||
val invertedImage = BufferedImage(image.width, image.height, if (hasAlpha) BufferedImage.TYPE_INT_ARGB else BufferedImage.TYPE_INT_RGB)
|
||||
for (x in 0 until image.width) {
|
||||
@@ -47,6 +51,12 @@ class InvertChannelsAction : DumbAwareAction() {
|
||||
invertedImage.setRGB(x, y, invertedRgba)
|
||||
}
|
||||
}
|
||||
return invertedImage
|
||||
invertedImage
|
||||
}
|
||||
|
||||
private suspend fun saveImageToFile(imageFile: VirtualFile, invertedImage: BufferedImage) = withContext(Dispatchers.IO) {
|
||||
val byteArrayOutputStream = ByteArrayOutputStream()
|
||||
ImageIO.write(invertedImage, DEFAULT_IMAGE_FORMAT, byteArrayOutputStream)
|
||||
imageFile.writeBytes(byteArrayOutputStream.toByteArray())
|
||||
}
|
||||
}
|
||||
@@ -5,13 +5,18 @@ 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 com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.openapi.vfs.writeBytes
|
||||
import org.intellij.images.editor.ImageDocument.IMAGE_DOCUMENT_DATA_KEY
|
||||
import org.intellij.images.scientific.ScientificUtils.DEFAULT_IMAGE_FORMAT
|
||||
import org.intellij.images.scientific.ScientificUtils.ORIGINAL_IMAGE_KEY
|
||||
import org.intellij.images.scientific.utils.ScientificUtils.DEFAULT_IMAGE_FORMAT
|
||||
import org.intellij.images.scientific.utils.ScientificUtils.ORIGINAL_IMAGE_KEY
|
||||
import org.intellij.images.scientific.statistics.ScientificImageActionsCollector
|
||||
import org.intellij.images.scientific.utils.launchBackground
|
||||
import java.awt.image.BufferedImage
|
||||
import java.io.ByteArrayOutputStream
|
||||
import javax.imageio.ImageIO
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
class RestoreOriginalImageAction : DumbAwareAction() {
|
||||
override fun getActionUpdateThread(): ActionUpdateThread = ActionUpdateThread.BGT
|
||||
@@ -19,11 +24,18 @@ class RestoreOriginalImageAction : DumbAwareAction() {
|
||||
override fun actionPerformed(e: AnActionEvent) {
|
||||
val imageFile = e.getData(CommonDataKeys.VIRTUAL_FILE) ?: return
|
||||
val originalImage = imageFile.getUserData(ORIGINAL_IMAGE_KEY) ?: return
|
||||
val document = e.getData(IMAGE_DOCUMENT_DATA_KEY) ?: return
|
||||
|
||||
launchBackground {
|
||||
saveImageToFile(imageFile, originalImage)
|
||||
document.value = originalImage
|
||||
ScientificImageActionsCollector.logRestoreOriginalImageInvoked(this@RestoreOriginalImageAction)
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun saveImageToFile(imageFile: VirtualFile, originalImage: BufferedImage) = withContext(Dispatchers.IO) {
|
||||
val byteArrayOutputStream = ByteArrayOutputStream()
|
||||
ImageIO.write(originalImage, DEFAULT_IMAGE_FORMAT, byteArrayOutputStream)
|
||||
imageFile.writeBytes(byteArrayOutputStream.toByteArray())
|
||||
val document = e.getData(IMAGE_DOCUMENT_DATA_KEY) ?: return
|
||||
document.value = originalImage
|
||||
ScientificImageActionsCollector.logRestoreOriginalImageInvoked(this)
|
||||
}
|
||||
}
|
||||
@@ -10,12 +10,16 @@ import com.intellij.openapi.fileChooser.FileSaverDescriptor
|
||||
import com.intellij.openapi.project.DumbAwareAction
|
||||
import com.intellij.openapi.vfs.VirtualFileManager
|
||||
import org.intellij.images.ImagesBundle
|
||||
import org.intellij.images.scientific.ScientificUtils
|
||||
import org.intellij.images.scientific.utils.ScientificUtils
|
||||
import org.intellij.images.scientific.statistics.ScientificImageActionsCollector
|
||||
import org.intellij.images.scientific.utils.launchBackground
|
||||
import java.io.IOException
|
||||
import java.nio.file.Files
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
internal class SaveImageAction : DumbAwareAction() {
|
||||
override fun getActionUpdateThread(): ActionUpdateThread = ActionUpdateThread.BGT
|
||||
|
||||
override fun actionPerformed(e: AnActionEvent) {
|
||||
val project = e.project
|
||||
@@ -33,13 +37,17 @@ internal class SaveImageAction : DumbAwareAction() {
|
||||
val targetFile = wrapper.file
|
||||
val selectedFormat = targetFile.extension.lowercase()
|
||||
|
||||
try {
|
||||
Files.write(wrapper.file.toPath(), virtualFile.contentsToByteArray())
|
||||
launchBackground {
|
||||
withContext(Dispatchers.IO) {
|
||||
try {
|
||||
Files.write(wrapper.file.toPath(), virtualFile.contentsToByteArray())
|
||||
}
|
||||
catch (e: IOException) {
|
||||
logger.warn("Failed to save image", e)
|
||||
}
|
||||
ScientificImageActionsCollector.logSaveAsImageInvoked(this@SaveImageAction, selectedFormat)
|
||||
}
|
||||
}
|
||||
catch (e: IOException) {
|
||||
logger.warn("Failed to save image", e)
|
||||
}
|
||||
ScientificImageActionsCollector.logSaveAsImageInvoked(this, selectedFormat)
|
||||
}
|
||||
|
||||
override fun update(e: AnActionEvent) {
|
||||
@@ -47,8 +55,6 @@ internal class SaveImageAction : DumbAwareAction() {
|
||||
e.presentation.isEnabledAndVisible = imageFile?.getUserData(ScientificUtils.SCIENTIFIC_MODE_KEY) != null
|
||||
}
|
||||
|
||||
override fun getActionUpdateThread(): ActionUpdateThread = ActionUpdateThread.BGT
|
||||
|
||||
companion object {
|
||||
private const val IMAGE_FORMAT = "png"
|
||||
private const val IMAGE_DEFAULT_NAME: String = "myimg"
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
package org.intellij.images.scientific.utils
|
||||
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.components.Service
|
||||
import com.intellij.openapi.components.service
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@Service
|
||||
class ScientificImageViewerCoroutine(val coroutineScope: CoroutineScope) {
|
||||
|
||||
object Utils {
|
||||
val scope: CoroutineScope
|
||||
get() = ApplicationManager.getApplication().service<ScientificImageViewerCoroutine>().coroutineScope
|
||||
}
|
||||
}
|
||||
|
||||
fun launchBackground(block: suspend CoroutineScope.() -> Unit): Job = ScientificImageViewerCoroutine.Utils.scope.launch(block = block)
|
||||
@@ -1,5 +1,5 @@
|
||||
// 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
|
||||
package org.intellij.images.scientific.utils
|
||||
|
||||
import com.intellij.openapi.components.PersistentStateComponent
|
||||
import com.intellij.openapi.components.Service
|
||||
Reference in New Issue
Block a user