
com.threerings.resource.Handler Maven / Gradle / Ivy
//
// Nenya library - tools for developing networked games
// Copyright (C) 2002-2012 Three Rings Design, Inc., All Rights Reserved
// https://github.com/threerings/nenya
//
// This library is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation; either version 2.1 of the License, or
// (at your option) any later version.
//
// This library 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
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
package com.threerings.resource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLStreamHandler;
import java.security.Permission;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.awt.Rectangle;
import java.awt.image.BufferedImage;
import javax.imageio.ImageIO;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.samskivert.io.ByteArrayOutInputStream;
import com.samskivert.net.AttachableURLFactory;
import com.samskivert.util.StringUtil;
import com.threerings.media.image.ColorPository;
import com.threerings.media.image.Colorization;
import com.threerings.media.image.ImageUtil;
import com.threerings.geom.GeomUtil;
import static com.threerings.resource.Log.log;
/**
* This class is not used directly, except by a registering ResourceManager so that we can load
* data from the resource manager using URLs of the form
* resource://<resourceSet>/<path>
. ResourceSet may be the empty string
* to load from the default resource sets.
*/
public class Handler extends URLStreamHandler
{
/**
* Register this class to handle "resource" urls ("resource://resourceSet/path")
* with the specified ResourceManager.
*/
public static void registerHandler (ResourceManager rmgr)
{
// we only want to wire up our Handler once, but if a new resource
// manager comes along, we'll point the existing handler there
if (_rmgr == null) {
// wire up our handler with the handy dandy attachable URL factory
AttachableURLFactory.attachHandler("resource", Handler.class);
}
_rmgr = rmgr;
}
@Override
protected int hashCode (URL url)
{
return String.valueOf(url).hashCode();
}
@Override
protected boolean equals (URL u1, URL u2)
{
return String.valueOf(u1).equals(String.valueOf(u2));
}
@Override
protected URLConnection openConnection (URL url)
throws IOException
{
return new URLConnection(url) {
@Override
public void connect ()
throws IOException
{
// the host is the bundle name
String bundle = this.url.getHost();
// and we need to remove the leading '/' from path;
String path = this.url.getPath().substring(1);
try {
// if there are query parameters, we need special magic
String query = url.getQuery();
if (!StringUtil.isBlank(query)) {
_stream = getStream(bundle, path, query);
} else if (StringUtil.isBlank(bundle)) {
_stream = _rmgr.getResource(path);
} else {
_stream = _rmgr.getResource(bundle, path);
}
this.connected = true;
} catch (IOException ioe) {
log.warning("Could not find resource",
"url", this.url, "error", ioe.getMessage());
throw ioe; // rethrow
}
}
@Override
public InputStream getInputStream ()
throws IOException
{
if (!this.connected) {
connect();
}
return _stream;
}
@Override
public Permission getPermission ()
throws IOException
{
// We allow anything in the resource bundle to be loaded
// without any permission restrictions.
return null;
}
protected InputStream _stream;
};
}
/**
* Does some magic to allow a subset of an image to be extracted, reencoded as a PNG and then
* spat back out to the Java content handler system for inclusion in internal documentation.
*/
protected InputStream getStream (String bundle, String path, String query)
throws IOException
{
// we can only do this with PNGs
if (!path.endsWith(".png")) {
log.warning("Requested sub-tile of non-PNG resource",
"bundle", bundle, "path", path, "dims", query);
return _rmgr.getResource(bundle, path);
}
// parse the query string
String[] bits = StringUtil.split(query, "&");
int width = -1, height = -1, tidx = -1;
HashMap zations = null;
try {
for (String bit : bits) {
if (bit.startsWith("width=")) {
width = Integer.parseInt(bit.substring(6));
} else if (bit.startsWith("height=")) {
height = Integer.parseInt(bit.substring(7));
} else if (bit.startsWith("tile=")) {
tidx = Integer.parseInt(bit.substring(5));
} else if (bit.startsWith("zation=")) {
String[] zation = bit.substring(7).split(":");
if (zations == null) {
zations = Maps.newHashMap();
}
zations.put(zation[0], zation[1]);
}
}
} catch (NumberFormatException nfe) {
}
if (width <= 0 || height <= 0 || tidx < 0) {
log.warning("Bogus sub-image dimensions",
"bundle", bundle, "path", path, "dims", query);
throw new FileNotFoundException(path);
}
// locate the tile image, then write that subimage back out in PNG format into memory and
// return an input stream for that
BufferedImage src = StringUtil.isBlank(bundle) ?
_rmgr.getImageResource(path) : _rmgr.getImageResource(bundle, path);
Rectangle trect = GeomUtil.getTile(src.getWidth(), src.getHeight(), width, height, tidx);
BufferedImage tile = src.getSubimage(trect.x, trect.y, trect.width, trect.height);
if (zations != null) {
ColorPository pository = ColorPository.loadColorPository(_rmgr);
ArrayList colorizations = Lists.newArrayList();
for (Map.Entry entry : zations.entrySet()) {
String zClass = entry.getKey();
String zColor = entry.getValue();
Colorization zation = null;
// First try looking if we got a number
try {
zation = pository.getColorization(zClass, Integer.parseInt(zColor));
} catch (NumberFormatException nfe) { }
// If that didn't work, try it as a zation name
if (zation == null) {
zation = pository.getColorization(zClass, zColor);
}
if (zation == null) {
log.warning("Couldn't figure out requested zation",
"class", zClass, "color", zColor);
} else {
colorizations.add(zation);
}
}
tile = ImageUtil.recolorImage(tile,
colorizations.toArray(new Colorization[colorizations.size()]));
}
ByteArrayOutInputStream data = new ByteArrayOutInputStream();
ImageIO.write(tile, "PNG", data);
return data.getInputStream();
}
/** Our singleton resource manager. */
protected static ResourceManager _rmgr;
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy