Java:用图像中间字符串替换文本并与自动换行对齐
Java: Replace Text with Image Mid-String and align with Word Wrapping
我对 Java 编程还是有点陌生,对于大量文本转储感到抱歉。非常感谢您花时间阅读我当前的问题!
我正在开发软件,以使用 Java Swing 帮助加快棋盘游戏的设计过程。它为游戏获取卡片的 CSV 文件,让您通过放置每列将在卡片上呈现的位置来构建虚拟卡片,然后从这些位置自动生成 CSV 中的所有卡片。
许多纸牌游戏都有代表游戏中某些东西的符号,我希望能够将它们插入字符串中间。我现在可以用一个符号替换整个字符串;因为它检查 string == a known rule
是否改为绘制符号。但是,我不知道如何在字符串中搜索一组特定的字符。如果它找到它们,将它们从字符串中删除,然后在它的位置绘制相应的符号。魔法卡上的法术力符号就是一个很好的例子:https://cdn0.vox-cdn.com/uploads/chorus_asset/file/8039357/C0cIVZ5.png
所以字符串可以是:Gain 1 {GOLD} at the start of each tun.
它需要使用规则 class 将 {GOLD}
替换为黄金图片,其中包含要查找的字符串和要替换为的缓冲图像。
我希望它能在不对符号大小使用硬性限制的情况下工作,但这不是硬性要求。最好的解决方案是缩放符号,使其高度与文本相同。
此方法采用缓冲图像(没有文本的卡片)并将文本覆盖在卡片顶部。
//Will modify the buffered image with the placeables
static public BufferedImage buildCard(BufferedImage start, int whichCardID) {
//Copy so we don't lose our template
BufferedImage ni = deepCopy(start); //ni = new image
//The headers of the document
String[] headers = MainWindow.loadedCards.get(0);
//For each placeable, write down it's text
for(int i=0; i<headers.length; i++) {
//get current header
String currentHeader = headers[i];
//The Text
String theText = MainWindow.loadedCards.get(whichCardID)[i];
//The Settings
PlaceableSettings theSettings = MainWindow.placeableSettings.get(currentHeader);
//Make the change to the image
//ni = writeToImage(ni, theText, theSettings);
///////New below
boolean foundRule = false;
//see if we have a rule to draw a graphic instead
for(RuleMaster.Rule r : RuleMaster.rules) {
if(r.keyword.equals(theText)) {
//there is a rule for this!
ni = drawRuleToImage(ni, r, theSettings);
foundRule = true; //so we don't draw the current text
}
}
//No rules for this
//Make the change to the image if there are no rules
if(foundRule == false)
ni = writeToImage(ni, theText, theSettings);
}
return ni;
}
//Takes a buffered image and writes text into it at the location given
static public BufferedImage writeToImage(BufferedImage old, String text, PlaceableSettings setts) {
//make new blank graphics
BufferedImage bi = new BufferedImage(old.getWidth(), old.getHeight(), BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = bi.createGraphics();
//write old image to it
g2d.drawImage(old, 0, 0, null); //null was set to "this" when this was not static | Note ion case this breaks
//write text on it
g2d.setPaint(setts.getColor());
g2d.setFont(setts.getFont());
//Setup word wrap
FontMetrics fm = g2d.getFontMetrics(setts.getFont());
// int rightSideBuffer = bi.getWidth() - 10;
//Rectangle2D rect = fm.getStringBounds(text, setts.getX(), rightSideBuffer, g2d); // try just -'ing the x slot from the width below
Rectangle2D rect = fm.getStringBounds(text, g2d); //this gets you the bounds for the entire image, need to remove space for x,y position
//TODO: Problem: this is always length 1
//Solution! No auto wrap, let the person define it as a setting
@SuppressWarnings("unchecked")
List<String> textList=StringUtils.wrap(text, fm, setts.getPixelsTillWrap() ); //width counted in # of characters
//g2d.drawString(text, setts.getX(), setts.getY()); //old draw with no wrap
for(int i=0; i< textList.size(); i++) {
g2d.drawString(textList.get(i), setts.getX(), setts.getY() + ( i*(setts.getFont().getSize() + 2/*Buffer*/)));
}
//!!DEBUG
if(EntryPoint.DEBUG) {
Random r = new Random();
g2d.setPaint(Color.RED);
g2d.drawString(Integer.toString(textList.size()), 100, 50+r.nextInt(250));
g2d.setPaint(Color.GREEN);
g2d.drawString(Double.toString(rect.getWidth()), 200, 50+r.nextInt(250));
g2d.setPaint(Color.PINK);
//g2d.drawString(Integer.toString(( ((int) rect.getWidth()) - setts.getX())), 100, 250+r.nextInt(100));
}
//cleanup
g2d.dispose();
return bi;
}
//Takes a buffered image and draws an image on it at the location given
static public BufferedImage drawRuleToImage(BufferedImage old, RuleMaster.Rule rule, PlaceableSettings theSettings) {
//make new blank graphics
BufferedImage bi = new BufferedImage(old.getWidth(), old.getHeight(), BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = bi.createGraphics();
//write old image to it
g2d.drawImage(old, 0, 0, null); //null was set to "this" when this was not static | Note ion case this breaks
g2d.drawImage(rule.image, theSettings.getX(), theSettings.getY(), null);
//cleanup
g2d.dispose();
//System.exit(1);
return bi;
}
每个规则只包含要替换的字符串和要替换的图像。
static public class Rule{
//Text to look for
String keyword;
//image to replace it with
BufferedImage image;
public Rule (String key, BufferedImage img) {
keyword = key;
image = img;
}
}
我正在尝试将其设计为供多人使用的工具,因此文本应该能够匹配用户添加的任何内容;尽管我目前的流程是使用诸如“{M}”之类的字符串,这可能是一个标准。
另一个大障碍是文本可以在卡片上换行,这意味着字符串和图像需要在提供的范围内换行。
编辑 1:
有一些想法,我将尝试这种方法。在绘制 'next' 一半的字符串时仍然会发现边界可能存在问题;但我相信这可能有效。
//If found a rule mid text:
//Split string in 2 at the rule match: strings 'start', and 'next'
//Calculate x and y for symbol
//x is the # of characters in ('start' % the word wrap width) +1 as the symbol is the next character, then multiply that by the character size of the font
//y is the integer of dividing the # of characters in 'start' by word wrap width multiplied by the font height
//Draw Start of String
//Draw symbol
//next x = sym.x + sym width //TODO next (x,y) math
我能够通过根据文本大小提前变形来解决问题。通过使用已知大小的图像,可以提前知道如何正确完成包装。
然后我遍历每一行。我看起来在将被替换的文本上的字符串中做了一个拆分。我像往常一样绘制了字符串的第一部分。使用 int pixelWidth = ni.getGraphics().getFontMetrics().stringWidth(splitString[j]);
计算字符串的宽度。然后在同一个Y处绘制图片,但是在X上加上了之前字符串的宽度。然后在X上加上图片当前的宽度,继续循环;根据需要绘制图像和字符串。
我对 Java 编程还是有点陌生,对于大量文本转储感到抱歉。非常感谢您花时间阅读我当前的问题!
我正在开发软件,以使用 Java Swing 帮助加快棋盘游戏的设计过程。它为游戏获取卡片的 CSV 文件,让您通过放置每列将在卡片上呈现的位置来构建虚拟卡片,然后从这些位置自动生成 CSV 中的所有卡片。
许多纸牌游戏都有代表游戏中某些东西的符号,我希望能够将它们插入字符串中间。我现在可以用一个符号替换整个字符串;因为它检查 string == a known rule
是否改为绘制符号。但是,我不知道如何在字符串中搜索一组特定的字符。如果它找到它们,将它们从字符串中删除,然后在它的位置绘制相应的符号。魔法卡上的法术力符号就是一个很好的例子:https://cdn0.vox-cdn.com/uploads/chorus_asset/file/8039357/C0cIVZ5.png
所以字符串可以是:Gain 1 {GOLD} at the start of each tun.
它需要使用规则 class 将 {GOLD}
替换为黄金图片,其中包含要查找的字符串和要替换为的缓冲图像。
我希望它能在不对符号大小使用硬性限制的情况下工作,但这不是硬性要求。最好的解决方案是缩放符号,使其高度与文本相同。
此方法采用缓冲图像(没有文本的卡片)并将文本覆盖在卡片顶部。
//Will modify the buffered image with the placeables
static public BufferedImage buildCard(BufferedImage start, int whichCardID) {
//Copy so we don't lose our template
BufferedImage ni = deepCopy(start); //ni = new image
//The headers of the document
String[] headers = MainWindow.loadedCards.get(0);
//For each placeable, write down it's text
for(int i=0; i<headers.length; i++) {
//get current header
String currentHeader = headers[i];
//The Text
String theText = MainWindow.loadedCards.get(whichCardID)[i];
//The Settings
PlaceableSettings theSettings = MainWindow.placeableSettings.get(currentHeader);
//Make the change to the image
//ni = writeToImage(ni, theText, theSettings);
///////New below
boolean foundRule = false;
//see if we have a rule to draw a graphic instead
for(RuleMaster.Rule r : RuleMaster.rules) {
if(r.keyword.equals(theText)) {
//there is a rule for this!
ni = drawRuleToImage(ni, r, theSettings);
foundRule = true; //so we don't draw the current text
}
}
//No rules for this
//Make the change to the image if there are no rules
if(foundRule == false)
ni = writeToImage(ni, theText, theSettings);
}
return ni;
}
//Takes a buffered image and writes text into it at the location given
static public BufferedImage writeToImage(BufferedImage old, String text, PlaceableSettings setts) {
//make new blank graphics
BufferedImage bi = new BufferedImage(old.getWidth(), old.getHeight(), BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = bi.createGraphics();
//write old image to it
g2d.drawImage(old, 0, 0, null); //null was set to "this" when this was not static | Note ion case this breaks
//write text on it
g2d.setPaint(setts.getColor());
g2d.setFont(setts.getFont());
//Setup word wrap
FontMetrics fm = g2d.getFontMetrics(setts.getFont());
// int rightSideBuffer = bi.getWidth() - 10;
//Rectangle2D rect = fm.getStringBounds(text, setts.getX(), rightSideBuffer, g2d); // try just -'ing the x slot from the width below
Rectangle2D rect = fm.getStringBounds(text, g2d); //this gets you the bounds for the entire image, need to remove space for x,y position
//TODO: Problem: this is always length 1
//Solution! No auto wrap, let the person define it as a setting
@SuppressWarnings("unchecked")
List<String> textList=StringUtils.wrap(text, fm, setts.getPixelsTillWrap() ); //width counted in # of characters
//g2d.drawString(text, setts.getX(), setts.getY()); //old draw with no wrap
for(int i=0; i< textList.size(); i++) {
g2d.drawString(textList.get(i), setts.getX(), setts.getY() + ( i*(setts.getFont().getSize() + 2/*Buffer*/)));
}
//!!DEBUG
if(EntryPoint.DEBUG) {
Random r = new Random();
g2d.setPaint(Color.RED);
g2d.drawString(Integer.toString(textList.size()), 100, 50+r.nextInt(250));
g2d.setPaint(Color.GREEN);
g2d.drawString(Double.toString(rect.getWidth()), 200, 50+r.nextInt(250));
g2d.setPaint(Color.PINK);
//g2d.drawString(Integer.toString(( ((int) rect.getWidth()) - setts.getX())), 100, 250+r.nextInt(100));
}
//cleanup
g2d.dispose();
return bi;
}
//Takes a buffered image and draws an image on it at the location given
static public BufferedImage drawRuleToImage(BufferedImage old, RuleMaster.Rule rule, PlaceableSettings theSettings) {
//make new blank graphics
BufferedImage bi = new BufferedImage(old.getWidth(), old.getHeight(), BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = bi.createGraphics();
//write old image to it
g2d.drawImage(old, 0, 0, null); //null was set to "this" when this was not static | Note ion case this breaks
g2d.drawImage(rule.image, theSettings.getX(), theSettings.getY(), null);
//cleanup
g2d.dispose();
//System.exit(1);
return bi;
}
每个规则只包含要替换的字符串和要替换的图像。
static public class Rule{
//Text to look for
String keyword;
//image to replace it with
BufferedImage image;
public Rule (String key, BufferedImage img) {
keyword = key;
image = img;
}
}
我正在尝试将其设计为供多人使用的工具,因此文本应该能够匹配用户添加的任何内容;尽管我目前的流程是使用诸如“{M}”之类的字符串,这可能是一个标准。
另一个大障碍是文本可以在卡片上换行,这意味着字符串和图像需要在提供的范围内换行。
编辑 1: 有一些想法,我将尝试这种方法。在绘制 'next' 一半的字符串时仍然会发现边界可能存在问题;但我相信这可能有效。
//If found a rule mid text:
//Split string in 2 at the rule match: strings 'start', and 'next'
//Calculate x and y for symbol
//x is the # of characters in ('start' % the word wrap width) +1 as the symbol is the next character, then multiply that by the character size of the font
//y is the integer of dividing the # of characters in 'start' by word wrap width multiplied by the font height
//Draw Start of String
//Draw symbol
//next x = sym.x + sym width //TODO next (x,y) math
我能够通过根据文本大小提前变形来解决问题。通过使用已知大小的图像,可以提前知道如何正确完成包装。
然后我遍历每一行。我看起来在将被替换的文本上的字符串中做了一个拆分。我像往常一样绘制了字符串的第一部分。使用 int pixelWidth = ni.getGraphics().getFontMetrics().stringWidth(splitString[j]);
计算字符串的宽度。然后在同一个Y处绘制图片,但是在X上加上了之前字符串的宽度。然后在X上加上图片当前的宽度,继续循环;根据需要绘制图像和字符串。