Skip to content

Commit e603107

Browse files
committed
refactor(image): implement image processing and upload functionality
1 parent 67e34d7 commit e603107

7 files changed

Lines changed: 224 additions & 191 deletions

File tree

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
package com.dev.servlet.adapter.out.image;
2+
3+
import jakarta.enterprise.context.ApplicationScoped;
4+
import org.imgscalr.Scalr;
5+
6+
import javax.imageio.ImageIO;
7+
import java.awt.*;
8+
import java.awt.image.BufferedImage;
9+
import java.io.ByteArrayInputStream;
10+
import java.io.ByteArrayOutputStream;
11+
import java.io.IOException;
12+
import java.io.InputStream;
13+
14+
@ApplicationScoped
15+
public class ImageProcessor {
16+
17+
static {
18+
ImageIO.scanForPlugins();
19+
}
20+
21+
/**
22+
* Convert image to TYPE_INT_RGB (JPG compatible)
23+
* TYPE_INT_RGB does not support transparency, so transparent areas
24+
* will be filled with white color.
25+
*
26+
* @param img the source image
27+
* @return a BufferedImage of type TYPE_INT_RGB
28+
*/
29+
public BufferedImage normalizeToJpg(BufferedImage img) {
30+
if (img.getType() == BufferedImage.TYPE_INT_RGB) {
31+
return img;
32+
}
33+
34+
BufferedImage jpg = new BufferedImage(
35+
img.getWidth(),
36+
img.getHeight(),
37+
BufferedImage.TYPE_INT_RGB
38+
);
39+
40+
Graphics2D g = jpg.createGraphics();
41+
g.drawImage(img, 0, 0, Color.WHITE, null);
42+
g.dispose();
43+
44+
return jpg;
45+
}
46+
47+
public BufferedImage cropSquare(BufferedImage source) {
48+
int min = Math.min(source.getWidth(), source.getHeight());
49+
int x = (source.getWidth() - min) / 2;
50+
int y = (source.getHeight() - min) / 2;
51+
52+
return Scalr.crop(source, x, y, min, min);
53+
}
54+
55+
public BufferedImage resize(BufferedImage source, int size) {
56+
return Scalr.resize(source, Scalr.Method.ULTRA_QUALITY, size);
57+
}
58+
59+
public InputStream toJpgStream(BufferedImage image) {
60+
try {
61+
ByteArrayOutputStream out = new ByteArrayOutputStream();
62+
ImageIO.write(image, "jpg", out);
63+
return new ByteArrayInputStream(out.toByteArray());
64+
} catch (IOException e) {
65+
throw new RuntimeException("Failed to write image", e);
66+
}
67+
}
68+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package com.dev.servlet.adapter.out.image;
2+
3+
import jakarta.enterprise.context.ApplicationScoped;
4+
import jakarta.inject.Inject;
5+
6+
import javax.imageio.ImageIO;
7+
import java.awt.image.BufferedImage;
8+
import java.io.InputStream;
9+
10+
@ApplicationScoped
11+
public class ImageService {
12+
13+
static {
14+
ImageIO.scanForPlugins();
15+
}
16+
17+
@Inject
18+
private ImageProcessor processor;
19+
20+
public InputStream processToSquareJpg(InputStream in, int size) {
21+
try {
22+
BufferedImage img = ImageIO.read(in);
23+
if (img == null) throw new RuntimeException("Invalid image");
24+
25+
img = processor.normalizeToJpg(img);
26+
img = processor.cropSquare(img);
27+
img = processor.resize(img, size);
28+
29+
return processor.toJpgStream(img);
30+
} catch (Exception e) {
31+
throw new RuntimeException("Image processing failed", e);
32+
}
33+
}
34+
}

src/main/java/com/dev/servlet/adapter/out/storage/ImageService.java

Lines changed: 0 additions & 137 deletions
This file was deleted.

src/main/java/com/dev/servlet/application/usecase/product/ScrapeProductUseCase.java

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import com.dev.servlet.adapter.out.external.webscrape.WebScrapeServiceRegistry;
44
import com.dev.servlet.adapter.out.external.webscrape.builder.WebScrapeBuilder;
55
import com.dev.servlet.adapter.out.external.webscrape.transfer.ProductWebScrapeDTO;
6-
import com.dev.servlet.adapter.out.storage.ImageService;
6+
import com.dev.servlet.adapter.out.image.ImageService;
77
import com.dev.servlet.application.mapper.ProductMapper;
88
import com.dev.servlet.application.port.in.product.ScrapeProductPort;
99
import com.dev.servlet.application.port.out.alert.AlertPort;
@@ -15,13 +15,13 @@
1515
import com.dev.servlet.domain.entity.User;
1616
import com.dev.servlet.domain.entity.enums.Status;
1717
import com.dev.servlet.infrastructure.config.Properties;
18+
import com.dev.servlet.infrastructure.http.FileHttpClient;
1819
import jakarta.annotation.PreDestroy;
1920
import jakarta.enterprise.context.ApplicationScoped;
2021
import jakarta.enterprise.context.control.RequestContextController;
2122
import jakarta.inject.Inject;
2223
import lombok.extern.slf4j.Slf4j;
2324

24-
import java.io.IOException;
2525
import java.io.InputStream;
2626
import java.net.URI;
2727
import java.time.Duration;
@@ -56,6 +56,8 @@ public class ScrapeProductUseCase implements ScrapeProductPort {
5656
private StorageService storageService;
5757
@Inject
5858
private ImageService imageService;
59+
@Inject
60+
private FileHttpClient fileHttpClient;
5961

6062
@Override
6163
public CompletableFuture<List<ProductResponse>> scrapeAsync(String url, String auth) {
@@ -160,20 +162,27 @@ private void uploadImageToStorage(List<Product> products, User user) {
160162
try {
161163
future.get();
162164
} catch (Exception e) {
163-
log.error("Error occurred while uploading product image", e);
165+
log.warn("Error occurred while uploading product image", e);
164166
}
165167
}
166168
}
167169

168-
private String uploadImage(String sourceUrl, User user) throws IOException {
170+
private String uploadImage(String sourceUrl, User user) {
169171
log.info("Processing image for product from URL: {}", sourceUrl);
170-
InputStream pic = imageService.writePicture(imageService.getJpgImageFromUrl(sourceUrl), 800);
171172

172-
final String path = "private/users/" + user.getId() + "/products/" + UUID.randomUUID() + ".jpg";
173-
log.info("Generating image URL for product image at path: {}", path);
173+
try (InputStream download = fileHttpClient.download(sourceUrl);
174+
InputStream pic = imageService.processToSquareJpg(download, 500)) {
175+
176+
final String path = "private/users/" + user.getId() + "/products/" + UUID.randomUUID() + ".jpg";
177+
log.info("Generating image URL for product image at path: {}", path);
178+
179+
URI uri = storageService.generateUploadUri(path, "image/jpeg", Duration.ofMinutes(5));
180+
fileHttpClient.upload(uri, pic, "image/jpeg");
181+
return path;
174182

175-
URI uploadUrl = storageService.generateUploadUri(path, "image/jpeg", Duration.ofMinutes(1));
176-
imageService.uploadImageToUrl(uploadUrl, pic, "image/jpeg");
177-
return path;
183+
} catch (Exception e) {
184+
log.error("Failed to upload product image from URL: {}", sourceUrl, e);
185+
return null;
186+
}
178187
}
179188
}

0 commit comments

Comments
 (0)