«Заполнить» символы Юникода в ярлыках

Как «заполнить» символы Unicode в ярлыках в Swing?

Я пытаюсь сделать пользовательский интерфейс для программы шахмат, которую я недавно запрограммировал (с фигурами в шахматах, что-то вроде выше). В нем я использую символы \u2654 для представления моих шахматных фигур ( \u2654 через \u265F ).

Проблема заключается в следующем:

Когда я установил фон моей шахматной фигуры JLabel на что-то вроде белого, вся этикетка заполнена (в моем случае это белый квадрат размером 50 * 50 пикселей с символом сверху). Это приводит к тому, что мои фигуры выглядят как плитки, а не только их картины.

Когда я устанавливаю ярлык непрозрачным, я просто получаю версию резака для печенья моей шахматной фигуры, а не одну, заполненную ее внутренностями. НАПРИМЕР

Фактический результат

Есть ли способ заполнить только символ?

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

Код

 import java.awt.*; import javax.swing.*; import java.util.Random; class ChessBoard { static Font font = new Font("Sans-Serif", Font.PLAIN, 50); static Random rnd = new Random(); public static void addUnicodeCharToContainer( String s, Container c, boolean randomColor) { JLabel l = new JLabel(s); l.setFont(font); if (randomColor) { int r = rnd.nextInt(255); int g = rnd.nextInt(255); int b = rnd.nextInt(255); l.setForeground(new Color(r,g,b)); l.setBackground(new Color(255-r,255-g,255-b)); l.setOpaque(true); } c.add(l); } public static void main(String[] args) { Runnable r = new Runnable() { @Override public void run() { JPanel gui = new JPanel(new GridLayout(0,6,4,4)); String[] pieces = { "\u2654","\u2655","\u2656","\u2657","\u2658","\u2659", "\u265A","\u265B","\u265C","\u265D","\u265E","\u265F" }; for (String piece : pieces) { addUnicodeCharToContainer(piece,gui,false); } for (String piece : pieces) { addUnicodeCharToContainer(piece,gui,true); } JOptionPane.showMessageDialog(null, gui); } }; SwingUtilities.invokeLater(r); } } 

Шахматные фигуры

Две строки генерируются через колдовство Java-2D. Фокус в том, чтобы:

  • Игнорируйте «черные» шахматные фигуры на том основании, что наш цвет действительно исходит из «пространств, содержащихся в форме». Они больше в белых шахматных фигурах.
  • Создайте GlyphVector который представляет форму персонажа. Это важно для дальнейших операций в Java-2D.
  • Создайте Rectangle размера изображения.
  • subtract() форму символа из формы изображения.
  • Перерыв, который изменил форму на регионы.
  • Заполните области цветом фона, но пропустите единую область, которая начинается с 0,0,0,0 (представляющая крайний регион, который нам нужен прозрачным).
  • Наконец, заполните форму самого символа, используя цвет контура.

Код

 import java.awt.*; import java.awt.font.*; import java.awt.geom.*; import java.awt.image.BufferedImage; import javax.swing.*; import java.util.*; class ChessBoard { static Font font = new Font(Font.SANS_SERIF, Font.PLAIN, 50); static Random rnd = new Random(); public static ArrayList separateShapeIntoRegions(Shape shape) { ArrayList regions = new ArrayList(); PathIterator pi = shape.getPathIterator(null); int ii = 0; GeneralPath gp = new GeneralPath(); while (!pi.isDone()) { double[] coords = new double[6]; int pathSegmentType = pi.currentSegment(coords); int windingRule = pi.getWindingRule(); gp.setWindingRule(windingRule); if (pathSegmentType == PathIterator.SEG_MOVETO) { gp = new GeneralPath(); gp.setWindingRule(windingRule); gp.moveTo(coords[0], coords[1]); System.out.println(ii++ + " \t" + coords[0] + "," + coords[1]); } else if (pathSegmentType == PathIterator.SEG_LINETO) { gp.lineTo(coords[0], coords[1]); } else if (pathSegmentType == PathIterator.SEG_QUADTO) { gp.quadTo(coords[0], coords[1], coords[2], coords[3]); } else if (pathSegmentType == PathIterator.SEG_CUBICTO) { gp.curveTo( coords[0], coords[1], coords[2], coords[3], coords[4], coords[5]); } else if (pathSegmentType == PathIterator.SEG_CLOSE) { gp.closePath(); regions.add(new Area(gp)); } else { System.err.println("Unexpected value! " + pathSegmentType); } pi.next(); } return regions; } public static void addColoredUnicodeCharToContainer( String s, Container c, Color bgColor, Color outlineColor, boolean blackSquare) { int sz = font.getSize(); BufferedImage bi = new BufferedImage( sz, sz, BufferedImage.TYPE_INT_ARGB); Graphics2D g = bi.createGraphics(); g.setRenderingHint( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g.setRenderingHint( RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE); g.setRenderingHint( RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY); FontRenderContext frc = g.getFontRenderContext(); GlyphVector gv = font.createGlyphVector(frc, s); Rectangle2D box1 = gv.getVisualBounds(); Shape shape1 = gv.getOutline(); Rectangle r = shape1.getBounds(); System.out.println("shape rect: " + r); int spaceX = sz - r.width; int spaceY = sz - r.height; AffineTransform trans = AffineTransform.getTranslateInstance( -rx + (spaceX / 2), -ry + (spaceY / 2)); System.out.println("Box2D " + trans); Shape shapeCentered = trans.createTransformedShape(shape1); Shape imageShape = new Rectangle2D.Double(0, 0, sz, sz); Area imageShapeArea = new Area(imageShape); Area shapeArea = new Area(shapeCentered); imageShapeArea.subtract(shapeArea); ArrayList regions = separateShapeIntoRegions(imageShapeArea); g.setStroke(new BasicStroke(1)); for (Shape region : regions) { Rectangle r1 = region.getBounds(); if (r1.getX() < 0.001 && r1.getY() < 0.001) { } else { g.setColor(bgColor); g.fill(region); } } g.setColor(outlineColor); g.fill(shapeArea); g.dispose(); JLabel l = new JLabel(new ImageIcon(bi), JLabel.CENTER); Color bg = (blackSquare ? Color.BLACK : Color.WHITE); l.setBackground(bg); l.setOpaque(true); c.add(l); } public static void main(String[] args) { Runnable r = new Runnable() { @Override public void run() { JPanel gui = new JPanel(new GridLayout(0, 6, 4, 4)); String[] pieces = { "\u2654", "\u2655", "\u2656", "\u2657", "\u2658", "\u2659" }; boolean blackSquare = false; for (String piece : pieces) { addColoredUnicodeCharToContainer( piece, gui, new Color(203,203,197), Color.DARK_GRAY, blackSquare); blackSquare = !blackSquare; } blackSquare = !blackSquare; for (String piece : pieces) { addColoredUnicodeCharToContainer( piece, gui, new Color(192,142,60), Color.DARK_GRAY, blackSquare); blackSquare = !blackSquare; } JOptionPane.showMessageDialog(null, gui); } }; SwingUtilities.invokeLater(r); } } 

Шахматная доска

Это то, что может выглядеть как шахматная доска (22.81 Kb).

Шахматная доска без одежды

Наборы спрайтов

Набор спрайтов шахматных фигур (64x64 пикселя), отображаемых из символов Юникода, - как PNG с прозрачным BG. Каждый из них имеет 6 столбцов для частей x 2 рядов для противников (общий размер 384x128 пикселей).

Шахматные фигуры с твердым наполнителем (бронза / олово) (11.64Kb).

Набор для плитки шахмат

Шахматные фигуры с gradleиентным заполнением (золото / серебро) (13.61Kb).

Набор плитки для шахматной фигуры с градиентной начинкой

Шахматные фигуры с gradleиентной заливкой (более темный голубой / пурпурный) (13.44Kb).

Набор плитки для шахматной фигуры с градиентной начинкой

Код для Chess Board & Sprite Set

 import java.awt.*; import java.awt.font.*; import java.awt.geom.*; import java.awt.image.BufferedImage; import javax.swing.*; import javax.swing.border.*; import java.io.*; import javax.imageio.ImageIO; import java.util.*; import java.util.logging.*; class ChessBoard { /** * Unicodes for chess pieces. */ static final String[] pieces = { "\u2654", "\u2655", "\u2656", "\u2657", "\u2658", "\u2659" }; static final int KING = 0, QUEEN = 1, CASTLE = 2, BISHOP = 3, KNIGHT = 4, PAWN = 5; public static final int[] order = new int[]{ CASTLE, KNIGHT, BISHOP, QUEEN, KING, BISHOP, KNIGHT, CASTLE }; /* * Colors.. */ public static final Color outlineColor = Color.DARK_GRAY; public static final Color[] pieceColors = { new Color(203, 203, 197), new Color(192, 142, 60) }; static final int WHITE = 0, BLACK = 1; /* * Font. The images use the font sizeXsize. */ static Font font = new Font("Sans-Serif", Font.PLAIN, 64); public static ArrayList separateShapeIntoRegions(Shape shape) { ArrayList regions = new ArrayList(); PathIterator pi = shape.getPathIterator(null); int ii = 0; GeneralPath gp = new GeneralPath(); while (!pi.isDone()) { double[] coords = new double[6]; int pathSegmentType = pi.currentSegment(coords); int windingRule = pi.getWindingRule(); gp.setWindingRule(windingRule); if (pathSegmentType == PathIterator.SEG_MOVETO) { gp = new GeneralPath(); gp.setWindingRule(windingRule); gp.moveTo(coords[0], coords[1]); } else if (pathSegmentType == PathIterator.SEG_LINETO) { gp.lineTo(coords[0], coords[1]); } else if (pathSegmentType == PathIterator.SEG_QUADTO) { gp.quadTo(coords[0], coords[1], coords[2], coords[3]); } else if (pathSegmentType == PathIterator.SEG_CUBICTO) { gp.curveTo( coords[0], coords[1], coords[2], coords[3], coords[4], coords[5]); } else if (pathSegmentType == PathIterator.SEG_CLOSE) { gp.closePath(); regions.add(new Area(gp)); } else { System.err.println("Unexpected value! " + pathSegmentType); } pi.next(); } return regions; } public static BufferedImage getImageForChessPiece( int piece, int side, boolean gradient) { int sz = font.getSize(); BufferedImage bi = new BufferedImage( sz, sz, BufferedImage.TYPE_INT_ARGB); Graphics2D g = bi.createGraphics(); g.setRenderingHint( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g.setRenderingHint( RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE); g.setRenderingHint( RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY); FontRenderContext frc = g.getFontRenderContext(); GlyphVector gv = font.createGlyphVector(frc, pieces[piece]); Rectangle2D box1 = gv.getVisualBounds(); Shape shape1 = gv.getOutline(); Rectangle r = shape1.getBounds(); int spaceX = sz - r.width; int spaceY = sz - r.height; AffineTransform trans = AffineTransform.getTranslateInstance( -rx + (spaceX / 2), -ry + (spaceY / 2)); Shape shapeCentered = trans.createTransformedShape(shape1); Shape imageShape = new Rectangle2D.Double(0, 0, sz, sz); Area imageShapeArea = new Area(imageShape); Area shapeArea = new Area(shapeCentered); imageShapeArea.subtract(shapeArea); ArrayList regions = separateShapeIntoRegions(imageShapeArea); g.setStroke(new BasicStroke(1)); g.setColor(pieceColors[side]); Color baseColor = pieceColors[side]; if (gradient) { Color c1 = baseColor.brighter(); Color c2 = baseColor; GradientPaint gp = new GradientPaint( sz/2-(r.width/4), sz/2-(r.height/4), c1, sz/2+(r.width/4), sz/2+(r.height/4), c2, false); g.setPaint(gp); } else { g.setColor(baseColor); } for (Shape region : regions) { Rectangle r1 = region.getBounds(); if (r1.getX() < 0.001 && r1.getY() < 0.001) { } else { g.fill(region); } } g.setColor(outlineColor); g.fill(shapeArea); g.dispose(); return bi; } public static void addColoredUnicodeCharToContainer( Container c, int piece, int side, Color bg, boolean gradient) { JLabel l = new JLabel( new ImageIcon(getImageForChessPiece(piece, side, gradient)), JLabel.CENTER); l.setBackground(bg); l.setOpaque(true); c.add(l); } public static void addPiecesToContainer( Container c, int intialSquareColor, int side, int[] pieces, boolean gradient) { for (int piece : pieces) { addColoredUnicodeCharToContainer( c, piece, side, intialSquareColor++%2 == BLACK ? Color.BLACK : Color.WHITE, gradient); } } public static void addPiecesToContainer( Container c, Color bg, int side, int[] pieces, boolean gradient) { for (int piece : pieces) { addColoredUnicodeCharToContainer( c, piece, side, bg, gradient); } } public static void addBlankLabelRow(Container c, int initialSquareColor) { for (int ii = 0; ii < 8; ii++) { JLabel l = new JLabel(); Color bg = (initialSquareColor++ % 2 == BLACK ? Color.BLACK : Color.WHITE); l.setBackground(bg); l.setOpaque(true); c.add(l); } } public static void main(String[] args) { final int[] pawnRow = new int[]{ PAWN, PAWN, PAWN, PAWN, PAWN, PAWN, PAWN, PAWN }; Runnable r = new Runnable() { @Override public void run() { int gradient = JOptionPane.showConfirmDialog( null, "Use gradient fille color?"); boolean gradientFill = gradient == JOptionPane.OK_OPTION; JPanel gui = new JPanel(new GridLayout(0, 8, 0, 0)); gui.setBorder(new BevelBorder( BevelBorder.LOWERED, Color.GRAY.brighter(), Color.GRAY, Color.GRAY.darker(), Color.GRAY)); // set up a chess board addPiecesToContainer(gui, WHITE, BLACK, order, gradientFill); addPiecesToContainer(gui, BLACK, BLACK, pawnRow, gradientFill); addBlankLabelRow(gui, WHITE); addBlankLabelRow(gui, BLACK); addBlankLabelRow(gui, WHITE); addBlankLabelRow(gui, BLACK); addPiecesToContainer(gui, WHITE, WHITE, pawnRow, gradientFill); addPiecesToContainer(gui, BLACK, WHITE, order, gradientFill); JOptionPane.showMessageDialog( null, gui, "Chessboard", JOptionPane.INFORMATION_MESSAGE); JPanel tileSet = new JPanel(new GridLayout(0, 6, 0, 0)); tileSet.setOpaque(false); int[] tileSetOrder = new int[]{ KING, QUEEN, CASTLE, KNIGHT, BISHOP, PAWN }; addPiecesToContainer( tileSet, new Color(0, 0, 0, 0), BLACK, tileSetOrder, gradientFill); addPiecesToContainer( tileSet, new Color(0, 0, 0, 0), WHITE, tileSetOrder, gradientFill); int result = JOptionPane.showConfirmDialog( null, tileSet, "Save this tileset?", JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE); if (result == JOptionPane.OK_OPTION) { BufferedImage bi = new BufferedImage( tileSet.getWidth(), tileSet.getHeight(), BufferedImage.TYPE_INT_ARGB); Graphics g = bi.createGraphics(); tileSet.paint(g); g.dispose(); String gradientString = gradientFill ? "gradient" : "solid"; File f = new File( "chess-pieces-tileset-" + gradientString + ".png"); try { ImageIO.write(bi, "png", f); Desktop.getDesktop().open(f); } catch (IOException ex) { Logger.getLogger( ChessBoard.class.getName()).log( Level.SEVERE, null, ex); } } } }; SwingUtilities.invokeLater(r); } } 

Смотрите также

  • Разработанный из кода GlyphVector как видно из этого ответа .

  • Результатом является UGlys - Unicode Glyphs в GitHub.

Проблема, которую я вижу, заключается в том, что глифы были разработаны, чтобы легко отличить традиционные черно-белые шахматные фигуры. Обратите внимание также на изменение дизайна шрифтов. Вы можете создавать fragmentы с оттенком, которые сохраняют черно-белое различие с использованием цветового пространства HSB . Зеленые и голубые изображены ниже.

Изображение HSB

Приложение: Для справки, вот скриншот Mac OS X из приближения формы глифов @ Andrew. Обратите внимание на преимущество использования Эндрю RenderingHints при масштабировании изображения.

изображение формы

 import java.awt.Color; import java.awt.Container; import java.awt.Font; import java.awt.GridLayout; import java.util.Random; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.SwingUtilities; /** @see https://stackoverflow.com/a/18691662/230513 */ class ChessBoard { static Font font = new Font("Sans-Serif", Font.PLAIN, 64); static Random rnd = new Random(); public static void addUnicodeCharToContainer(String s, Container c) { JLabel l = new JLabel(s); l.setFont(font); l.setOpaque(true); c.add(l); } public static void addWhite(String s, Container c, Float h) { JLabel l = new JLabel(s); l.setFont(font); l.setOpaque(true); l.setForeground(Color.getHSBColor(h, 1, 1)); l.setBackground(Color.getHSBColor(h, 3 / 8f, 5 / 8f)); c.add(l); } public static void addBlack(String s, Container c, Float h) { JLabel l = new JLabel(s); l.setFont(font); l.setOpaque(true); l.setForeground(Color.getHSBColor(h, 5 / 8f, 3 / 8f)); l.setBackground(Color.getHSBColor(h, 7 / 8f, 7 / 8f)); c.add(l); } public static void main(String[] args) { Runnable r = new Runnable() { @Override public void run() { JPanel gui = new JPanel(new GridLayout(0, 6, 4, 4)); String[] white = { "\u2654", "\u2655", "\u2656", "\u2657", "\u2658", "\u2659" }; String[] black = { "\u265A", "\u265B", "\u265C", "\u265D", "\u265E", "\u265F" }; for (String piece : white) { addUnicodeCharToContainer(piece, gui); } for (String piece : white) { addWhite(piece, gui, 2 / 6f); } for (String piece : black) { addUnicodeCharToContainer(piece, gui); } for (String piece : black) { addBlack(piece, gui, 3 / 6f); } JOptionPane.showMessageDialog(null, gui); } }; SwingUtilities.invokeLater(r); } } 

В конце концов, я нашел, что создание спрайта – это более простой и простой способ решить проблему. Каждый fragment теперь соответствует графике внутри спрайта вместо символа / символа. Из-за этого части не могут быть изменены так же красиво, но это не самая большая сделка.

Идея Андрея Томпсона с GlyphVector казалась многообещающей, но вопрос о отделении внутреннего белого пространства от внешнего белого пространства остается сложным.

Одна (неэффективная) идея, которую я все еще имею, состоит в том, чтобы сделать тонну глифов из шахматной фигуры, начиная с очень небольшого размера шрифта и с белым цветом:

 for (int i = 1; i < BOARD_WIDTH/8) { JLabel chessPiece =new JLabel("\u2654"); chessPiece.setForeground(Color.white); chessPiece.setFont(new Font("Sans-Serif", Font.PLAIN, i)); add(chessPiece); } 

затем добавьте одну последнюю шахматную фигуру с черным передним планом:

 JLabel chessPiece =new JLabel("\u2654"); chessPiece.setForeground(Color.black); chessPiece.setFont(new Font("Sans-Serif", Font.PLAIN, BOARD_WIDTH/8))); add(chessPiece); 

Обратите внимание, что я не проверял это.

  • Удаление символов, отличных от ASCII, из файлов данных
  • В чем разница между utf8_general_ci и utf8_unicode_ci
  • Как я могу выполнять итерацию по кодовым точкам Unicode строки Java?
  • Отображать символы Юникода при преобразовании Html в Pdf
  • Каков полный диапазон для китайских иероглифов в Юникоде?
  • Разница между UTF-8 и UTF-16?
  • Действительные символы в имени classа Java
  • Каков правильный способ кодирования URL-символов Unicode?
  • Некоторые юникодовые альт-коды не работают
  • Unicode grep для Windows
  • Как я могу получить код символа Юникода?
  • Давайте будем гением компьютера.