如何在运行时制作动态图像? [英] How to make a dynamic image at run time?

查看:246
本文介绍了如何在运行时制作动态图像?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用基于NetBeans平台的卡片游戏,我正在努力使我的头脑围绕动态图像。为什么动态?那么我想让卡在运行时调整到页面的更改(即名称,文字,成本等)。



我的第一个黑客是创建一个组件(JPanel),其中标签预先放置在基于卡值加载文本/图像的位置。这似乎工作正常,但是当我想到一些页面在后来的版本中有不同的看法(这意味着并不是所有的东西都在同一个地方)变得很麻烦。



所以我想了解一些基于某种模板的方法。



任何想法?



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

解决方案

最后我有一段时间回到这一点,能够找出一种使用 Java 2D教程



图片不在我将在我的应用程序中使用,但作为概念证明。


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. OrtizBultrón
* / public class DefaultImageManager {

  / ** 
* @param args命令行参数
* /
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),很多人认为文森特梵高在他花了两年的时间里画了他最好的作品
+普罗旺斯这里是他的
+画的星夜 - 有些人认为是他最伟大的
+的工作,但是,随着他的艺术光辉达到了新的
+高点在普罗旺斯,他的身体和心理健康状况急剧下降,
200,150,新点(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);
}
}
/ **
*用于创建最终图像的图层
* /
private ArrayList layers = new ArrayList();
private ArrayList textLayers = new ArrayList();

  / ** 
* @返回图层
* /
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();
//段落中第一个字符的索引。
int paragraphStart = paragraph.getBeginIndex();
//段落结束后第一个字符的索引。
int paragraphEnd = paragraph.getEndIndex();
Graphics2D graphics = textImage.createGraphics();
FontRenderContext frc = graphics.getFontRenderContext();
// LineBreakMeasurer用于换行段落。
LineBreakMeasurer lineMeasurer = new LineBreakMeasurer(paragraph,frc);
//将Break的宽度设置为Component的宽度。
float breakWidth = width;
float drawPosY = 0;
//将位置设置为段落中第一个字符的索引。
lineMeasurer.setPosition(paragraphStart);

//获取行直到整个段落被显示。
while(lineMeasurer.getPosition()< paragraphEnd){
//检索下一个布局。清理程序还将缓存
//这些布局,直到组件重新调整大小。
TextLayout layout = lineMeasurer.nextLayout(breakWidth);

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

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

//在(drawPosX,drawPosY)上绘制TextLayout。
layout.draw(graphics,drawPosX,drawPosY);

//移动y坐标准备下一个布局。
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);
}
(BufferedImage text:getTextLayers()){
finalImage.createGraphics()。drawImage(text,
0,0,text.getWidth(),text.getHeight (),
0,0,text.getWidth(null),
text.getHeight(null),
null);
}
文件outputfile = new File(saved.png);
ImageIO.write(finalImage,png,outputfile);
}

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

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


文本的放置,但它的作品。我想我可以实现一个xml格式来存储所有这些信息,以便易于配置。在下面的例子中,太阳是在雨水之上绘制的,文字是最重要的。对于我的应用程序,每个层都将构建我想要的页面。



以下是我使用的图像:



最终结果:




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?

解决方案

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:

And the final result:

这篇关于如何在运行时制作动态图像?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆