/* * Copyright 2014 SATO taichi * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package ninja.siden.sirusi; import io.undertow.server.HttpHandler; import io.undertow.server.handlers.cache.CacheHandler; import io.undertow.server.handlers.cache.DirectBufferCache; import io.undertow.util.MimeMappings; import java.awt.Color; import java.awt.Graphics2D; import java.awt.geom.AffineTransform; import java.awt.image.AffineTransformOp; import java.awt.image.BufferedImage; import java.io.IOException; import java.io.OutputStream; import java.math.BigInteger; import java.util.Arrays; import java.util.HashSet; import java.util.Objects; import java.util.Random; import java.util.Set; import java.util.regex.Pattern; import javax.imageio.ImageIO; import ninja.siden.App; import ninja.siden.Config; import ninja.siden.Renderer; import ninja.siden.Request; import ninja.siden.Response; import ninja.siden.internal.Core; import org.xnio.OptionMap; /** * @author taichi */ public class Sirusi { public static void main(String[] args) { App app = new App() { @Override protected HttpHandler wrap(OptionMap config, HttpHandler handler) { DirectBufferCache cache = new DirectBufferCache(1024, 10, 1024 * 1024 * 200); return new CacheHandler(cache, super.wrap(config, handler)); } }; new Sirusi(app); app.listen(port()).asShutdownHook(); } static int port() { String port = Objects.toString(System.getenv("PORT"), "8080"); if (Pattern.matches("\\d{1,5}", port)) { int i = Integer.parseInt(port); if (0 < i && i < 65536) { return i; } } return 8080; } Set<String> types; public Sirusi(App app) { app.get("/favicon.ico", (req, res) -> getClass().getClassLoader() .getResource("favicon.ico")); app.get("/:seed.:type", this::identicon); app.get("/", (req, res) -> "I'm running!! yey!"); this.types = new HashSet<>(Arrays.asList(ImageIO .getWriterFileSuffixes())); } public Object identicon(Request req, Response res) throws Exception { String seed = req.params("seed").orElse("0000000"); String type = req.params("type") .filter(s -> types.contains(s.toLowerCase())).orElse("png"); int size = req.query("s").filter(s -> s.matches("\\d{1,3}")) .map(Integer::parseInt).filter(i -> i < 4097).orElse(48); MimeMappings mm = req.raw().getAttachment(Core.CONFIG) .get(Config.MIME_MAPPINGS); res.type(mm.getMimeType(type)); return res.render(seed, Renderer.ofStream((p, os) -> { render(seed, size, type, os); })); } public void render(String seed, int size, String formatName, OutputStream out) throws IOException { Random r = new Random(new BigInteger(seed.getBytes()).longValue()); int[] kinds = { 5, 6, 7 }; int boxel = kinds[Math.abs(r.nextInt()) % 3]; BufferedImage original = make(r, boxel); BufferedImage img = resize(boxel, original, size); ImageIO.write(img, formatName, out); } BufferedImage make(Random r, int boxel) { BufferedImage img = square(boxel); int fa = Math.abs(r.nextInt()); int ba = Color.WHITE.getRGB(); int half = (boxel - (boxel % 2)) / 2 + 1; for (int x = 0; x < half; x++) { for (int y = 0; y < boxel; y++) { int col = r.nextBoolean() ? ba : fa; img.setRGB(x, y, col); img.setRGB(boxel - 1 - x, y, col); } } return img; } BufferedImage resize(int boxel, BufferedImage src, int size) { int mod = size % boxel; int scale = (size - mod) / boxel; AffineTransform at = new AffineTransform(); at.scale(scale, scale); AffineTransformOp op = new AffineTransformOp(at, AffineTransformOp.TYPE_NEAREST_NEIGHBOR); BufferedImage out = square(size); Graphics2D g2d = out.createGraphics(); g2d.setColor(Color.WHITE); g2d.fillRect(0, 0, size, size); g2d.dispose(); int border = mod / 2; op.filter( src, out.getSubimage(border, border, out.getWidth() - border, out.getHeight() - border)); return out; } BufferedImage square(int size) { return new BufferedImage(size, size, BufferedImage.TYPE_INT_BGR); } }