Skip to content

Commit

Permalink
Merge pull request #2 from cerus/feature-filters
Browse files Browse the repository at this point in the history
Add filters
  • Loading branch information
cerus authored Jun 12, 2022
2 parents d70833f + b685738 commit 7f078e7
Show file tree
Hide file tree
Showing 8 changed files with 135 additions and 3 deletions.
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ Query params:
- Whether the hat overlay should be rendered or not
- Allowed values: `true`, `false`
- Default: `true`
- (Optional) `filter`
- The filters (concatenate filters with ,)
- Allowed values: id of a registered filter

**GET /skins**\
List all available skin providers
Expand Down Expand Up @@ -66,6 +69,12 @@ Example usage:
<img src="https://mchr.cerus.dev/v1/render/Cerus_?skin=minotar&size=128&overlay=false" alt="Rendered image">
</details>

<details>
<summary>Render a flat head using a Minotar skin of size 128x128 with a grayscale filter</summary>
<a href="https://mchr.cerus.dev/v1/render/Cerus_?skin=minotar&size=128&filter=grayscale">https://mchr.cerus.dev/v1/render/Cerus_?skin=minotar&size=128&filter=grayscale</a><br>
<img src="https://mchr.cerus.dev/v1/render/Cerus_?skin=minotar&size=128&filter=grayscale" alt="Rendered image">
</details>

## Installation

### Using docker-compose
Expand Down
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

<groupId>dev.cerus</groupId>
<artifactId>mc-head-render</artifactId>
<version>1.0.1</version>
<version>1.0.2</version>

<properties>
<maven.compiler.source>17</maven.compiler.source>
Expand Down
5 changes: 5 additions & 0 deletions src/main/java/dev/cerus/mcheadrender/Launcher.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

import dev.cerus.mcheadrender.config.JsonFileSkinProviderConfig;
import dev.cerus.mcheadrender.config.SkinProviderConfig;
import dev.cerus.mcheadrender.filter.Filter;
import dev.cerus.mcheadrender.filter.GrayscaleFilter;
import dev.cerus.mcheadrender.filter.InvertFilter;
import dev.cerus.mcheadrender.image.DefaultImageCache;
import dev.cerus.mcheadrender.renderer.FlatRenderer;
import dev.cerus.mcheadrender.renderer.IsometricRenderer;
Expand All @@ -22,6 +25,7 @@ public static void main(final String[] args) throws IOException {
// Init registries
final Registry<Renderer> rendererRegistry = new Registry<>(Renderer::id, "flat", new FlatRenderer(), new IsometricRenderer());
final Registry<SkinProvider> skinProviderRegistry = new Registry<>(SkinProvider::id, "mojang", new MojangSkinProvider());
final Registry<Filter> filterRegistry = new Registry<>(Filter::id, null, new GrayscaleFilter(), new InvertFilter());

// Init skin provider config
final SkinProviderConfig skinProviderConfig = new JsonFileSkinProviderConfig(new File("skin_provider.json"));
Expand All @@ -31,6 +35,7 @@ public static void main(final String[] args) throws IOException {
final WebServer webServer = new WebServer(
rendererRegistry,
skinProviderRegistry,
filterRegistry,
new DefaultImageCache()
);
webServer.start(Globals.API_HOST, Globals.API_PORT);
Expand Down
32 changes: 32 additions & 0 deletions src/main/java/dev/cerus/mcheadrender/filter/Filter.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package dev.cerus.mcheadrender.filter;

import java.awt.image.BufferedImage;

/**
* Applies some sort of visual effect onto the final image
*/
public abstract class Filter {

/**
* Apply the filter
*
* @param img The image that should be filtered
*/
public abstract void apply(BufferedImage img);

public abstract String id();

@Override
public int hashCode() {
return this.id().hashCode();
}

@Override
public boolean equals(final Object obj) {
if (!(obj instanceof Filter)) {
return false;
}
return obj == this || ((Filter) obj).id().equals(this.id());
}

}
28 changes: 28 additions & 0 deletions src/main/java/dev/cerus/mcheadrender/filter/GrayscaleFilter.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package dev.cerus.mcheadrender.filter;

import java.awt.Color;
import java.awt.image.BufferedImage;

/**
* Grayscales an image
*/
public class GrayscaleFilter extends Filter {

@Override
public void apply(final BufferedImage img) {
for (int x = 0; x < img.getWidth(); x++) {
for (int y = 0; y < img.getHeight(); y++) {
final int pixel = img.getRGB(x, y);
final Color color = new Color(pixel, true);
final int avg = (color.getRed() + color.getGreen() + color.getBlue()) / 3;
img.setRGB(x, y, new Color(avg, avg, avg, color.getAlpha()).getRGB());
}
}
}

@Override
public String id() {
return "grayscale";
}

}
32 changes: 32 additions & 0 deletions src/main/java/dev/cerus/mcheadrender/filter/InvertFilter.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package dev.cerus.mcheadrender.filter;

import java.awt.Color;
import java.awt.image.BufferedImage;

/**
* Inverts an image
*/
public class InvertFilter extends Filter {

@Override
public void apply(final BufferedImage img) {
for (int x = 0; x < img.getWidth(); x++) {
for (int y = 0; y < img.getHeight(); y++) {
final int pixel = img.getRGB(x, y);
final Color color = new Color(pixel, true);
img.setRGB(x, y, new Color(
255 - color.getRed(),
255 - color.getGreen(),
255 - color.getBlue(),
color.getAlpha()
).getRGB());
}
}
}

@Override
public String id() {
return "invert";
}

}
12 changes: 11 additions & 1 deletion src/main/java/dev/cerus/mcheadrender/web/WebServer.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package dev.cerus.mcheadrender.web;

import dev.cerus.mcheadrender.filter.Filter;
import dev.cerus.mcheadrender.image.ImageCache;
import dev.cerus.mcheadrender.renderer.Renderer;
import dev.cerus.mcheadrender.skin.SkinProvider;
Expand All @@ -17,11 +18,16 @@ public class WebServer {
private final Registry<Renderer> rendererRegistry;
private final Registry<SkinProvider> skinProviderRegistry;
private final ImageCache imageCache;
private final Registry<Filter> filterRegistry;
private Javalin app;

public WebServer(final Registry<Renderer> rendererRegistry, final Registry<SkinProvider> skinProviderRegistry, final ImageCache imageCache) {
public WebServer(final Registry<Renderer> rendererRegistry,
final Registry<SkinProvider> skinProviderRegistry,
final Registry<Filter> filterRegistry,
final ImageCache imageCache) {
this.rendererRegistry = rendererRegistry;
this.skinProviderRegistry = skinProviderRegistry;
this.filterRegistry = filterRegistry;
this.imageCache = imageCache;
}

Expand Down Expand Up @@ -66,4 +72,8 @@ public Registry<SkinProvider> getSkinProviderRegistry() {
return this.skinProviderRegistry;
}

public Registry<Filter> getFilterRegistry() {
return this.filterRegistry;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import dev.cerus.mcheadrender.Globals;
import static dev.cerus.mcheadrender.Globals.LOGGER;
import dev.cerus.mcheadrender.filter.Filter;
import dev.cerus.mcheadrender.image.ImageCache;
import dev.cerus.mcheadrender.renderer.Renderer;
import dev.cerus.mcheadrender.skin.SkinProvider;
Expand All @@ -15,8 +16,10 @@
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Objects;
import javax.imageio.ImageIO;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
Expand Down Expand Up @@ -88,6 +91,17 @@ public void handle(@NotNull final Context ctx) throws Exception {
}

final BufferedImage renderedHead = renderer.render(image, size, overlay);

final List<Filter> filters = ctx.queryParams("filter").stream()
.flatMap(s -> Arrays.stream(s.split(",")))
.map(s -> this.webServer.getFilterRegistry().get(s))
.filter(Objects::nonNull)
.distinct()
.toList();
for (final Filter filter : filters) {
filter.apply(renderedHead);
}

this.img(ctx, renderedHead);
}

Expand All @@ -112,7 +126,9 @@ public void handle(@NotNull final Context ctx) throws Exception {
new QueryParam("skin", "The skin provider", String.class, true,
List.copyOf(this.webServer.getSkinProviderRegistry().ids()), null, "mojang"),
new QueryParam("renderer", "The renderer", String.class, true,
List.of("flat", "isometric"), null, "flat"),
List.copyOf(this.webServer.getRendererRegistry().ids()), null, "flat"),
new QueryParam("filter", "The filters (concatenate filters with ,)", String.class, true,
List.copyOf(this.webServer.getFilterRegistry().ids()), null, null),
new QueryParam("size", "The desired width and height", int.class, true,
null, List.of("128", "512", "16"), "8"),
new QueryParam("overlay", "Whether the hat overlay should be rendered or not",
Expand Down

0 comments on commit 7f078e7

Please sign in to comment.