1
0
mirror of https://gitlab.com/annimon/imagetagger.git synced 2024-09-19 14:34:21 +03:00

Add ResizableImage to reduce scalings count due to endless repaint

This commit is contained in:
Victor 2021-01-04 19:54:18 +02:00
parent 385f6d7c13
commit 27ab04293a
5 changed files with 152 additions and 43 deletions

View File

@ -1,6 +1,7 @@
package com.annimon.imagetagger;
import com.annimon.imagetagger.beans.Config;
import com.annimon.imagetagger.logic.FilesProvider;
import com.annimon.imagetagger.logic.ImageProcessor;
import com.annimon.imagetagger.logic.KeyProcessor;
import com.annimon.imagetagger.views.ImagePanel;
@ -33,7 +34,8 @@ public class Main extends JFrame {
final var tagButtons = config.getButtons(config.getProfile());
final var tagPanel = new TagPanel(tagButtons);
final var imageProcessor = new ImageProcessor(config.getDir(), config.getFilter(), config.getSort());
final var files = new FilesProvider(config.getDir());
final var imageProcessor = new ImageProcessor(files, config.getFilter(), config.getSort());
final var imagePanel = new ImagePanel(imageProcessor);
final var keyProcessor = new KeyProcessor(tagButtons);
keyProcessor.setTagPanel(tagPanel);

View File

@ -0,0 +1,35 @@
package com.annimon.imagetagger.logic;
import com.annimon.imagetagger.views.ResizableImage;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.stream.Stream;
import javax.imageio.ImageIO;
public class FilesProvider {
protected final File dir;
public FilesProvider(String dir) {
this.dir = new File(dir);
}
public Stream<File> stream() {
final var files = dir.listFiles();
if (files == null) {
throw new RuntimeException("There are no files in directory " + dir);
}
return Arrays.stream(files);
}
public ResizableImage loadImage(File file) {
try {
return new ResizableImage(ImageIO.read(file));
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public void preloadImage(File file) { }
}

View File

@ -1,9 +1,8 @@
package com.annimon.imagetagger.logic;
import com.annimon.imagetagger.beans.ImageInfo;
import java.awt.*;
import com.annimon.imagetagger.views.ResizableImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@ -13,28 +12,27 @@ import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import javax.imageio.ImageIO;
public class ImageProcessor {
private final File dir;
private final FilesProvider files;
private final String filter;
private final String sort;
private final List<ImageInfo> imageInfos;
private int imagesCount;
private int index;
private ImageInfo currentInfo;
private Image image;
private ResizableImage image;
public ImageProcessor(String dir, String filter, String sort) {
this.dir = new File(dir);
public ImageProcessor(FilesProvider files, String filter, String sort) {
this.files = files;
this.filter = filter;
this.sort = sort;
imageInfos = new ArrayList<>();
imagesCount = 0;
}
public Image getImage() {
public ResizableImage getImage() {
return image;
}
@ -57,6 +55,7 @@ public class ImageProcessor {
index = imagesCount - 1;
}
loadImage();
preloadImage(-1);
}
public void nextImage() {
@ -65,6 +64,7 @@ public class ImageProcessor {
index = 0;
}
loadImage();
preloadImage(1);
}
public void writeTagsToFile() {
@ -90,11 +90,7 @@ public class ImageProcessor {
}
public void populateFiles() {
final var files = dir.listFiles();
if (files == null) {
throw new RuntimeException("There are no files in directory " + dir);
}
final var infos = Arrays.stream(files)
final var infos = files.stream()
.filter(this::allowedFiles)
.map(ImageInfo::new)
.map(ImageInfo::loadTagFile)
@ -114,11 +110,17 @@ public class ImageProcessor {
if (index < 0 || index >= imagesCount) return;
currentInfo = imageInfos.get(index);
try {
image = ImageIO.read(currentInfo.getFile());
} catch (IOException e) {
throw new RuntimeException(e);
image = files.loadImage(currentInfo.getFile());
}
private void preloadImage(int delta) {
int newIndex = index + delta;
if (newIndex < 0) {
newIndex = imagesCount - 1;
} else if (newIndex >= imagesCount) {
newIndex = 0;
}
files.preloadImage(imageInfos.get(newIndex).getFile());
}
private boolean allowedFiles(File file) {

View File

@ -2,9 +2,8 @@ package com.annimon.imagetagger.views;
import com.annimon.imagetagger.logic.ImageProcessor;
import java.awt.*;
import javax.swing.*;
public class ImagePanel extends JPanel {
public class ImagePanel extends Component {
private static final Color TEXT_COLOR = new Color(0x80FFFFFF, true);
private final ImageProcessor imageProcessor;
@ -13,38 +12,27 @@ public class ImagePanel extends JPanel {
this.imageProcessor = imageProcessor;
}
@SuppressWarnings("UnusedAssignment")
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
public void paint(Graphics g) {
super.paint(g);
final var g2d = (Graphics2D) g;
final int width = getWidth();
final int height = getHeight();
var image = imageProcessor.getImage();
if ((width <= 5) || (height <= 5) || (image == null)) {
final var resizableImage = imageProcessor.getImage();
if ((width <= 5) || (height <= 5) || (resizableImage == null)) {
return;
}
final int imgWidth = image.getWidth(this);
final int imgHeight = image.getHeight(this);
int scaleX = imgWidth;
int scaleY = imgHeight;
var image = resizableImage.getOriginal();
int imgWidth = resizableImage.getOriginalWidth();
int imgHeight = resizableImage.getOriginalHeight();
if (imgWidth > width || imgHeight > height) {
if (scaleX > width) {
// Fit by width
scaleX = width;
scaleY = imgHeight * scaleX / imgWidth;
}
if (scaleY > height) {
// Fit by height
scaleY = height;
scaleX = imgWidth * scaleY / imgHeight;
}
image = image.getScaledInstance(scaleX, scaleY, Image.SCALE_SMOOTH);
image = resizableImage.getResized(width, height);
imgWidth = resizableImage.getResizedWidth();
imgHeight = resizableImage.getResizedHeight();
}
final int x = (width - scaleX) / 2;
final int y = (height - scaleY) / 2;
final int x = (width - imgWidth) / 2;
final int y = (height - imgHeight) / 2;
g2d.drawImage(image, x, y, this);
int yy = 5;

View File

@ -0,0 +1,82 @@
package com.annimon.imagetagger.views;
import java.awt.*;
import java.awt.image.BufferedImage;
public class ResizableImage {
private final Image original;
private Image resizedImage;
private int resizedWidth, resizedHeight;
public ResizableImage(Image original) {
this.original = original;
}
public Image getOriginal() {
return original;
}
public BufferedImage getOriginalAsBufferedImage() {
return toBufferedImage(original);
}
public int getOriginalWidth() {
return original.getWidth(null);
}
public int getOriginalHeight() {
return original.getHeight(null);
}
public Image getResized(int prefWidth, int prefHeight) {
boolean sizeMatched = (resizedWidth == prefWidth) || (resizedHeight == prefHeight);
if (resizedImage == null || !sizeMatched) {
resizedImage = resizeIfNecessary(original, prefWidth, prefHeight);
resizedWidth = resizedImage.getWidth(null);
resizedHeight = resizedImage.getHeight(null);
}
return resizedImage;
}
public BufferedImage getResizedAsBufferedImage(int prefWidth, int prefHeight) {
return toBufferedImage(getResized(prefWidth, prefHeight));
}
public int getResizedWidth() {
return resizedWidth;
}
public int getResizedHeight() {
return resizedHeight;
}
private static Image resizeIfNecessary(Image image, int prefWidth, int prefHeight) {
final int width = image.getWidth(null);
final int height = image.getHeight(null);
if (width <= prefWidth && height <= prefHeight) {
return image;
}
int newWidth = width;
int newHeight = height;
if (width > prefWidth) {
newWidth = prefWidth;
newHeight = height * newWidth / width;
}
if (newHeight > prefHeight) {
newHeight = prefHeight;
newWidth = width * newHeight / height;
}
return image.getScaledInstance(newWidth, newHeight, Image.SCALE_SMOOTH);
}
private static BufferedImage toBufferedImage(Image image) {
final int width = image.getWidth(null);
final int height = image.getHeight(null);
final var img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
final var g = img.createGraphics();
g.drawImage(image, 0, 0, null);
g.dispose();
return img;
}
}