如何在运行时制作动态图像?

发布于 2024-12-09 10:43:20 字数 358 浏览 0 评论 0原文

我正在开发一款基于 NetBeans 平台的纸牌游戏,并且正在努力理解动态图像。为什么是动态的?好吧,我希望卡片在运行时根据页面的更改(即名称、文本、成本等)进行调整。

我的第一个破解是创建一个组件(JPanel),其中预先放置了标签,我根据卡值加载文本/图像。这似乎工作得很好,但当我想到某些页面在以后的版本中具有不同的外观(意味着并非所有内容都在同一个地方)时,它就变得很麻烦。

所以我试图了解如何基于某种模板来做到这一点。

有什么想法吗?

有一个后续问题:JList of cards?

I'm working on a card game based on the NetBeans platform and I'm struggling to get my head around dynamic images. Why dynamic? Well I want the cards to adjust at run time to changes to the page (i.e. name, text, cost, etc).

My first hack at it was creating a component (JPanel) with labels pre-placed where I loaded the text/image based on the card values. That seems to work fine but then it became troublesome when I thought about some pages having a different look in later editions (meaning not everything would be on the same place).

So I'm trying to get an idea about ways to do this based on some kind of template.

Any idea?

There's a follow-up question at: JList of cards?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

月朦胧 2024-12-16 10:43:20

最后,我有时间回到这个问题,并能够找到一种使用 Java 2D 教程

这些图片与我将在应用程序中使用的图片并不接近,但可以作为概念证明。

封装javaapplication3;

导入java.awt.*;导入 java.awt.font.FontRenderContext;进口
java.awt.font.LineBreakMeasurer;导入 java.awt.font.TextAttribute;
导入 java.awt.font.TextLayout;导入java.awt.image.BufferedImage;
导入java.io.File;导入java.io.IOException;进口
java.net.MalformedURLException;导入java.net.URL;进口
java.text.AttributedCharacterIterator;进口
java.text.AttributedString;导入java.util.ArrayList;进口
java.util.HashMap;导入java.util.logging.Level;进口
java.util.logging.Logger;导入javax.imageio.ImageIO;

/** * * @author Javier A. Ortiz Bultrón
*/ 公共类DefaultImageManager {

<前><代码>/**
* @param args 命令行参数
*/
公共静态无效主(字符串[] args){
尝试 {
// TODO 代码应用逻辑在这里
DefaultImageManager 管理器 = new DefaultImageManager();
URL url = DefaultImageManager.class.getResource("weather-rain.png");
manager.getLayers().add(ImageIO.read(url));
url = DefaultImageManager.class.getResource("天气-太阳.png");
manager.getLayers().add(ImageIO.read(url));
manager.addText(new Font("Arial", Font.PLAIN, 10), "很多人相信文森特·梵高画出了他最好的作品"
+“他在普罗旺斯度过的两年期间。这里是他的地方”
+“画了《星夜》——有些人认为这是他最伟大的作品”
+“所有的作品。然而,随着他的艺术才华达到新的水平”
+“在普罗旺斯的高度,他的身心健康直线下降。”,
200, 150, 新点(0, 0));
管理器.生成();
} catch (MalformedURLException ex) {
Logger.getLogger(DefaultImageManager.class.getName()).log(Level.SEVERE,

空,例如);
} catch (IOException ex) {
Logger.getLogger(DefaultImageManager.class.getName()).log(Level.SEVERE,
空,例如);
}
}
/**
* 用于创建最终图像的图层
*/
私有 ArrayList 层 = new ArrayList();
私有 ArrayList textLayers = new ArrayList();

<前><代码>/**
* @return 图层
*/
公共ArrayList获取图层(){
返回层;
}

私有尺寸 getMaxSize() {
int 宽度 = 0,高度 = 0;
for (BufferedImage img : getLayers()) {
if (img.getWidth() > 宽度) {
宽度 = img.getWidth();
}
if (img.getHeight() > 高度) {
高度 = img.getHeight();
}
}
返回新尺寸(宽度,高度);
}

public void addText(Font font, String text, int height, int width, Point location) {
BufferedImage 文本图像 = new BufferedImage(宽度, 高度,
BufferedImage.TYPE_INT_ARGB);
HashMap地图=
new HashMap();
map.put(TextAttribute.FAMILY, font.getFamily());
map.put(TextAttribute.SIZE, font.getSize());
map.put(TextAttribute.FOREGROUND, Color.BLACK);
AttributedString aString = new AttributedString(文本, 地图);
AttributedCharacterIterator 段落 = aString.getIterator();
// 段落中第一个字符的索引。
int paragraphStart = paragraph.getBeginIndex();
// 段落结尾后第一个字符的索引。
int paragraphEnd = paragraph.getEndIndex();
Graphics2D 图形 = textImage.createGraphics();
FontRenderContext frc = Graphics.getFontRenderContext();
// 用于对段落进行换行的 LineBreakMeasurer。
LineBreakMeasurer lineMeasurer = new LineBreakMeasurer(paragraph, frc);
// 将分隔宽度设置为组件的宽度。
浮动中断宽度=宽度;
浮动drawPosY = 0;
// 将位置设置为段落中第一个字符的索引。
lineMeasurer.setPosition(paragraphStart);

// 获取行,直到显示整个段落。
while (lineMeasurer.getPosition() < paragraphEnd) {
// 检索下一个布局。更聪明的程序也会缓存
// 这些布局直到重新调整组件大小。
TextLayout 布局 = lineMeasurer.nextLayout(breakWidth);

// 计算笔 x 位置。如果该段落是从右到左的,我们
// 将 TextLayouts 与面板的右边缘对齐。
// 注意:此示例中的英文文本不会发生这种情况。
// 注意:drawPosX 始终是放置文本左侧的位置。
浮动drawPosX =布局.isLeftToRight()
? 0:breakWidth -layout.getAdvance();

// 按布局的上升方向移动 y 坐标。
drawPosY +=layout.getAscent();

// 在 (drawPosX, drawPosY) 处绘制 TextLayout。
布局.draw(图形,drawPosX,drawPosY);

// 移动 y 坐标,为下一个布局做准备。
drawPosY +=layout.getDescent() +layout.getLeading();
}
getTextLayers().add(textImage);
}

公共无效生成()抛出IOException {
尺寸大小 = getMaxSize();
BufferedImage FinalImage = new BufferedImage(size.width, size.height,
BufferedImage.TYPE_INT_ARGB);
for (BufferedImage img : getLayers()) {
FinalImage.createGraphics().drawImage(img,
0, 0, 尺寸.宽度, 尺寸.高度,
0, 0, img.getWidth(null),
img.getHeight(null),
无效的);
}
for(BufferedImage 文本: getTextLayers()){
FinalImage.createGraphics().drawImage(文本,
0, 0, 文本.getWidth(), 文本.getHeight(),
0, 0, 文本.getWidth(null),
文本.getHeight(null),
无效的);
}
文件输出文件 = new File("saved.png");
ImageIO.write(finalImage, "png", 输出文件);
}

/**
* @return 文本图层
*/
公共ArrayList获取文本图层(){
返回文本图层;
}

/**
* @param textLayers 要设置的textLayers
*/
公共无效setTextLayers(ArrayListtextLayers){
this.textLayers = textLayers;
} }

它仍然需要一些改进,特别是在文本的位置上,但它是有效的。我想我可以实现一个 xml 格式来存储所有这些信息,这样就可以轻松配置。在下面的示例中,太阳被绘制在雨的顶部,文本位于所有这些的顶部。对于我的应用程序,每一层将一起构建我想要的页面。

这是我使用的图像:
在此处输入图像描述
在此处输入图像描述

最终结果:

在此处输入图像描述

Finally I got some time to get back to this and was able to figure out a way using Java 2D tutorial.

The pictures are not near what I will use in my application but serves as proof of concept.

package javaapplication3;

import java.awt.*; import java.awt.font.FontRenderContext; import
java.awt.font.LineBreakMeasurer; import java.awt.font.TextAttribute;
import java.awt.font.TextLayout; import java.awt.image.BufferedImage;
import java.io.File; import java.io.IOException; import
java.net.MalformedURLException; import java.net.URL; import
java.text.AttributedCharacterIterator; import
java.text.AttributedString; import java.util.ArrayList; import
java.util.HashMap; import java.util.logging.Level; import
java.util.logging.Logger; import javax.imageio.ImageIO;

/** * * @author Javier A. Ortiz Bultrón
*/ public class DefaultImageManager {

/**
 * @param args the command line arguments
 */
public static void main(String[] args) {
    try {
        // TODO code application logic here
        DefaultImageManager manager = new DefaultImageManager();
        URL url = DefaultImageManager.class.getResource("weather-rain.png");
        manager.getLayers().add(ImageIO.read(url));
        url = DefaultImageManager.class.getResource("weather-sun.png");
        manager.getLayers().add(ImageIO.read(url));
        manager.addText(new Font("Arial", Font.PLAIN, 10), "Many people believe that Vincent van Gogh painted his best works "
                + "during the two-year period he spent in Provence. Here is where he "
                + "painted The Starry Night--which some consider to be his greatest "
                + "work of all. However, as his artistic brilliance reached new "
                + "heights in Provence, his physical and mental health plummeted. ",
                200, 150, new Point(0, 0));
        manager.generate();
    } catch (MalformedURLException ex) {
        Logger.getLogger(DefaultImageManager.class.getName()).log(Level.SEVERE,

null, ex);
} catch (IOException ex) {
Logger.getLogger(DefaultImageManager.class.getName()).log(Level.SEVERE,
null, ex);
}
}
/**
* Layers used to create the final image
*/
private ArrayList layers = new ArrayList();
private ArrayList textLayers = new ArrayList();

/**
 * @return the layers
 */
public ArrayList<BufferedImage> getLayers() {
    return layers;
}

private Dimension getMaxSize() {
    int width = 0, height = 0;
    for (BufferedImage img : getLayers()) {
        if (img.getWidth() > width) {
            width = img.getWidth();
        }
        if (img.getHeight() > height) {
            height = img.getHeight();
        }
    }
    return new Dimension(width, height);
}

public void addText(Font font, String text, int height, int width, Point location) {
    BufferedImage textImage = new BufferedImage(width, height,
            BufferedImage.TYPE_INT_ARGB);
    HashMap<TextAttribute, Object> map =
            new HashMap<TextAttribute, Object>();
    map.put(TextAttribute.FAMILY, font.getFamily());
    map.put(TextAttribute.SIZE, font.getSize());
    map.put(TextAttribute.FOREGROUND, Color.BLACK);
    AttributedString aString = new AttributedString(text, map);
    AttributedCharacterIterator paragraph = aString.getIterator();
    // index of the first character in the paragraph.
    int paragraphStart = paragraph.getBeginIndex();
    // index of the first character after the end of the paragraph.
    int paragraphEnd = paragraph.getEndIndex();
    Graphics2D graphics = textImage.createGraphics();
    FontRenderContext frc = graphics.getFontRenderContext();
    // The LineBreakMeasurer used to line-break the paragraph.
    LineBreakMeasurer lineMeasurer = new LineBreakMeasurer(paragraph, frc);
    // Set break width to width of Component.
    float breakWidth = width;
    float drawPosY = 0;
    // Set position to the index of the first character in the paragraph.
    lineMeasurer.setPosition(paragraphStart);

    // Get lines until the entire paragraph has been displayed.
    while (lineMeasurer.getPosition() < paragraphEnd) {
        // Retrieve next layout. A cleverer program would also cache
        // these layouts until the component is re-sized.
        TextLayout layout = lineMeasurer.nextLayout(breakWidth);

        // Compute pen x position. If the paragraph is right-to-left we
        // will align the TextLayouts to the right edge of the panel.
        // Note: this won't occur for the English text in this sample.
        // Note: drawPosX is always where the LEFT of the text is placed.
        float drawPosX = layout.isLeftToRight()
                ? 0 : breakWidth - layout.getAdvance();

        // Move y-coordinate by the ascent of the layout.
        drawPosY += layout.getAscent();

        // Draw the TextLayout at (drawPosX, drawPosY).
        layout.draw(graphics, drawPosX, drawPosY);

        // Move y-coordinate in preparation for next layout.
        drawPosY += layout.getDescent() + layout.getLeading();
    }
    getTextLayers().add(textImage);
}

public void generate() throws IOException {
    Dimension size = getMaxSize();
    BufferedImage finalImage = new BufferedImage(size.width, size.height,
            BufferedImage.TYPE_INT_ARGB);
    for (BufferedImage img : getLayers()) {
        finalImage.createGraphics().drawImage(img,
                0, 0, size.width, size.height,
                0, 0, img.getWidth(null),
                img.getHeight(null),
                null);
    }
    for(BufferedImage text: getTextLayers()){
        finalImage.createGraphics().drawImage(text,
                0, 0, text.getWidth(), text.getHeight(),
                0, 0, text.getWidth(null),
                text.getHeight(null),
                null);
    }
    File outputfile = new File("saved.png");
    ImageIO.write(finalImage, "png", outputfile);
}

/**
 * @return the textLayers
 */
public ArrayList<BufferedImage> getTextLayers() {
    return textLayers;
}

/**
 * @param textLayers the textLayers to set
 */
public void setTextLayers(ArrayList<BufferedImage> textLayers) {
    this.textLayers = textLayers;
} }

It still needs some refining specially on the placement of the text but it works. I guess I can implement a xml format to store all this information so is easily configurable. In the example below suns are drawn on top of rain, and the text is on top of all that. For my application each layer will build together the page I want.

Here are the images I used:
enter image description here
enter image description here

And the final result:

enter image description here

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文