2017-02-08 6 views
4

Я пытаюсь написать программу для рисования полигонов и заполнения их желаемым цветом. Это простое приложение для рисования, но проблема, с которой я столкнулась, - это когда я рисую многоугольники и рисую их то между полигонами появляется тонкая белая линия. Но когда я не сглаживаю полигоны, тогда белая линия исчезает, но полигоны не являются гладкими. И реальная проблема в том, что мне нужно иметь гладкие полигоны, а также белую тонкую линию также нужно удалить.Призрачная белая линия появляется при сглаживании многоугольников в JAVA

Класс рисовать многоугольник является:

public class GrayScaleManager{ 

    private final VisualizerController controller; 

    private final BufferedImage grayScaledImage; 
    private final HashMap<ToolsModel, BufferedImage> grayScaleportionList; 

    public GrayScaleManager(VisualizerController drawingCanvas) { 
     this.controller = drawingCanvas; 
     grayScaleportionList = new HashMap<>(); 

     grayScaledImage = toGray(Utility.bufferedImageDeepCopy(Util.getImg())); 
    } 


    public void grayScaleSelectedPortion(Graphics2D g, ToolsModel selectedArea) { 


     g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); 
     g.setClip((Shape) selectedArea); 
     g.drawImage(grayScaledImage, 0, 0, null); 
     g.setClip(null); 


    } 

    private BufferedImage toGray(BufferedImage image) { 
     int width = image.getWidth(); 
     int height = image.getHeight(); 
     for (int i = 0; i < height; i++) { 
      for (int j = 0; j < width; j++) { 
       Color c = new Color(image.getRGB(j, i)); 
       int red = (int) (c.getRed() * 0.3); 
       int green = (int) (c.getGreen() * 0.59); 
       int blue = (int) (c.getBlue() * 0.11); 

       int sum = red + green + blue; 
       Color newColor = new Color(sum, sum, sum); 
       image.setRGB(j, i, newColor.getRGB()); 
      } 
     } 
     return image; 
    } 
    public VisualizerController getController() { 
     return controller; 
    } 
    public HashMap<ToolsModel, BufferedImage> getGrayScaleportionList() { 
     return grayScaleportionList; 
    } 
} 

И образ, что я получаю, когда я бегу код являются enter image description here

Собственно код вращается в traingle (3 сценариев) :

Сценарий 1: Если код выполняется как этот

public void grayScaleSelectedPotion(Graphics2D g, ToolsModel selectedArea){ 
     g.setClip((Shape) selectedArea); 
     g.drawImage(grayScaledImage, 0, 0, null); 
     g.setClip(null); 
    } 

Плюсы: 1. Если несколько слоев нарисованы путем совпадения друг с другом одного цвета, слои кажутся одиночными (один слой). 2. Не призраков белых линий. Против: 1. Кромки линий не являются гладкими.

Сценарий 2: Если применяется визуализация, просто применяя ниже код внутри выше метода.

public void grayScaleSelectedPotion(Graphics2D g, ToolsModel selectedArea){ 
       g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,                    RenderingHints.VALUE_ANTIALIAS_ON); 
       g.setClip((Shape) selectedArea); 
       g.drawImage(grayScaledImage, 0, 0, null); 
       g.setClip(null); 
    } 

За: 1. Один слой. 2. Ребра гладкие. Против: 1. Появляются белые пояса призраков.

Сценарий 3: Если вынесено, но DrawImage() удален

 public void grayScaleSelectedPotion(Graphics2D g, ToolsModel selectedArea){ 
       g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,                    RenderingHints.VALUE_ANTIALIAS_ON); 
       g.setClip((Shape) selectedArea); 
      // g.drawImage(grayScaledImage, 0, 0, null); 
       g.setClip(null); 
     } 

Pros: 1. Края являются гладкими. 2. Не призраков белых линий.

Против: 1. Несколько слоев отчетливо видны, даже слои имеют одинаковые цвета (что неприемлемо).

В заключение, все три недостатка в трех сценариях должны быть очищены.

После внедрения решения от @MadProgrammer код выглядит как:

super.paintComponent(g); 
    grayImage = grayScaleManager.getGrayImage(); 
    BufferedImage mask = new BufferedImage(img.getWidth(),img.getHeight(),BufferedImage.TYPE_INT_ARGB); 
    Graphics2D g2d = mask.createGraphics(); 
    g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON); 
    g2d.setRenderingHint(RenderingHints.KEY_RENDERING,RenderingHints.VALUE_RENDER_QUALITY); 
    shadeList.forEach((shape)->{ 
     g2d.setColor(shape.getColor()); 
     if (shape.getColor().getAlpha() != NULL_ALPHA) { 
      //g2d.fill((Shape)shape); 
     } 
     g2d.fill((Shape)shape); 
     if (shape.getColor().getAlpha() == SELECTION_ALPHA) { 
      g2d.setStroke(new BasicStroke(1)); 
      g2d.setColor(Color.red.brighter().brighter().brighter()); 
      g2d.draw((Shape) shape); 
     } 
    }); 
    // g2d.dispose(); 
    masked = applyMask(mask,grayImage,AlphaComposite.SRC_IN); 
    g.drawImage(img,0,0,null); 
    g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_IN, 0.0f)); 
    g.drawImage(masked, 0, 0, this); 
    g2d.dispose(); 
    g.dispose(); 
} 


/*Added methods for the changes applymask method*/ 

public static BufferedImage applyMask(BufferedImage sourceImage, BufferedImage maskImage, int method) { 

    System.out.println("I am in applymask"); 

    BufferedImage maskedImage = null; 
    if (sourceImage != null) { 
     System.out.println("I am in applymask in if case"); 

     int width = maskImage.getWidth(null); 
     int height = maskImage.getHeight(null); 

     maskedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); 
     Graphics2D mg = maskedImage.createGraphics(); 

     int x = (width - sourceImage.getWidth(null))/2; 
     int y = (height - sourceImage.getHeight(null))/2; 

     //mg.setColor(Color.RED); 
     //mg.drawImage(sourceImage, x, y, null); 
     mg.drawImage(sourceImage, 0, 0, null); 
     mg.setComposite(AlphaComposite.getInstance(method,0.0f)); 

     mg.dispose(); 
    } 

    return maskedImage; 

} 

Но теперь grayScaledImage не красится и многоугольники накладываются друг на друга, и когда grayScaledImage добавляется то мы не можем добавить другие цвета к многоугольнику.

+0

Из памяти 'setClip' не генерирует« мягкие »ребра – MadProgrammer

+0

@MadProgrammer, пожалуйста, вы можете быть более выразительными. –

+0

Если вы используете 'setClip', вы не получите преимущества сглаживания (из памяти), посмотрите на [Soft Clipping] (https://community.oracle.com/blogs/campbell/2006/07/ 19/java-2d-trickery-soft-clipping) для некоторых идей. Вы также должны использовать 'Graphics # create' и' Graphics # dispose', которые позволят вам вносить изменения в контекст (например, с помощью 'setClip'), который не будет переноситься на – MadProgrammer

ответ

-2

Я думаю, ваше изображение показывает, что ваш код строит многоугольники в 2D, поэтому это показывает белую линию, чтобы чувствовать 2D, что один полигон перекрывает другие полигоны.

+0

Извините Маулин, который может и не быть реальной причиной, поскольку я много искал, и белая линия не появляется, если граница многоугольника является прямой, например, если я рисую квадрат или прямоугольник, не будет никакой белой линии. Поэтому я думаю, что его проблема в Antialias для треугольников –

+0

О, ладно ......... –

0

Вы можете решить свою проблему, создав объединение отдельных фигур обрезки с помощью класса Area, а затем примените их как маску обрезки изображения в оттенках серого.

1

Хорошо, так что это может показаться немного запутанным, но оно должно приблизиться к вашей цели. В основном setClip не генерирует «мягкие края», вы должны обманывать.

Основная идея заключается в создании прозрачного изображения области, которую вы хотите захватить, это становится «маской». Затем мы используем маску для «вырезания» части исходного изображения, которое затем, наконец, применяется к исходному изображению.

Это одни и те же основные концепции продемонстрированы в следующих примерах ...

Позвольте мне попробовать и вас через важные части ...

// The master image or background 
master = ImageIO.read(...); 
// Generate a gray scaled version of the master image 
// This is what we will be cutting out 
ColorConvertOp op = new ColorConvertOp(ColorSpace.getInstance(ColorSpace.CS_GRAY), null); 
grayScaled = op.filter(master, null); 

int width = master.getWidth()/4; 
int height = master.getHeight()/4; 

// This simply what I'm using as the base "selection" 
// But for all intents purpose, it can be anything which can 
// be painted through Graphics 
Shape shape = new Rectangle2D.Double(0, 0, width, height); 

// The base mask, not that it's transparent 
BufferedImage mask = new BufferedImage(master.getWidth(), master.getHeight(), BufferedImage.TYPE_INT_ARGB); 
Graphics2D g2d = mask.createGraphics(); 
// Offset the location to apply the "selection" 
g2d.translate((master.getWidth() - shape.getBounds().width)/2, (master.getHeight() - shape.getBounds().height)/2); 
// Any color will do, it could even have an alpha applied 
g2d.setColor(Color.BLUE); 
// Rotate it a bit, because square is boring... 
shape = new Path2D.Double(shape, AffineTransform.getRotateInstance(Math.toRadians(45.0), width/2, height/2)); 
// Fill the area 
g2d.fill(shape); 
// Rotate again, so you can see that we're compounding the selection 
shape = new Path2D.Double(shape, AffineTransform.getRotateInstance(Math.toRadians(45.0), width/2, height/2)); 
// Fill the new selection 
g2d.fill(shape);   
// Clean up 
g2d.dispose(); 

// Now, apply the mask to the image to get a "cut out" 
masked = applyMask(mask, grayScaled, AlphaComposite.SRC_IN); 

Теперь, это простой пример. Если вы хотите изменить выделение, вы можете воссоздать mask с нуля или просто нарисовать новые объекты на оригинале mask, а затем повторно применить его к grayScaled для создания нового изображения masked.

Тогда все, что вам нужно сделать, это нарисовать masked изображение над master изображения на любом уровне альфа вы хотите ..

Example

что «сероватый» звезда в середине, это маска ;)

import java.awt.AlphaComposite; 
import java.awt.Color; 
import java.awt.Dimension; 
import java.awt.EventQueue; 
import java.awt.Graphics; 
import java.awt.Graphics2D; 
import java.awt.Shape; 
import java.awt.color.ColorSpace; 
import java.awt.geom.AffineTransform; 
import java.awt.geom.Path2D; 
import java.awt.geom.Rectangle2D; 
import java.awt.image.BufferedImage; 
import java.awt.image.ColorConvertOp; 
import java.io.File; 
import java.io.IOException; 
import javax.imageio.ImageIO; 
import javax.swing.JFrame; 
import javax.swing.JPanel; 
import javax.swing.UIManager; 
import javax.swing.UnsupportedLookAndFeelException; 

public class Test { 

    public static void main(String[] args) { 
     new Test(); 
    } 

    public Test() { 
     EventQueue.invokeLater(new Runnable() { 
      @Override 
      public void run() { 
       try { 
        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); 
       } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { 
        ex.printStackTrace(); 
       } 

       JFrame frame = new JFrame("Testing"); 
       frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
       frame.add(new TestPane()); 
       frame.pack(); 
       frame.setLocationRelativeTo(null); 
       frame.setVisible(true); 
      } 
     }); 
    } 

    public class TestPane extends JPanel { 

     private BufferedImage master; 
     private BufferedImage grayScaled; 
     private BufferedImage masked; 

     public TestPane() { 
      try { 
       master = ImageIO.read(...); 
       ColorConvertOp op = new ColorConvertOp(ColorSpace.getInstance(ColorSpace.CS_GRAY), null); 
       grayScaled = op.filter(master, null); 

       int width = master.getWidth()/4; 
       int height = master.getHeight()/4; 

       Shape shape = new Rectangle2D.Double(0, 0, width, height); 
       shape = new Path2D.Double(shape, AffineTransform.getRotateInstance(Math.toRadians(45.0), width/2, height/2)); 

       BufferedImage mask = new BufferedImage(master.getWidth(), master.getHeight(), BufferedImage.TYPE_INT_ARGB); 
       Graphics2D g2d = mask.createGraphics(); 
       g2d.translate((master.getWidth() - shape.getBounds().width)/2, (master.getHeight() - shape.getBounds().height)/2); 
       g2d.setColor(Color.BLUE); 
       g2d.fill(shape); 
       shape = new Path2D.Double(shape, AffineTransform.getRotateInstance(Math.toRadians(45.0), width/2, height/2)); 
       g2d.fill(shape);    
       g2d.dispose(); 

       masked = applyMask(mask, grayScaled, AlphaComposite.SRC_IN); 
      } catch (IOException ex) { 
       ex.printStackTrace(); 
      } 
     } 

     @Override 
     public Dimension getPreferredSize() { 
      return master == null ? getPreferredSize() : new Dimension(master.getWidth(), master.getHeight()); 
     } 

     @Override 
     protected void paintComponent(Graphics g) { 
      super.paintComponent(g); 
      if (master != null && masked != null) { 
       Graphics2D g2d = (Graphics2D) g.create(); 
       int x = (getWidth() - master.getWidth())/2; 
       int y = (getHeight() - master.getHeight())/2; 

       g2d.drawImage(master, x, y, this); 
       g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.5f)); 
       g2d.drawImage(masked, x, y, this); 
       g2d.dispose(); 
      } 
     } 

    } 

    public static BufferedImage applyMask(BufferedImage sourceImage, BufferedImage maskImage, int method) { 

     BufferedImage maskedImage = null; 
     if (sourceImage != null) { 

      int width = maskImage.getWidth(null); 
      int height = maskImage.getHeight(null); 

      maskedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); 
      Graphics2D mg = maskedImage.createGraphics(); 

      int x = (width - sourceImage.getWidth(null))/2; 
      int y = (height - sourceImage.getHeight(null))/2; 

      mg.drawImage(sourceImage, x, y, null); 
      mg.setComposite(AlphaComposite.getInstance(method)); 

      mg.drawImage(maskImage, 0, 0, null); 

      mg.dispose(); 
     } 

     return maskedImage; 

    } 

} 

вы также можете применить рендеринг подсказки к любому из него в любое время вы хотите, чтобы помочь очистить его, так как это всего лишь образы, это не должно дать вам (для многих) вопросов;)

+0

Большое спасибо за подробное описание Я попробую и дам вам знать как можно скорее. –

+0

Не бойтесь играть с порядком параметров изображения и типа applyMask типа AlphaComposite, взял несколько попыток заставить его делать то, что я хотел;) вы можете взглянуть на [Композитная графика] (https://docs.oracle.com/javase/tutorial/2d/advanced/compositing.html) для получения более подробной информации – MadProgrammer

+0

Я думаю, что мне нужна ваша помощь всерьез. Я схожу с ума со всем этим графическим кодом. Не могли бы вы помочь мне в этом, я могу отправить вам свой проект, если вы заинтересованы в том, что у меня нет много времени, чтобы закончить этот проект, и реализация вашего кода выглядит многообещающим, но я не смог его преодолеть. Так что бы у вас было время посмотреть на это и помочь решить проблему. –

Смежные вопросы