我有一个带有 JavaFX 的 GUI。我从用户那里得到一张图片。然后我运行一个 C 程序并为其提供图片的文件路径。 c程序处理图片并将其返回给java程序,在java程序中显示处理后的图片。这是相关代码:
Java:
public void runCProgram(String t)
{
try {
String command = "C:\\Users\\fendl\\CPP2\\Uebung\\fotofilter";
// Create a ProcessBuilder for the C program
ProcessBuilder processBuilder = new ProcessBuilder(command, imagePath, t);
// Redirect the output to the Java program's output
processBuilder.redirectOutput(ProcessBuilder.Redirect.INHERIT);
// Start the C program
Process process = processBuilder.start();
// Wait for the C program to finish
int exitCode = process.waitFor();
if (exitCode == 0) {
// Image processing was successful
// Read the processed image data from the C program's output stream
try (InputStream is = process.getInputStream()) {
ByteArrayOutputStream outputData = new ByteArrayOutputStream();
byte[] buffer = new byte[2056];
int bytesRead;
while ((bytesRead = is.read(buffer)) != -1) {
outputData.write(buffer, 0, bytesRead);
}
byte[] processedImageData = outputData.toByteArray();
Platform.runLater(() -> {
imageView.setImage(new Image(new ByteArrayInputStream(processedImageData)));
});
System.out.println("\n C program successfully processed the image.");
}
} else {
System.err.println("C program exited with an error code: " + exitCode);
}
} catch (IOException | InterruptedException e) {
e.printStackTrace();
}
}
C:
int main(int argc, char const *argv[])
{
FILE *inputFile = fopen(argv[1], "rb");
if (inputFile == NULL)
{
perror("Failed to open the file");
return 1;
}
//The first 54 bytes of a bmp file is the header
unsigned char imageHeader[54];
fread(imageHeader, sizeof(unsigned char), 54, inputFile);
if (imageHeader[0] != 'B' || imageHeader[1] != 'M')
{
perror("File is not a bmp file");
return 1;
}
int width = *(int *) &imageHeader[18];
int height = *(int *) &imageHeader[22];
int bitDepth = *(int *) &imageHeader[28];
//Normally 3 Bytes per Pixel (red, green, blue)
int bytesPerPixel = bitDepth / 8;
//Row of pixel is always a multiple of 4 in a bmp file
int dataSize = width * height* bytesPerPixel;
//If there is a color table stored in the bmp file; the next 1024 bytes is the color table
unsigned char colorTable[1024];
if (bitDepth <= 8)
{
fread(colorTable, sizeof(unsigned char), 1024, inputFile);
}
//The rest of the bytes is the data of the image (RGB values for every pixel)
unsigned char *imageData = (unsigned char *) malloc(dataSize);
fread(imageData, sizeof(unsigned char), dataSize, inputFile);
//Apply Filter
choose_filter(dataSize, bytesPerPixel, imageData, argv[2][0]);
//Write image to output stream
fwrite(imageHeader, sizeof(unsigned char), 54, stdout);
if (bitDepth <= 8)
{
fwrite(colorTable, sizeof(unsigned char), 1024, stdout);
}
fwrite(imageData, sizeof(unsigned char), dataSize, stdout);
fflush(stdout);
fclose(inputFile);
free(imageData);
return 0;
}
问题:问题是Java中的“processedImageData”为空。所以我如何从我的 c 程序获取数据似乎有问题。
当将图像写入文件而不是写入 C 中的输出流时,一切正常,我们得到正确处理的图像。 我的控制台中还有很多奇怪的符号,因此 c 程序似乎至少返回了一些东西。 ChatGPT 也帮不上忙:(
有人知道问题可能是什么以及如何解决吗?
正如 DuncG 指出的那样,在读取 Process 的输出之前,不得调用 Process 的
waitFor
方法。调用 waitFor 后,该过程完成,没有任何输出可供读取。
Process process = processBuilder.start();
try (InputStream is = process.getInputStream()) {
// ...
}
// Wait for the C program to finish
int exitCode = process.waitFor();
if (exitCode != 0) {
System.err.println("C program exited with an error code: " + exitCode);
}
processBuilder.redirectOutput(ProcessBuilder.Redirect.INHERIT);
导致子进程使用 Java 程序的标准输出作为自己的标准输出。这意味着 Java 程序无法读取该输出。
你想要的是:
processBuilder.redirectError(ProcessBuilder.Redirect.INHERIT);
这将确保 C 程序打印的任何错误都出现在 Java 程序的标准错误上。
不要盲目地假设图像是正确的:
imageView.setImage(new Image(new ByteArrayInputStream(processedImageData)));
您应该检查图像中是否有错误:
Image image = new Image(new ByteArrayInputStream(processedImageData));
if (image.getException() != null) {
System.err.println("Exception encountered while loading image.");
image.getException().printStackTrace();
}
imageView.setImage(image);
您不需要 ByteArrayOutputStream。只需使用 readAllBytes:
读取字节try (InputStream is = process.getInputStream()) {
byte[] processedImageData = is.readAllBytes();
这并不是绝对必要的,但它可以节省内存(字节数组的副本更少),并且更少的代码可以帮助您消除自己的代码作为可能的错误来源。
在计算 dataSize 时,您有这样的评论:
//Row of pixel is always a multiple of 4 in a bmp file
但是你完全忽略了这个说法。
此外,高度可以为负值,如BMP 格式中所述。
int bytesPerRow = width * bytesPerPixel;
if (bytesPerRow % 4) {
bytesPerRow += (4 - (bytesPerRow % 4));
}
int dataSize = bytesPerRow * abs(height);
可能有更紧凑的方法来做到这一点,但我的 C 技能很生疏,我更喜欢清晰的东西而不是神秘的东西。
BMP格式并没有说颜色表总是1024字节。颜色数是文件中偏移量 46 处的 32 位值;如果为零,则颜色数量为 2ⁿ,其中 n 是每像素的位数。
int width = *(int *) &imageHeader[18];
int height = *(int *) &imageHeader[22];
int bitDepth = *(int *) &imageHeader[28];
int color_count = *(int *) &imageHeader[46];
// ...
if (color_count == 0)
{
color_count = 1 << bitDepth;
}
int color_table_size = color_count * 4;
unsigned char *colorTable = NULL;
if (bitDepth <= 8)
{
colorTable = (unsigned char *) malloc(color_table_size);
fread(colorTable, sizeof(unsigned char), color_table_size, inputFile);
}
当然,就在你的 main 方法返回之前:
if (colorTable)
{
free(colorTable);
}