11月20日
任务三:
阅读百度给出的官方文档可知,需要将照片处理为json数据然后调用api上传,然后需要将api返回的json数据转化为图片形式显示在gui界面上。
Gui设计了两个按钮,一个是上传图片一个是保存图片(图片一经上传就直接被优化返回,不需要网络优化按钮)。软件对照片进行了初步的处理,在保留长宽比的基础上在gui界面上完整的居中显示(包括返回的照片)。点击保存按钮可以选择文件夹将处理的的照片保存在本地。
原本在百度官方给出的文档中显示,最多上传不超过8m的数据包,但实际上在测试过程中,只要照片超过1m就会出现错误返回。所以添加了检测照片大小数据的功能,超过1m会提示用户照片数据过大,无法处理,需要重新上传。
实现代码如下:
import okhttp3.*;
import org.json.JSONObject;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.image.BufferedImage;
import java.io.*;
import javax.imageio.ImageIO;
import java.net.URLEncoder;
import java.util.Base64;
public class PhotoEnhancer extends JFrame {
private static final String API_KEY =
"T2ZS5mbDARSEIJKfSZrxr0ve";
private static final String
SECRET_KEY = "3y8zcki0ViAploSzUTr7Wq9BK5Q17qNk";
private static final OkHttpClient
HTTP_CLIENT = new OkHttpClient().newBuilder().build();
private JLabel originalLabel;
private JLabel processedLabel;
private BufferedImage originalImage;
private BufferedImage processedImage;
public PhotoEnhancer() {
setTitle("图像增强清晰度软件");
setSize(1600, 800);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLayout(new BorderLayout());
JPanel topPanel = new JPanel(new
GridLayout(1, 2));
originalLabel = new JLabel();
processedLabel = new JLabel();
topPanel.add(new JScrollPane(originalLabel));
topPanel.add(new
JScrollPane(processedLabel));
JPanel bottomPanel = new
JPanel(); // 使用默认的 FlowLayout
bottomPanel.setLayout(new
FlowLayout(FlowLayout.CENTER, 700, 20)); // 水平居中,适当的水平和垂直间距
JButton
uploadButton = new JButton("上传照片");
JButton saveButton = new
JButton("保存照片");
uploadButton.addActionListener(this::uploadImage);
saveButton.addActionListener(this::saveImage);
bottomPanel.add(uploadButton);
bottomPanel.add(saveButton);
add(topPanel,
BorderLayout.CENTER);
add(bottomPanel,
BorderLayout.SOUTH);
}
private void uploadImage(ActionEvent
event) {
JFileChooser fileChooser = new
JFileChooser();
if
(fileChooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) {
File file =
fileChooser.getSelectedFile();
if (file.length() > 1024 *
1024) {
JOptionPane.showMessageDialog(this,
"上传的图片过大,请上传小于1M的图片。", "错误", JOptionPane.ERROR_MESSAGE);
return;
}
try {
originalImage = ImageIO.read(file);
updateLabel(originalLabel, originalImage);
processedImage =
processImage(originalImage);
updateLabel(processedLabel, processedImage);
} catch (IOException e) {
e.printStackTrace();
}
}
}
private void updateLabel(JLabel
label, BufferedImage image) {
int labelWidth =
label.getParent().getWidth(); // 使用父容器的宽度
int
labelHeight = label.getParent().getHeight(); // 使用父容器的高度
int
imageWidth = image.getWidth();
int imageHeight =
image.getHeight();
double scaleX = (double)
labelWidth / imageWidth;
double scaleY = (double)
labelHeight / imageHeight;
double scale = Math.min(scaleX,
scaleY);
int scaledWidth = (int)
(imageWidth * scale);
int scaledHeight = (int)
(imageHeight * scale);
// 创建一个新的BufferedImage用于绘制居中的图片
BufferedImage
centeredImage = new BufferedImage(labelWidth, labelHeight,
BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d =
centeredImage.createGraphics();
// 清除背景并绘制居中的图片
g2d.setComposite(AlphaComposite.Clear);
g2d.fillRect(0, 0, labelWidth,
labelHeight);
g2d.setComposite(AlphaComposite.SrcOver);
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2d.drawImage(image, (labelWidth
- scaledWidth) / 2, (labelHeight - scaledHeight) / 2, scaledWidth,
scaledHeight, null);
g2d.dispose();
// 设置新的居中图片到JLabel
ImageIcon
icon = new ImageIcon(centeredImage);
label.setIcon(icon);
label.revalidate();
label.repaint();
}
private void saveImage(ActionEvent
event) {
if (processedImage != null) {
JFileChooser fileChooser =
new JFileChooser();
if
(fileChooser.showSaveDialog(this) == JFileChooser.APPROVE_OPTION) {
File file =
fileChooser.getSelectedFile();
try {
ImageIO.write(processedImage,
"png", file);
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
private BufferedImage
processImage(BufferedImage image) throws IOException {
ByteArrayOutputStream bao = new
ByteArrayOutputStream();
ImageIO.write(image,
"png", bao);
byte[] imageBytes =
bao.toByteArray();
String base64Image = Base64.getEncoder().encodeToString(imageBytes);
base64Image = URLEncoder.encode(base64Image,
"utf-8");
MediaType mediaType = MediaType.parse("application/x-www-form-urlencoded");
RequestBody body = RequestBody.create(mediaType,
"image=" + base64Image);
Request request = new
Request.Builder()
.url("https://aip.baidubce.com/rest/2.0/image-process/v1/image_definition_enhance?access_token="
+ getAccessToken())
.method("POST",
body)
.addHeader("Content-Type",
"application/x-www-form-urlencoded")
.addHeader("Accept", "application/json")
.build();
Response response =
HTTP_CLIENT.newCall(request).execute();
if (!response.isSuccessful())
throw new IOException("Unexpected code " + response);
String jsonResponse =
response.body().string();
JSONObject jsonResponseBody = new
JSONObject(jsonResponse);
String base64ImageResult =
jsonResponseBody.getString("image");
byte[] imageBytesDecoded =
Base64.getDecoder().decode(base64ImageResult);
ByteArrayInputStream bais = new
ByteArrayInputStream(imageBytesDecoded);
return ImageIO.read(bais);
}
static String getAccessToken() throws
IOException {
MediaType mediaType = MediaType.parse("application/x-www-form-urlencoded");
RequestBody body = RequestBody.create(mediaType,
"grant_type=client_credentials&client_id=" + API_KEY +
"&client_secret=" + SECRET_KEY);
Request request = new
Request.Builder()
.url("https://aip.baidubce.com/oauth/2.0/token")
.method("POST",
body)
.addHeader("Content-Type",
"application/x-www-form-urlencoded")
.build();
Response response =
HTTP_CLIENT.newCall(request).execute();
return new
JSONObject(response.body().string()).getString("access_token");
}
public static void main(String[]
args) {
SwingUtilities.invokeLater(()
-> {
new
PhotoEnhancer().setVisible(true);
});
}
}
运行截图: