Updated recolorization tool to be more useful in creating colorizations and in viewing colorizations of art. Now has two modes:
- View all colorization mode shows all the colorizations of a selection colorization class for the image. - Normal mode allows modification by sliders of the colorization parameters. git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@3886 542714f4-19e9-0310-aa3c-eee0fc999fb1
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// $Id: RecolorImage.java,v 1.6 2004/08/27 02:12:46 mdb Exp $
|
||||
// $Id$
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2004 Three Rings Design, Inc., All Rights Reserved
|
||||
@@ -23,7 +23,11 @@ package com.threerings.media.tools;
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Color;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Rectangle;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.Collections;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.awt.event.MouseAdapter;
|
||||
@@ -31,6 +35,7 @@ import java.awt.event.MouseEvent;
|
||||
import java.awt.image.BufferedImage;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
@@ -38,17 +43,27 @@ import javax.imageio.ImageIO;
|
||||
import javax.swing.BorderFactory;
|
||||
import javax.swing.ImageIcon;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JComboBox;
|
||||
import javax.swing.JFileChooser;
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.JSlider;
|
||||
import javax.swing.JTextField;
|
||||
import javax.swing.JToggleButton;
|
||||
import javax.swing.event.ChangeEvent;
|
||||
import javax.swing.event.ChangeListener;
|
||||
|
||||
import com.samskivert.swing.HGroupLayout;
|
||||
import com.samskivert.swing.IntField;
|
||||
import com.samskivert.swing.VGroupLayout;
|
||||
import com.samskivert.swing.event.DocumentAdapter;
|
||||
import com.samskivert.swing.util.SwingUtil;
|
||||
import com.samskivert.util.Interator;
|
||||
|
||||
import com.threerings.media.image.ColorPository;
|
||||
import com.threerings.media.image.Colorization;
|
||||
import com.threerings.media.image.ImageUtil;
|
||||
|
||||
/**
|
||||
@@ -70,6 +85,7 @@ public class RecolorImage extends JPanel
|
||||
images.add(_newImage = new JLabel());
|
||||
add(new JScrollPane(images));
|
||||
|
||||
// Image file
|
||||
JPanel file = new JPanel(new HGroupLayout(HGroupLayout.STRETCH));
|
||||
file.add(new JLabel("Image file:"), HGroupLayout.FIXED);
|
||||
file.add(_imagePath = new JTextField());
|
||||
@@ -78,11 +94,39 @@ public class RecolorImage extends JPanel
|
||||
browse.setActionCommand("browse");
|
||||
browse.addActionListener(this);
|
||||
file.add(browse, HGroupLayout.FIXED);
|
||||
JButton reload = new JButton("Reload");
|
||||
reload.setActionCommand("reload");
|
||||
reload.addActionListener(this);
|
||||
file.add(reload, HGroupLayout.FIXED);
|
||||
add(file, VGroupLayout.FIXED);
|
||||
|
||||
// Colorization file
|
||||
JPanel colFile = new JPanel(new HGroupLayout(HGroupLayout.STRETCH));
|
||||
colFile.add(new JLabel("Colorize file:"), HGroupLayout.FIXED);
|
||||
colFile.add(_colFilePath = new JTextField());
|
||||
_colFilePath.setEditable(false);
|
||||
browse = new JButton("Browse...");
|
||||
browse.setActionCommand("browse_colorize");
|
||||
browse.addActionListener(this);
|
||||
colFile.add(browse, HGroupLayout.FIXED);
|
||||
add(colFile, VGroupLayout.FIXED);
|
||||
|
||||
JPanel colMode = new JPanel(new HGroupLayout(HGroupLayout.STRETCH));
|
||||
colMode.add(_mode = new JToggleButton("All Colorizations"));
|
||||
colMode.add(_classList = new JComboBox());
|
||||
ActionListener al = new ActionListener () {
|
||||
public void actionPerformed (ActionEvent ae) {
|
||||
convert();
|
||||
}
|
||||
};
|
||||
_mode.addActionListener(al);
|
||||
_classList.addActionListener(al);
|
||||
|
||||
add(colMode, VGroupLayout.FIXED);
|
||||
|
||||
JPanel controls = new JPanel(new HGroupLayout(HGroupLayout.STRETCH));
|
||||
controls.add(new JLabel("Source color:"), HGroupLayout.FIXED);
|
||||
controls.add(_source = new JTextField());
|
||||
controls.add(_source = new JTextField("FF0000"));
|
||||
_colorLabel = new JPanel();
|
||||
_colorLabel.setSize(48, 48);
|
||||
_colorLabel.setOpaque(true);
|
||||
@@ -98,17 +142,17 @@ public class RecolorImage extends JPanel
|
||||
HGroupLayout hlay = new HGroupLayout(HGroupLayout.STRETCH);
|
||||
JPanel dists = new JPanel(hlay);
|
||||
dists.add(new JLabel("HSV distances:"), HGroupLayout.FIXED);
|
||||
dists.add(_hueD = new JTextField("0.05"));
|
||||
dists.add(_saturationD = new JTextField("0.8"));
|
||||
dists.add(_valueD = new JTextField("0.6"));
|
||||
dists.add(_hueD = new SliderAndLabel(0.0f, 1.0f, 0.05f));
|
||||
dists.add(_saturationD = new SliderAndLabel(0.0f, 1.0f, 0.8f));
|
||||
dists.add(_valueD = new SliderAndLabel(0.0f, 1.0f, 0.6f));
|
||||
add(dists, VGroupLayout.FIXED);
|
||||
|
||||
hlay = new HGroupLayout(HGroupLayout.STRETCH);
|
||||
JPanel offsets = new JPanel(hlay);
|
||||
offsets.add(new JLabel("HSV offsets:"), HGroupLayout.FIXED);
|
||||
offsets.add(_hueO = new JTextField("0.1"));
|
||||
offsets.add(_saturationO = new JTextField("0.0"));
|
||||
offsets.add(_valueO = new JTextField("0.0"));
|
||||
offsets.add(_hueO = new SliderAndLabel(-1.0f, 1.0f, 0.1f));
|
||||
offsets.add(_saturationO = new SliderAndLabel(-1.0f, 1.0f, 0.0f));
|
||||
offsets.add(_valueO = new SliderAndLabel(-1.0f, 1.0f, 0.0f));
|
||||
add(offsets, VGroupLayout.FIXED);
|
||||
|
||||
add(_status = new JTextField(), VGroupLayout.FIXED);
|
||||
@@ -134,40 +178,98 @@ public class RecolorImage extends JPanel
|
||||
String cwd = System.getProperty("user.dir");
|
||||
if (cwd == null) {
|
||||
_chooser = new JFileChooser();
|
||||
_colChooser = new JFileChooser();
|
||||
} else {
|
||||
_chooser = new JFileChooser(cwd);
|
||||
_colChooser = new JFileChooser(cwd);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs colorizations.
|
||||
*/
|
||||
protected void convert ()
|
||||
{
|
||||
if (_image == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// obtain the target color and offset
|
||||
try {
|
||||
BufferedImage image;
|
||||
if (_mode.isSelected()) {
|
||||
// All recolorings from file.
|
||||
image = getAllRecolors();
|
||||
if (image == null) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
// Normal recoloring
|
||||
int color = Integer.parseInt(_source.getText(), 16);
|
||||
|
||||
float hueD = _hueD.getValue();
|
||||
float satD = _saturationD.getValue();
|
||||
float valD = _valueD.getValue();
|
||||
float[] dists = new float[] { hueD, satD, valD };
|
||||
|
||||
float hueO = _hueO.getValue();
|
||||
float satO = _saturationO.getValue();
|
||||
float valO = _valueO.getValue();
|
||||
float[] offsets = new float[] { hueO, satO, valO };
|
||||
|
||||
image = ImageUtil.recolorImage(
|
||||
_image, new Color(color), dists, offsets);
|
||||
}
|
||||
_newImage.setIcon(new ImageIcon(image));
|
||||
_status.setText("Recolored image.");
|
||||
repaint();
|
||||
|
||||
} catch (NumberFormatException nfe) {
|
||||
_status.setText("Invalid value: " + nfe.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an image with all recolorings of the selection colorization class.
|
||||
*/
|
||||
public BufferedImage getAllRecolors ()
|
||||
{
|
||||
if (_colRepo == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
ColorPository.ClassRecord colClass =
|
||||
_colRepo.getClassRecord((String)_classList.getSelectedItem());
|
||||
int classId = colClass.classId;
|
||||
|
||||
ArrayList imgs = new ArrayList();
|
||||
Interator iter = colClass.colors.keys();
|
||||
BufferedImage img = new BufferedImage(_image.getWidth(),
|
||||
_image.getHeight()*colClass.colors.size(),
|
||||
BufferedImage.TYPE_INT_ARGB);
|
||||
Graphics gfx = img.getGraphics();
|
||||
int y = 0;
|
||||
|
||||
while (iter.hasNext()) {
|
||||
Colorization coloriz =
|
||||
_colRepo.getColorization(classId, iter.nextInt());
|
||||
BufferedImage subImg = ImageUtil.recolorImage(
|
||||
_image, coloriz.rootColor, coloriz.range, coloriz.offsets);
|
||||
|
||||
gfx.drawImage(subImg, 0, y, null, null);
|
||||
|
||||
y += subImg.getHeight();
|
||||
}
|
||||
|
||||
return img;
|
||||
}
|
||||
|
||||
public void actionPerformed (ActionEvent event)
|
||||
{
|
||||
String cmd = event.getActionCommand();
|
||||
|
||||
if (cmd.equals("convert")) {
|
||||
// obtain the target color and offset
|
||||
try {
|
||||
int color = Integer.parseInt(_source.getText(), 16);
|
||||
|
||||
float hueD = Float.parseFloat(_hueD.getText());
|
||||
float satD = Float.parseFloat(_saturationD.getText());
|
||||
float valD = Float.parseFloat(_valueD.getText());
|
||||
float[] dists = new float[] { hueD, satD, valD };
|
||||
|
||||
float hueO = Float.parseFloat(_hueO.getText());
|
||||
float satO = Float.parseFloat(_saturationO.getText());
|
||||
float valO = Float.parseFloat(_valueO.getText());
|
||||
float[] offsets = new float[] { hueO, satO, valO };
|
||||
|
||||
BufferedImage image = ImageUtil.recolorImage(
|
||||
_image, new Color(color), dists, offsets);
|
||||
_newImage.setIcon(new ImageIcon(image));
|
||||
_status.setText("Recolored image.");
|
||||
repaint();
|
||||
|
||||
} catch (NumberFormatException nfe) {
|
||||
_status.setText("Invalid value: " + nfe.getMessage());
|
||||
}
|
||||
|
||||
convert();
|
||||
} else if (cmd.equals("update")) {
|
||||
// obtain the target color and offset
|
||||
try {
|
||||
@@ -177,9 +279,9 @@ public class RecolorImage extends JPanel
|
||||
float[] thsv = rgbToHSV(target);
|
||||
|
||||
// set the offsets based on the differences
|
||||
_hueO.setText("" + (thsv[0] - shsv[0]));
|
||||
_saturationO.setText("" + (thsv[1] - shsv[1]));
|
||||
_valueO.setText("" + (thsv[2] - shsv[2]));
|
||||
_hueO.setValue(thsv[0] - shsv[0]);
|
||||
_saturationO.setValue(thsv[1] - shsv[1]);
|
||||
_valueO.setValue(thsv[2] - shsv[2]);
|
||||
|
||||
} catch (NumberFormatException nfe) {
|
||||
_status.setText("Invalid value: " + nfe.getMessage());
|
||||
@@ -190,6 +292,13 @@ public class RecolorImage extends JPanel
|
||||
if (result == JFileChooser.APPROVE_OPTION) {
|
||||
setImage(_chooser.getSelectedFile());
|
||||
}
|
||||
} else if (cmd.equals("reload")) {
|
||||
setImage(_chooser.getSelectedFile());
|
||||
} else if (cmd.equals("browse_colorize")) {
|
||||
int result = _colChooser.showOpenDialog(this);
|
||||
if (result == JFileChooser.APPROVE_OPTION) {
|
||||
setColorizeFile(_colChooser.getSelectedFile());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -205,6 +314,37 @@ public class RecolorImage extends JPanel
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads up the colorization classes from the specified file.
|
||||
*/
|
||||
public void setColorizeFile (File path)
|
||||
{
|
||||
try {
|
||||
_colRepo =
|
||||
ColorPository.loadColorPository(new FileInputStream(path));
|
||||
|
||||
_classList.removeAllItems();
|
||||
Iterator iter = _colRepo.enumerateClasses();
|
||||
ArrayList names = new ArrayList();
|
||||
while (iter.hasNext()) {
|
||||
String str = ((ColorPository.ClassRecord)iter.next()).name;
|
||||
names.add(str);
|
||||
}
|
||||
|
||||
Collections.sort(names);
|
||||
|
||||
iter = names.iterator();
|
||||
while (iter.hasNext()) {
|
||||
_classList.addItem((String)iter.next());
|
||||
}
|
||||
|
||||
_classList.setSelectedIndex(0);
|
||||
_colFilePath.setText(path.getPath());
|
||||
} catch (Exception ex) {
|
||||
_status.setText("Error opening colorization file: " + ex);
|
||||
}
|
||||
}
|
||||
|
||||
protected static float[] rgbToHSV (int rgb)
|
||||
{
|
||||
float[] hsv = new float[3];
|
||||
@@ -229,6 +369,48 @@ public class RecolorImage extends JPanel
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Class with linked slider and label arranged vertically.
|
||||
*/
|
||||
protected class SliderAndLabel extends JPanel
|
||||
{
|
||||
public SliderAndLabel (float minf, float maxf, float valuef)
|
||||
{
|
||||
int min = (int)(minf*CONVERSION);
|
||||
int max = (int)(maxf*CONVERSION);
|
||||
int value = (int)(valuef*CONVERSION);
|
||||
setLayout(new VGroupLayout(VGroupLayout.STRETCH));
|
||||
_intField = new JLabel(String.valueOf(value/CONVERSION));
|
||||
_slider = new JSlider(min, max, value);
|
||||
|
||||
_slider.addChangeListener(new ChangeListener() {
|
||||
public void stateChanged (ChangeEvent ce) {
|
||||
_intField.setText(String.valueOf(
|
||||
((float)_slider.getValue())/CONVERSION));
|
||||
|
||||
convert();
|
||||
}
|
||||
});
|
||||
add(_intField);
|
||||
add(_slider);
|
||||
}
|
||||
|
||||
public float getValue ()
|
||||
{
|
||||
return _slider.getValue()/CONVERSION;
|
||||
}
|
||||
|
||||
public void setValue (float val)
|
||||
{
|
||||
_slider.setValue((int)(val*CONVERSION));
|
||||
}
|
||||
|
||||
protected JSlider _slider;
|
||||
protected JLabel _intField;
|
||||
|
||||
protected final static float CONVERSION = 1000.0f;
|
||||
}
|
||||
|
||||
public static void main (String[] args)
|
||||
{
|
||||
try {
|
||||
@@ -255,7 +437,9 @@ public class RecolorImage extends JPanel
|
||||
|
||||
protected BufferedImage _image;
|
||||
protected JFileChooser _chooser;
|
||||
protected JFileChooser _colChooser;
|
||||
protected JTextField _imagePath;
|
||||
protected JTextField _colFilePath;
|
||||
|
||||
protected JLabel _oldImage;
|
||||
protected JLabel _newImage;
|
||||
@@ -264,16 +448,21 @@ public class RecolorImage extends JPanel
|
||||
protected JTextField _source;
|
||||
protected JTextField _target;
|
||||
|
||||
protected JTextField _hueO;
|
||||
protected JTextField _saturationO;
|
||||
protected JTextField _valueO;
|
||||
protected SliderAndLabel _hueO;
|
||||
protected SliderAndLabel _saturationO;
|
||||
protected SliderAndLabel _valueO;
|
||||
|
||||
protected JTextField _hueD;
|
||||
protected JTextField _saturationD;
|
||||
protected JTextField _valueD;
|
||||
protected SliderAndLabel _hueD;
|
||||
protected SliderAndLabel _saturationD;
|
||||
protected SliderAndLabel _valueD;
|
||||
|
||||
protected JTextField _status;
|
||||
|
||||
protected JComboBox _classList;
|
||||
protected JToggleButton _mode;
|
||||
|
||||
protected ColorPository _colRepo;
|
||||
|
||||
protected static final String IMAGE_PATH =
|
||||
// "bundles/components/pirate/torso/regular/standing.png";
|
||||
"bundles/components/pirate/head/regular/standing.png";
|
||||
|
||||
Reference in New Issue
Block a user