gpt4 book ai didi

java - 从 ServletOutputStream 输出 GIF

转载 作者:搜寻专家 更新时间:2023-11-01 03:04:23 28 4
gpt4 key购买 nike

我正在编写一个动态生成 GIF 文件的端点。我会从头开始。

我有一个名为 Function 的类(class)它像一个抽象类一样工作,我有几个类,在这个例子中 AddFunction ,代表一小块功能。在这种情况下,AddFunction将一些数字相加。当到达终点时,AddFunction的ID传递给它(它可以是任何,在这个例子中它是 add 函数)。 Controller 中的代码如下:

/**
* Returns the image for a function
*/
@RequestMapping(value = "/function/{functionId}/image.gif", produces = "image/gif")
public void getImage(@PathVariable(value = "functionId") String functionId, HttpServletResponse response) throws IOException {
Function function = functionService.getFunction(Integer.valueOf(functionId));

Logger logger = Logger.getLogger(FunctionController.class);

ServletOutputStream servOut = response.getOutputStream();

// Uses default values if you pass in nulls.
function.getImage(servOut, null, null);

servOut.flush();
servOut.close();
}

一、 Function是通过它的 ID 找到的。我已经检查过,并找到了正确的功能。这段代码需要一些验证(例如检查传入的 id 是否为有效数字),但我稍后会讨论。然后我获取 servlet 输出流并将其传递给 getImage函数的方法。此方法生成描述该函数的 GIF。此代码如下所示:
public void getImage(OutputStream out, String staticContent, String changedContent) throws IOException {
String[] data = {"2", "+", "2", "=", "4"};

Logger logger = Logger.getLogger(AddFunction.class);

logger.info("Getting the add image.");

ImageUtils.writeSequenceToImage(ImageIO.createImageOutputStream(out), data, 5, Constants.IMAGE_HEIGHT / 2);
}

如您所见,它忽略了这些值,目前正在使用库存数据。它创建一个值数组。这些值中的每一个都出现在 GIF 的每一帧中。所以我要做的就是拿 ServletOutputStream我使用 ImageIO.createImageOutputStreamImageOutputStream 包裹它目的。这是传入 writeSequenceToImage 的时候我自己的方法 ImageUtils类(class)。最后两个值是写入位置的坐标。在这种情况下,图像的垂直中间,在最左边。 writeSequenceToImage 的代码方法如下:
public static void writeSequenceToImage(ImageOutputStream out, String[] contentList, int x, int y) throws IOException {
StringBuilder dataBuilder = new StringBuilder();

Test test = new Test(out, BufferedImage.TYPE_INT_RGB, 500, true);

Logger logger = Logger.getLogger(ImageUtils.class);

logger.info("Writing sequence to image.");

for (String content : contentList) {
dataBuilder.append(content);

logger.info("writing " + dataBuilder.toString() + " to the gif.");

test.writeToSequence(generateAndWriteToImage(dataBuilder.toString(), x, y));
}
}

在这段代码中,我使用了类 Test (临时名称),其中包含将数据写入 GIF 文件的代码。我在这里所做的只是循环并将每个值添加到 GIF 中的一个帧中。类(class)代码 Test可以找到 here .我所做的是建立字符串,因此在我们的示例中,日志将输出:
2014-12-31 14:37:15 INFO  ImageUtils:48 - Writing sequence to image.
2014-12-31 14:37:15 INFO ImageUtils:53 - writing 2 to the gif.
2014-12-31 14:37:15 INFO ImageUtils:53 - writing 2+ to the gif.
2014-12-31 14:37:15 INFO ImageUtils:53 - writing 2+2 to the gif.
2014-12-31 14:37:15 INFO ImageUtils:53 - writing 2+2= to the gif.
2014-12-31 14:37:15 INFO ImageUtils:53 - writing 2+2=4 to the gif.

这将在 GIF 的每一帧中显示它构建字符串的外观。现在,我将其写入 GIF 并希望它直接被插入 ServletOutputStream ,仅当我尝试使用以下 HTML 引用它时:
<div class="panel columns large-12" ng-show="selectedFunction">
<h2>{{selectedFunction.name}}</h2>

<p>{{selectedFunction.description}}</p>

<p>This function expects a {{selectedFunction.expectedParameterType}} as a parameter.</p>

<p>This function will return a {{selectedFunction.expectedReturnType}}</p>

<img src="/autoalgorithm/functions/function/{{selectedFunction.id}}/image.gif" alt="{{selectedFunction.name}}"/>
</div>

我在 Chrome 中看到以下数据返回:

Data Response

我在我的页面上没有看到任何图像:

View

我试过的

我试图看看回来的东西的大小。为此,我更换了 ServletOutputStreamByteArrayOutputStream所以我可以得到数据的大小。如果我这样做,我的代码如下所示:
/**
* Returns the image for a function
*/
@RequestMapping(value = "/function/{functionId}/image.gif", produces = "image/gif")
public @ResponseBody byte[] getImage(@PathVariable(value = "functionId") String functionId, HttpServletResponse response) throws IOException {
Function function = functionService.getFunction(Integer.valueOf(functionId));

Logger logger = Logger.getLogger(FunctionController.class);

ByteArrayOutputStream baos = new ByteArrayOutputStream();

// Uses default values if you pass in nulls.
function.getImage(baos, null, null);

logger.info("The number of bytes returned is " + baos.toByteArray().length);

return baos.toByteArray();
}

和日志输出:
2014-12-31 15:34:09 INFO  FunctionController:85 - The number of bytes returned is 0

所以这告诉我它也没有被写入。所以我改变了我的方法并重构了代码,所以我保留了对 ImageOutputStream 的引用。在我的 Controller 中。这意味着我可以完全控制对象,所以现在输出的日志:
2014-12-31 15:39:56 INFO  FunctionController:85 - The number of bytes returned is 2708

这是令人鼓舞的! 2KB 听起来很适合非常简单的 GIF。但是,当我查看 Google 的回复时,类似的故事:

ios response

虽然这次它有内容长度,但没有预览可用,图像仍然没有出现。

我想知道这里有没有人解决过类似的问题?我怀疑这与 GIF 的编码有关,但是 ImageIO不支持从一个流到另一个流的转换,只支持从一个 BufferedImage键入另一个。所以我使用了 ImageIO.read将其读入 BufferedImage 的方法并使用 ImageIO.write把它写成 gifServletOutputStream .这产生了以下错误:
java.lang.IllegalArgumentException: image == null!

在这一点上,我被难住了。我希望一组新鲜的眼睛可以帮助我。有没有人有任何想法?

最佳答案

正如评论中已经指出的,您的问题有点不简洁,但我会尝试向您展示它是如何工作的。

首先尝试以下操作:

@RequestMapping(value = "/function/{functionId}/image.gif", produces = "image/gif")
public void getImage(@PathVariable(value = "functionId") String functionId, HttpServletResponse response) throws IOException {

BufferedImage firstImage = ImageIO.read(new File("/bla.jpg"));
response.setContentType("image/gif"); // this should happen automatically

ImageIO.write(firstImage, "gif", response.getOutputStream());
response.getOutputStream().close();
}

将一些名为 bla.jpg 的文件放在您的根目录中或更改某个现有图像文件的路径(也可以是 GIF)。确保您至少具有读取访问权限。

这应该在任何情况下都有效,无论是 jpg 还是 gif 文件。如果这不起作用,则您的 Spring 配置可能有问题。你应该排除这种情况。

如果这有效,您可以使用您的方法 generateAndWriteToImage() 替换 ImageIO.read(new File("/bla.jpg")); 。你应该完成。

现在,我不知道你的 generateAndWriteToImage() 方法做了什么,但我假设它创建了一个 BufferedImage 的实例,将一些文本写入图像并返回它。
像这样的东西:
public static BufferedImage generateAndWriteToImage(String string, int x, int y) {

BufferedImage image = new BufferedImage(x,y,BufferedImage.TYPE_INT_RGB);
Graphics g = image.getGraphics();
g.setPaintMode();
g.setFont(g.getFont().deriveFont(30f));
g.drawString(string, 100, 100);
g.dispose();
return image;
}

如果您创建类型为 BufferedImage.TYPE_INT_RGB 的图像,这应该不会导致任何问题。

TL;DR 您自己已经发现的另一件事是,稍微重构一下就可以关闭 ImageOutputStream

假设以下方法:
@RequestMapping(value = "/function/{functionId}/image.gif", produces = "image/gif")
public void getImage(@PathVariable(value = "functionId") String functionId, HttpServletResponse response) throws IOException {
Function function = functionService.getFunction(Integer.valueOf(functionId));

ServletOutputStream servOut = response.getOutputStream();

// Uses default values if you pass in nulls.
function.getImage(servOut, null, null);

servOut.flush();
servOut.close();
}

这个方法:
public void getImage(OutputStream out, String staticContent, String changedContent) throws IOException {
String[] data = {"2", "+", "2", "=", "4"};

Logger logger = Logger.getLogger(AddFunction.class);

logger.info("Getting the add image.");

ImageUtils.writeSequenceToImage(ImageIO.createImageOutputStream(out), data, 5, Constants.IMAGE_HEIGHT / 2);
}

在第二种方法中,您使用 ImageOutputStream(最后一行)创建 ImageIO.createImageOutputStream(out) 的本地实例。

我想主要问题是,您没有关闭此 ImageOutputStream ,这可能会导致数据未写入任何其他 OutputStream (由于缓冲)。

为了使其工作,您可以将您的方法重构为:
@RequestMapping(value = "/function/{functionId}/image.gif", produces = "image/gif")
public void getImage(@PathVariable(value = "functionId") String functionId, HttpServletResponse response) throws IOException {
Function function = functionService.getFunction(Integer.valueOf(functionId));

ImageOutputStream servOut = ImageIO.createImageOutputStream(response.getOutputStream());

// Uses default values if you pass in nulls.
function.getImage(servOut, null, null);

servOut.close();
}

和这个:
public void getImage(ImageOutputStream out, String staticContent, String changedContent) throws IOException {
String[] data = {"2", "+", "2", "=", "4"};

Logger logger = Logger.getLogger(AddFunction.class);

logger.info("Getting the add image.");

ImageUtils.writeSequenceToImage(out, data, 5, Constants.IMAGE_HEIGHT / 2);
}

同样的事情也适用于 generateAndWriteToImage() 方法。如果它正确返回 BufferedImage 的实例,这应该可以工作(通过重构)。

关于java - 从 ServletOutputStream 输出 GIF,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27723315/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com