Skip to content

Commit

Permalink
#88 extract media package and add cropping option to media format def…
Browse files Browse the repository at this point in the history
…inition (#90)

Co-authored-by: Thorsten Marx <t.marx@eggheads.de>
  • Loading branch information
thmarx and Thorsten Marx authored Nov 21, 2023
1 parent 2e44370 commit 36d025b
Show file tree
Hide file tree
Showing 15 changed files with 493 additions and 85 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
* #L%
*/

import com.github.thmarx.cms.api.media.MediaFormat;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
Expand Down Expand Up @@ -55,14 +56,14 @@ public Map<String, MediaFormat> getMediaFormats() {
(int) map.get("width"),
(int) map.get("height"),
Media.format4String((String) map.get("format")),
(boolean) map.get("compression")
(boolean) map.get("compression"),
(boolean) map.getOrDefault("cropped", false)
);
mediaFormats.put(mediaFormat.name(), mediaFormat);
});

return mediaFormats;
}

public static record MediaFormat(String name, int width, int height, Media.Format format, boolean compression) {
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package com.github.thmarx.cms.api.media;

/*-
* #%L
* cms-api
* %%
* Copyright (C) 2023 Marx-Software
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program. If not, see
* <http://www.gnu.org/licenses/gpl-3.0.html>.
* #L%
*/

import com.github.thmarx.cms.api.Media;

/**
*
* @author t.marx
*/
public record MediaFormat(String name, int width, int height, Media.Format format, boolean compression, boolean cropped) {
public MediaFormat (String name, int width, int height, Media.Format format, boolean compression) {
this(name, width, height, format, compression, false);
}
}
33 changes: 33 additions & 0 deletions cms-media/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.github.thmarx.cms</groupId>
<artifactId>cms-parent</artifactId>
<version>2.12.0-SNAPSHOT</version>
</parent>
<artifactId>cms-media</artifactId>
<packaging>jar</packaging>

<dependencies>
<dependency>
<groupId>com.github.usefulness</groupId>
<artifactId>webp-imageio</artifactId>
</dependency>
<dependency>
<groupId>com.github.thmarx.cms</groupId>
<artifactId>cms-api</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>net.coobird</groupId>
<artifactId>thumbnailator</artifactId>
<version>0.4.20</version>
</dependency>
</dependencies>

</project>
126 changes: 126 additions & 0 deletions cms-media/src/main/java/com/github/thmarx/cms/media/Crop.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
package com.github.thmarx.cms.media;

/*-
* #%L
* cms-media
* %%
* Copyright (C) 2023 Marx-Software
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program. If not, see
* <http://www.gnu.org/licenses/gpl-3.0.html>.
* #L%
*/

import java.awt.Graphics2D;
import java.awt.geom.AffineTransform;
import java.awt.geom.Point2D;
import java.awt.image.BufferedImage;

/**
* code from: http://www.java2s.com/example/java-utility-method/bufferedimage-crop/cropscale-bufferedimage-source-int-width-int-height-63a10.html
*
* @author t.marx
*/
public class Crop {

/**
* This function crops the image to the aspect ratio of the width and height and then scales the image to the given
* values
*
* @param source is the image to resize
* @param width is the wanted width
* @param height is the wanted height
* @return a new image with the specified width and height
*/
public static BufferedImage cropScale(BufferedImage source, int width, int height) {
float aspect = width / height;
BufferedImage tmp = cropToAspectRatio(source, aspect);
tmp = scale(tmp, width, height, false);
return tmp;
}

public static BufferedImage my_crop (final BufferedImage image, final int target_width, int target_height) {
int width = target_width;
int height = target_height;

int x = (image.getWidth() / 2) - (width / 2);
int y = (image.getHeight() / 2) - (height / 2);

if (x < 0 || y < 0) {
x = y = 0;
}

return image.getSubimage(x, y, width, height);
}

/**
* Crops a image to a specific aspect ration
*
* @param image is the actual image to crop
* @param aspect is the aspect ratio to convert the image to
* @return a new image with the specified aspect ratio
*/
public static BufferedImage cropToAspectRatio(BufferedImage image, float aspect) {
int x = 0, y = 0;
int width = image.getWidth();
int height = image.getHeight();

// Check if the width is larger than the height
if (width > height) {
width = (int) (height * aspect);
x = image.getWidth() / 2 - width / 2;
} else {
height = (int) (width * aspect);
y = image.getHeight() / 2 - height / 2;
}

if (x < 0 || y < 0) {
x = y = 0;
}

return image.getSubimage(x, y, width, height);
}

/**
* Resizes a BufferedImage
*
* @param source is the image to resize
* @param width is the wanted width
* @param height is the wanted height
* @param keep_aspect is if the aspect ratio of the image should be kept
* @return the resized image
*/
public static BufferedImage scale(BufferedImage source, int width, int height, boolean keep_aspect) {
double scale_width = (double) width / source.getWidth();
double scale_height = (double) height / source.getHeight();

// aspect calculation
if (keep_aspect) {
if (scale_width * source.getHeight() > height) {
scale_width = scale_height;
} else {
scale_height = scale_width;
}
}

BufferedImage tmp = new BufferedImage((int) (scale_width * source.getWidth()),
(int) (scale_height * source.getHeight()), BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = tmp.createGraphics();

AffineTransform at = AffineTransform.getScaleInstance(scale_width, scale_height);
g2d.drawRenderedImage(source, at);
g2d.dispose();
return tmp;
}
}
141 changes: 141 additions & 0 deletions cms-media/src/main/java/com/github/thmarx/cms/media/MediaManager.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
package com.github.thmarx.cms.media;

/*-
* #%L
* cms-media
* %%
* Copyright (C) 2023 Marx-Software
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program. If not, see
* <http://www.gnu.org/licenses/gpl-3.0.html>.
* #L%
*/

import com.github.thmarx.cms.api.Media;
import com.github.thmarx.cms.api.SiteProperties;
import com.github.thmarx.cms.api.media.MediaFormat;
import com.github.thmarx.cms.api.theme.Theme;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import lombok.RequiredArgsConstructor;
import net.coobird.thumbnailator.Thumbnails;
import net.coobird.thumbnailator.geometry.Positions;

/**
*
* @author t.marx
*/
@RequiredArgsConstructor
public class MediaManager {

private final Path assetBase;
private final Theme theme;
private final SiteProperties siteProperties;

private Map<String, MediaFormat> mediaFormats;
private Path tempDirectory;

public Path resolve (String uri) {
return assetBase.resolve(uri);
}

public boolean hasMediaFormat (String format) {
return getMediaFormats().containsKey(format);
}
public MediaFormat getMediaFormat (String format) {
return getMediaFormats().get(format);
}

private Path getTempDirectory() throws IOException {
if (tempDirectory == null) {
tempDirectory = Files.createTempDirectory("cms-media-temp");
}
return tempDirectory;
}

public Optional<byte[]> getScaledContent(final String mediaPath, final MediaFormat mediaFormat) throws IOException {

Path resolve = assetBase.resolve(mediaPath);

if (Files.exists(resolve)) {
Optional<byte[]> tempContent = getTempContent(mediaPath, mediaFormat);
if (tempContent.isPresent()) {
return tempContent;
}

Thumbnails.Builder<File> scaleBuilder = Thumbnails
.of(resolve.toFile())
.size(mediaFormat.width(), mediaFormat.height())
;

if (mediaFormat.cropped()) {
scaleBuilder.crop(Positions.CENTER);
}

byte[] data = Scale.toFormat(scaleBuilder.asBufferedImage(), mediaFormat);

writeTempContent(mediaPath, mediaFormat, data);

return Optional.of(data);
}
return Optional.empty();
}

public String getTempFilename(final String mediaPath, final MediaFormat mediaFormat) {
var tempFilename = mediaPath.replace("/", "_").replace(".", "_");
tempFilename += "-" + mediaFormat.name() + Media.fileending4Format(mediaFormat.format());

return tempFilename;
}

private Path writeTempContent(final String mediaPath, final MediaFormat mediaFormat, byte[] content) throws IOException {
var tempFilename = getTempFilename(mediaPath, mediaFormat);

var tempFile = getTempDirectory().resolve(tempFilename);
Files.deleteIfExists(tempFile);
Files.write(tempFile, content);

return tempFile;
}

private Optional<byte[]> getTempContent(final String mediaPath, final MediaFormat mediaFormat) throws IOException {
var tempFilename = getTempFilename(mediaPath, mediaFormat);

var tempFile = getTempDirectory().resolve(tempFilename);
if (Files.exists(tempFile)) {
return Optional.of(Files.readAllBytes(tempFile));
}

return Optional.empty();
}

private Map<String, MediaFormat> getMediaFormats() {

if (mediaFormats == null) {
mediaFormats = new HashMap<>();

if (!theme.empty()) {
mediaFormats.putAll(theme.properties().getMediaFormats());
}
mediaFormats.putAll(siteProperties.getMediaFormats());
}

return mediaFormats;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
* #L%
*/
import com.github.thmarx.cms.api.Media;
import com.github.thmarx.cms.api.media.MediaFormat;
import com.luciad.imageio.webp.WebPWriteParam;
import java.awt.Color;
import java.awt.Image;
Expand Down Expand Up @@ -87,6 +88,17 @@ public static ScaleResult scaleWithAspectIfTooLarge(byte[] fileData, int maxWidt
return result;
}

public static byte[] toFormat(final BufferedImage imageBuff, final MediaFormat mediaFormat) throws IOException {
if (null != mediaFormat.format()) {
return switch (mediaFormat.format()) {
case JPEG -> toJPG(imageBuff, !mediaFormat.compression());
case WEBP -> toWEBP(imageBuff, !mediaFormat.compression());
case PNG -> toPNG(imageBuff, !mediaFormat.compression());
};
}
throw new IllegalArgumentException("unknown media format");
}

private static byte[] toPNG(final BufferedImage imageBuff, final boolean uncompressed) throws IOException {
try (ByteArrayOutputStream buffer = new ByteArrayOutputStream()) {
if (uncompressed) {
Expand Down
Loading

0 comments on commit 36d025b

Please sign in to comment.