使用JavaFX和C进行图像处理;从 C 到 Java 获取数据时出现问题

问题描述 投票:0回答:1

我有一个带有 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 也帮不上忙:(

有人知道问题可能是什么以及如何解决吗?

java c image-processing stdout processbuilder
1个回答
0
投票

1.读取程序输出后移动 waitFor。

正如 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);
}

2.删除对redirectOutput的调用。

processBuilder.redirectOutput(ProcessBuilder.Redirect.INHERIT);
导致子进程使用 Java 程序的标准输出作为自己的标准输出。这意味着 Java 程序无法读取该输出。

你想要的是:

processBuilder.redirectError(ProcessBuilder.Redirect.INHERIT);

这将确保 C 程序打印的任何错误都出现在 Java 程序的标准错误上。

3.检查图像加载是否有错误。

不要盲目地假设图像是正确的:

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);

4. (可选)使用 readAllBytes 而不是 ByteArrayOutputStream。

您不需要 ByteArrayOutputStream。只需使用 readAllBytes:

读取字节
try (InputStream is = process.getInputStream()) {
    byte[] processedImageData = is.readAllBytes();

这并不是绝对必要的,但它可以节省内存(字节数组的副本更少),并且更少的代码可以帮助您消除自己的代码作为可能的错误来源。

5.根据BMP格式计算dataSize。

在计算 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 技能很生疏,我更喜欢清晰的东西而不是神秘的东西。

6.根据BMP格式计算色表大小。

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);
}
© www.soinside.com 2019 - 2024. All rights reserved.