我在jpeg或png类型的变量中有一个imagen,我正在尝试通过java 1.6用命令行jpegoptim或pngquant转换它。
问题是我做不到。我读了很多答案,但没有找到答案。
这是我尝试的最后一个功能:
public int execute(byte[] image) throws IOException {
ProcessBuilder processBuilder = new ProcessBuilder(commandLine);
final Process process = processBuilder.start();
final ByteArrayOutputStream outputBuffer = new ByteArrayOutputStream();
final ByteArrayOutputStream errorBuffer = new ByteArrayOutputStream();
try {
// Handle stdout...
new Thread() {
public void run() {
try {
IOUtils.copy(process.getInputStream(), outputBuffer);
} catch (Exception e) {
LOG.error("Error executing " + commandLine,e);
}
}
}.start();
// Handle sderr...
new Thread() {
public void run() {
try {
IOUtils.copy(process.getErrorStream(), errorBuffer);
} catch (Exception e) {
LOG.error("Error executing " + commandLine,e);
}
}
}.start();
process.getOutputStream().write(image);
process.getOutputStream().flush();
process.waitFor();
result = outputBuffer.toByteArray();
errorMsg = errorBuffer.toString("ASCII");
} catch (InterruptedException e) {
LOG.error("Error executing " + commandLine,e);
} finally {
if( process != null ) {
close(process.getErrorStream());
close(process.getOutputStream());
close(process.getInputStream());
process.destroy();
}
}
return process.exitValue();
}
命令行用于jpg:
this.commandLine = new ArrayList<String>();
this.commandLine.add("jpegoptim");
this.commandLine.add("-m90");
this.commandLine.add("--stdout");
this.commandLine.add("--stdin");
对于png:
this.commandLine = new ArrayList<String>();
this.commandLine.add("pngquant");
this.commandLine.add("--quality=70-80");
this.commandLine.add(">stdout");
this.commandLine.add("<stdin");
此代码的问题是管道破裂。我尝试了不同的编码方式。我在这里读过不同的论坛,但我不知道如何让它发挥作用。
提前谢谢。
编辑:
正如Linux弟子建议的那样,我将命令改为:
List<String> commandLine = new ArrayList<String>();
commandLine.add("tee");
commandLine.add("-a");
commandLine.add("logfile.log");
和代码:
byte[] image = jpg.read(args[0]); // path to file...
ProcessBuilder processBuilder = new ProcessBuilder(commandLine);
final Process process = processBuilder.start();
OutputStream stdin = process.getOutputStream ();
final InputStream stderr = process.getErrorStream ();
final InputStream stdout = process.getInputStream ();
Thread errorT = new Thread() {
public void run() {
byte[] buf = new byte[1024];
int len;
try {
while ((len = stdout.read(buf)) != -1) {
// process byte buffer
System.out.write(buf, 0, len);
System.out.flush();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
};
errorT.start();
Thread outputT = new Thread() {
public void run() {
byte[] buf = new byte[1024];
int len;
try {
while ((len = stderr.read(buf)) != -1) {
System.err.write(buf, 0, len);
System.err.flush();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
};
outputT.start();
stdin.write(image);
stdin.flush();
//stdin.close();
try {
process.waitFor();
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
stdin.close();
stderr.close();
stdout.close();
等待一去不复返。。。缺少什么?
如果我将"stdin.close();"放在flush之后(在上面的代码中有注释),则过程结束。但是stdout没有被完全处理,并且显示了一个错误:java.io.IOException:Stream关闭了两次(每个线程一次)。logfile.log等于映像,但stdout被截断。
我通过命令行测试:
java-cp testProc.jar testProc.Test image.jpg>image_new.jpg
logfile.log等于image.jpgimage_new.jpg较小,是image.jpg的截断版本。
有什么线索吗?
从最后两行开始。使用>stdin
不能通过stdin
。查看一些ProcessBuilder示例,了解如何使用BufferedWriter写入进程的stdin(Java进程的stdout),然后使用BufferedReader对子进程的stdout。如果在那之后仍然有问题,那么为了进行诊断,您可以尝试用tee -a logfile
替换jpegoptim
和pngquant
,这将获取stdin并直接将其管道传输回stdout(以及一个名为logfile的文件)
然后你得到了一个包含所有管道输入数据的文件,或者你会得到一个空文件和管道错误,因为你的Java程序没有传递数据,你可以看看它是否正确
如果您得到一个包含数据的文件,但没有得到管道错误,则可能意味着jpegoptim
没有返回任何数据
此时,您可以在命令行上将数据从logfile
管道传输到jpegoptim
,并使用这些选项,直到它正常工作,然后在Java代码中使用这些工作选项。
终于成功了!
我完全靠运气找到了解决方案!。。。我打乱了这条线:
stdin.close();
并在"process.waitFor();"行之后添加:此行:
errorT.join();
outputT.join();
要处理图像,命令是:
commandLine.add("jpegoptim");
commandLine.add("-m90");
commandLine.add("--stdout");
commandLine.add("--stdin");
和:
commandLine.add("pngquant");
commandLine.add("--quality=70-80");
commandLine.add("-");
最终代码:
public int execute(List<String> commandLine, byte[] image) throws IOException {
ProcessBuilder processBuilder = new ProcessBuilder(commandLine);
final Process process = processBuilder.start();
OutputStream stdin = process.getOutputStream ();
final InputStream stderr = process.getErrorStream ();
final InputStream stdout = process.getInputStream ();
final ByteArrayOutputStream bos = new ByteArrayOutputStream();
Thread errorT = new Thread() {
public void run() {
byte[] buf = new byte[1024];
int len;
try {
while ((len = stdout.read(buf)) != -1) {
// process byte buffer
bos.write(buf, 0, len);
bos.flush();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
};
errorT.start();
Thread outputT = new Thread() {
public void run() {
byte[] buf = new byte[1024];
int len;
try {
while ((len = stderr.read(buf)) != -1) {
System.err.write(buf, 0, len);
System.err.flush();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
};
outputT.start();
stdin.write(image);
stdin.flush();
stdin.close();
try {
process.waitFor();
errorT.join();
outputT.join();
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
stdin.close();
stderr.close();
stdout.close();
System.out.write(bos.toByteArray());
return 0;
}