これはRadialGradientPaint
、適切なAlphaComposite
で解決することができます。
以下は、これを行う方法を示すMCVEです。それはuser1803551 used in his answerと同じイメージを使用するので、スクリーンショットはほぼ同じに見えます。
- それは最初にイメージを塗りつぶし:しかし、この1を使用すると、所望の画像の実際の作成が行わ
updateGradientAt
方法、現在のマウスの位置を渡すことによって、周りに穴を移動することができますMouseMotionListener
を追加します元の画像
- 次に、
RadialGradientPaint
を作成します。中央には完全に不透明な色、境界には完全に透明な色(!)があります。これは直観に反して見えるかもしれませんが、次のステップで行われる既存のイメージから穴を「切り取る」ことを意図しています。
はGraphics2D
に割り当てられています。これは、式
Ar = Ad*(1-As)
Cr = Cd*(1-As)
「ソース」を意味s
「結果」のr
スタンド、および「宛先」
ため
d
スタンドのように、アルファ値の「反転」させます
結果は、希望の位置に放射状のグラデーション透明度を持ち、中央が完全に透明で、境界線(!)が完全に不透明なイメージです。次に、Paint
とComposite
のこの組み合わせを使用して、楕円を穴のサイズと座標で充填します。 (1つはfillRect
コールを行い、イメージ全体を満たしてもよい - 結果は変わらない)。
import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RadialGradientPaint;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class TransparentGradientInImage
{
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
@Override
public void run()
{
createAndShowGUI();
}
});
}
private static void createAndShowGUI()
{
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
TransparentGradientInImagePanel p =
new TransparentGradientInImagePanel();
f.getContentPane().add(p);
f.setSize(800, 600);
f.setLocationRelativeTo(null);
f.setVisible(true);
}
}
class TransparentGradientInImagePanel extends JPanel
{
private BufferedImage background;
private BufferedImage originalImage;
private BufferedImage imageWithGradient;
TransparentGradientInImagePanel()
{
try
{
background = ImageIO.read(
new File("night-sky-astrophotography-1.jpg"));
originalImage = convertToARGB(ImageIO.read(new File("7bI1Y.jpg")));
imageWithGradient = convertToARGB(originalImage);
}
catch (IOException e)
{
e.printStackTrace();
}
addMouseMotionListener(new MouseAdapter()
{
@Override
public void mouseMoved(MouseEvent e)
{
updateGradientAt(e.getPoint());
}
});
}
private void updateGradientAt(Point point)
{
Graphics2D g = imageWithGradient.createGraphics();
g.drawImage(originalImage, 0, 0, null);
int radius = 100;
float fractions[] = { 0.0f, 1.0f };
Color colors[] = { new Color(0,0,0,255), new Color(0,0,0,0) };
RadialGradientPaint paint =
new RadialGradientPaint(point, radius, fractions, colors);
g.setPaint(paint);
g.setComposite(AlphaComposite.DstOut);
g.fillOval(point.x - radius, point.y - radius, radius * 2, radius * 2);
g.dispose();
repaint();
}
private static BufferedImage convertToARGB(BufferedImage image)
{
BufferedImage newImage =
new BufferedImage(image.getWidth(), image.getHeight(),
BufferedImage.TYPE_INT_ARGB);
Graphics2D g = newImage.createGraphics();
g.drawImage(image, 0, 0, null);
g.dispose();
return newImage;
}
@Override
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
g.drawImage(background, 0, 0, null);
g.drawImage(imageWithGradient, 0, 0, null);
}
}
あなたは、異なる効果を達成するためにRadialGradientPaint
のfractions
とcolors
でプレイしてもよいです。例えば、大規模な、ソフトな "コロナ" で、これらの値...
float fractions[] = { 0.0f, 0.1f, 1.0f };
Color colors[] = {
new Color(0,0,0,255),
new Color(0,0,0,255),
new Color(0,0,0,0)
};
原因小さな、透明の穴、:これらの値に対し

float fractions[] = { 0.0f, 0.9f, 1.0f };
Color colors[] = {
new Color(0,0,0,255),
new Color(0,0,0,255),
new Color(0,0,0,0)
};
小さな「コロナ」を有する大きくて鮮明な透明な中心をもたらす:

RadialGradientPaint
JavaDocsには、望ましい値を見つけるのに役立ついくつかの例があります。
私は(同様の)答え掲載いくつかの関連質問:そのパフォーマンスについての質問を受けて
EDITをその仲間で尋ねられたNTS
Paint
/Composite
アプローチのパフォーマンスがgetRGB
/setRGB
アプローチとの比較についての質問は確かに面白いです。私の以前の経験から、最初のものは2番目のものよりもはるかに高速だったでしょう。一般に、getRGB
/setRGB
は遅くなりがちで、組み込みのメカニズムは高度に最適化されています(場合によってはハードウェアアクセラレーションさえも可能です)。実際に
、Paint
/Composite
アプローチはgetRGB
/setRGB
アプローチよりも早く、私は期待と同じくらいではありません。私のPC上のタイミングが一緒にいる
// NOTE: This is not really a sophisticated "Benchmark",
// but gives a rough estimate about the performance
import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RadialGradientPaint;
import java.awt.image.BufferedImage;
public class TransparentGradientInImagePerformance
{
public static void main(String[] args)
{
int w = 1000;
int h = 1000;
BufferedImage image0 = new BufferedImage(w, h,
BufferedImage.TYPE_INT_ARGB);
BufferedImage image1 = new BufferedImage(w, h,
BufferedImage.TYPE_INT_ARGB);
long before = 0;
long after = 0;
int runs = 100;
for (int radius = 100; radius <=400; radius += 10)
{
before = System.nanoTime();
for (int i=0; i<runs; i++)
{
transparitize(image0, w/2, h/2, radius);
}
after = System.nanoTime();
System.out.println(
"Radius "+radius+" with getRGB/setRGB: "+(after-before)/1e6);
before = System.nanoTime();
for (int i=0; i<runs; i++)
{
updateGradientAt(image0, image1, new Point(w/2, h/2), radius);
}
after = System.nanoTime();
System.out.println(
"Radius "+radius+" with paint "+(after-before)/1e6);
}
}
private static void transparitize(
BufferedImage imgA, int centerX, int centerY, int r)
{
for (int x = centerX - r; x < centerX + r; x++)
{
for (int y = centerY - r; y < centerY + r; y++)
{
double distance = Math.sqrt(
Math.pow(Math.abs(centerX - x), 2) +
Math.pow(Math.abs(centerY - y), 2));
if (distance > r)
continue;
int argb = imgA.getRGB(x, y);
int a = (argb >> 24) & 255;
double factor = distance/r;
argb = (argb - (a << 24) + ((int) (a * factor) << 24));
imgA.setRGB(x, y, argb);
}
}
}
private static void updateGradientAt(BufferedImage originalImage,
BufferedImage imageWithGradient, Point point, int radius)
{
Graphics2D g = imageWithGradient.createGraphics();
g.drawImage(originalImage, 0, 0, null);
float fractions[] = { 0.0f, 1.0f };
Color colors[] = { new Color(0, 0, 0, 255), new Color(0, 0, 0, 0) };
RadialGradientPaint paint = new RadialGradientPaint(point, radius,
fractions, colors);
g.setPaint(paint);
g.setComposite(AlphaComposite.DstOut);
g.fillOval(point.x - radius, point.y - radius, radius * 2, radius * 2);
g.dispose();
}
}
:以下は、当然のことながら、本当に深い「ベンチマーク」(私はこれのためにキャリパーやJMHを採用していなかった)、実際のパフォーマンスについて良い評価を与えるべきではありませんPaint
/Composite
方法は約2倍の速さgetRGB
/setRGB
方法としてあることを示す
...
Radius 390 with getRGB/setRGB: 1518.224404
Radius 390 with paint 764.11017
Radius 400 with getRGB/setRGB: 1612.854049
Radius 400 with paint 794.695199
の行。パフォーマンスとは別に、Paint
/Composite
には、上記のRadialGradientPaint
の可能なパラメータ化を中心とするいくつかの他の利点があります。これが私がこのソリューションを好む理由です。
とてもいいです、 – user1803551
@ user1803551これはEDITを追加したほうがパフォーマンスが良いようですが、期待したほどのパフォーマンスは得られていません(これは ' RadialGradientPaint' - これでいくつかの素晴らしい効果を得ることができ、単純に「穴をカットする」はこのクラスにとって最も簡単なケースの1つです) – Marco13