Home » MODDING HQ 1.13 » v1.13 Coding Talk » Doubling image size
Doubling image size[message #247198]
|
Wed, 17 March 2010 05:36
|
|
Nephut |
Messages:4
Registered:March 2010 |
|
|
I am coding a Java-program that doubles (x and y) the image sizes of JA2 tiles, characters and objects. It should work for 8-bit non-animated files (single image) and 8-bit animated files (multiple images). It will not work for 16-bit files.
The program does the following:
1. read every sti-file in one folder and process images one by one
2. uncompress an image into an internal datastructure
3. double the size (2*2)
4. filter the image
5. compress the image
6. save them to sti-files
The filtering far from perfect and it is probably not a very text-book approach. I have been coding it in an ad-hoc -style, trying something and seeing if it works. I have concentrated on these aspects:
- keep unchanged as many pixels as possible (most filtering is only done on every other line)
- remove blockiness due to 2*2 doubling
- make lines straight; especially 45 degrees and those parallel to tile edges
- keep line thicknesses unchanged
In addition the program processes edges of characters. It corrects color-types (hair, shirt, ...) of some dark pixels in the edge and draws a thin line around characters.
Check out these images before and after double-sizing (click for higher resolution):
![http://img689.imageshack.us/img689/4053/ja2hq3.jpg](http://img689.imageshack.us/img689/4053/ja2hq3.jpg)
I extracted the following sti-files out of slf-files ANIMS.SLF and TILESETS.SLF:
Data/Anims/F_MERC/*
Data/Anims/M_MERC/*
Data/Anims/S_MERC/*
tilesets/0/* (excluding subdirectories)
and processed them (about 450 sti-files) with the program. The program ran about 15 minutes (2.4 GHz Core 2 Duo). This is how it looks in-game:
![http://img219.imageshack.us/img219/7702/ja2hq4.jpg](http://img219.imageshack.us/img219/7702/ja2hq4.jpg)
Here double-sized are: characters, rooftops, fence , square (below hand), footsteps, bushes, part of road, debris, ...
I haven't tested almost anything in-game, but here are some observations. Scrolling seems to work ok. While walking the mercs tread somewhat, because real distances have not doubled. They can for instance crouch or hop over the fence. The tab above active merc leaves artifacts when walking left. Moving cursor over the artifacts wipes them. The cursor needs to be placed slightly down and right to select a merc.
Report message to a moderator
|
Civilian
|
|
|
Re: Doubling image size[message #247233]
|
Thu, 18 March 2010 03:19 ![Go to previous message Go to previous message](/theme/Bear_Classic_Brown/images/up.png)
|
|
CptMoore |
![](/images/ranks/sergeant_1stclass.png) |
Messages:224
Registered:March 2009 |
|
|
Nice demo. You could add more freely adjustable scaling like 1.5 instead of 2x. That'll be added challenge.
Report message to a moderator
|
Sergeant 1st Class
|
|
|
|
|
|
Re: Doubling image size[message #247252]
|
Thu, 18 March 2010 10:59 ![Go to previous message Go to previous message](/theme/Bear_Classic_Brown/images/up.png)
|
|
Nephut |
Messages:4
Registered:March 2010 |
|
|
Thanks for your replies!
I implemented 2x smaller by picking every other pixel from every other line.
It's difficult to come up with anything better when the palette is only 256 colors.
This is how it looks in-game (same sti-files):
![http://img705.imageshack.us/img705/1523/ja2hq5.jpg](http://img705.imageshack.us/img705/1523/ja2hq5.jpg)
Here is the java source code "StiDouble.java":
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
public class StiDouble {
boolean zoomIn = true;
boolean processEdges = false;
String folderIn = "";
String folderOut = "";
public static void main(String[] args) {
StiDouble sd = new StiDouble();
if (args.length != 4) {
System.out.println("ERROR: Incorrect number of arguments.");
}
if (args[0].equals("I")) { //zoom in
sd.zoomIn = true;
} else if (args[0].equals("O")) { //zoom out
sd.zoomIn = false;
} else {
System.out.println("ERROR: 1. argument incorrect.");
return;
}
if (args[1].equals("N")) { //no edge processing
sd.processEdges = false;
} else if (args[1].equals("P")) { //edge processing
sd.processEdges = true;
} else {
System.out.println("ERROR: 2. argument incorrect.");
return;
}
sd.folderIn = args[2];
sd.folderOut = args[3];
sd.ProcessFiles();
}
private void ProcessFiles () {
File dir = new File(folderIn);
String[] files = dir.list();
for (int i=0; i dataIn = new ArrayList();
List dataOut = new ArrayList();
ReadFile(filenameIn, dataIn);
//process only sti-files
if (filenameIn.endsWith(".sti") == false &&
filenameIn.endsWith(".Sti") == false &&
filenameIn.endsWith(".STI") == false)
return;
//process only if starts with "STCI"
if (dataIn.size() < 64 ||
dataIn.get(0) != 0x53 ||
dataIn.get(1) != 0x54 ||
dataIn.get(2) != 0x43 ||
dataIn.get(3) != 0x49)
return;
int stitype = dataIn.get(16);
if (stitype == 4) { //16-bit file
//does not process 16-bit files
} else if (stitype == 40) { //8-bit non-animated file (single image)
Process8BitFile (dataIn, dataOut);
WriteFile(filenameOut, dataOut);
System.out.println("Processed: " + filenameOut);
} else if (stitype == 41) { //8-bit animated file (multiple images)
Process8BitFile (dataIn, dataOut);
WriteFile(filenameOut, dataOut);
System.out.println("Processed: " + filenameOut);
}
return;
}
private void Process8BitFile (List dataIn, List dataOut)
{
List dataHeader = new ArrayList();
List dataImages = new ArrayList();
int sizeuncompressed = 0;
int sizecompressed = 0;
int imagecount = GetInt(dataIn, 28, 2);
int headerDataBegin = 832;
int imageDataBegin = headerDataBegin + 16 * imagecount;
for (int currentimage = 0; currentimage < imagecount; currentimage++)
{
StiImage image;
image = Read8BitImage(dataIn, currentimage, headerDataBegin, imageDataBegin);
if (zoomIn == false) {
image = image.HalfSize();
} else {
if (processEdges == true)
image = image.Char_FixColor();
image = image.DoubleSize();
image = image.Filter2x2();
if (processEdges == true)
image = image.Char_Hairline();
}
sizeuncompressed += image.getSize();
sizecompressed += Write8BitImage(image, dataHeader, dataImages, sizecompressed);
}
//Copy header and palette
for(int i = 0; i < 832; i++){
dataOut.add(new Byte(dataIn.get(i)));
}
//Set initial size of the image in bytes
SetInt(dataOut, 4, 4, sizeuncompressed);
//Set image size in bytes after compression
SetInt(dataOut, 8, 4, sizecompressed);
//Copy image headers
for(int i = 0; i < dataHeader.size(); i++){
dataOut.add(new Byte(dataHeader.get(i)));
}
//Copy images
for(int i = 0; i < dataImages.size(); i++){
dataOut.add(new Byte(dataImages.get(i)));
}
//Copy Additional application data
int headerpos = headerDataBegin + (imagecount-1) * 16;
int finalpos = GetInt(dataIn, headerpos + 0, 4) + GetInt(dataIn, headerpos + 4, 4) + imageDataBegin;
for (int i = finalpos; i < dataIn.size(); i++) {
dataOut.add(new Byte(dataIn.get(i)));
}
}
public StiImage Read8BitImage (List dataIn, int currentimage, int headerDataBegin, int ImageDataBegin)
{
int headerpos = headerDataBegin + currentimage * 16;
int imagepos = GetInt(dataIn, headerpos + 0, 4) + ImageDataBegin;
int compressedsize = GetInt(dataIn, headerpos + 4, 4);
int horizontalshift = GetInt(dataIn, headerpos + 8, 2);
int verticalshift = GetInt(dataIn, headerpos + 10, 2);
int height = GetInt(dataIn, headerpos + 12, 2);
int width = GetInt(dataIn, headerpos + 14, 2);
StiImage image = new StiImage(width, height, horizontalshift, verticalshift);
for (int i = 0; i < 256; i++) {
image.palette[i][0] = dataIn.get(64 + 3*i) & 0xFF;
image.palette[i][1] = dataIn.get(65 + 3*i) & 0xFF;
image.palette[i][2] = dataIn.get(66 + 3*i) & 0xFF;
}
int x = 1;
int y = 1;
int value;
int servicecount = 0;
for (int i = 0; i < compressedsize; i++) {
value = GetInt(dataIn, imagepos + i, 1);
if (value == 0) { //new line
y++;
x = 1;
servicecount = 0;
} else if (servicecount == 0) { //service byte
if ((value & 0x80) == 0x80) {
for (int j = 0; j < value-128; j++)
image.imagedata[x++][y] = 0;
servicecount = 0;
} else {
servicecount = value;
}
} else { //non-transparent
servicecount--;
image.imagedata[x++][y] = (byte) value;
}
}
return image;
}
public int Write8BitImage(StiImage image, List dataHeader, List dataImages, int sizecompressed)
{
int size = 0;
for (int y = 1; y <= image.height; y++) {
int x = 1;
while (x <= image.width) {
// process transparent bytes
if (image.imagedata[x][y] == 0) {
int count = 0;
while (x <= image.width && image.imagedata[x][y] == 0 && count < 127) {
count++;
x++;
}
dataImages.add(new Byte((byte) (0x80 + count)));
size++;
// process non-transparent bytes
} else {
int count = 0;
while (x+count <= image.width && image.imagedata[x+count][y] != 0 && count < 127) {
count++;
}
dataImages.add(new Byte((byte) count));
size++;
for (int i = 0; i < count; i++) {
dataImages.add(new Byte(image.imagedata[x+i][y]));
size++;
}
x += count;
}
}
dataImages.add(new Byte((byte) 0));
size++;
}
AddInt(dataHeader, 4, sizecompressed);
AddInt(dataHeader, 4, size);
AddInt(dataHeader, 2, image.horizontalshift);
AddInt(dataHeader, 2, image.verticalshift);
AddInt(dataHeader, 2, image.height);
AddInt(dataHeader, 2, image.width);
return size;
}
private static void ReadFile (String filenameIn, List list)
{
DataInputStream dis = null;
try {
dis = new DataInputStream(new FileInputStream(filenameIn));
while (dis.available() != 0) {
list.add(new Byte(dis.readByte()));
}
} catch (IOException ex) {
} finally {
if (dis != null) {
try {
dis.close();
} catch (IOException ex) {
}
}
}
}
private static void WriteFile (String filenameOut, List list)
{
DataOutputStream dos = null;
try {
dos = new DataOutputStream(new FileOutputStream(filenameOut));
for(int i = 0; i < list.size(); i++){
dos.writeByte(list.get(i));
}
} catch (IOException ex) {
} finally {
if (dos != null) {
try {
dos.close();
} catch (IOException ex) {
}
}
}
}
private class StiImage {
private int pixeltype[] = {
-1, 0, 0, 0, 0, 0, 0, 0, // 1=hair
0, 0, 0, 0, 0, 0, 0, 0, // 2=face and hands
0, 0, 0, 0, 0, 0, 0, 0, // 3=shirt
0, 0, 0, 0, 0, 0, 0, 0, // 4=legs
0, 0, 0, 0, 0, 0, 0, 0, // 5=other light/dark parts
0, 0, 0, 0, 0, 0, 0, 0, // 6=boots
0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, // 0=unused
0, 0, 0, 0, 0, 0, 0, 0, //-1=transparent
0, 0, 0, 0, 0, 0, 0, 0, //-2=blood
0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0, //
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, -2, -2,
-2, -2, -2, -2, -2, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 1, 1, 1,
1, 1, 1, 0, 0, 0, 0, 0
};
private int darkness[] = {
0, 0, 0, 0, 0, 0, 0, 0, //highest value for each type must be 90
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 30, 40,
50, 60, 70, 80, 90, 20, 25, 30,
35, 40, 45, 50, 55, 60, 65, 70,
75, 80, 85, 90, 10, 15, 20, 25,
30, 35, 40, 45, 50, 55, 60, 65,
70, 75, 80, 85, 90, 20, 25, 30,
35, 40, 45, 50, 55, 60, 65, 70,
75, 80, 85, 90, 20, 25, 30, 35,
40, 45, 50, 55, 60, 65, 70, 75,
80, 85, 90, 18, 26, 34, 42, 50,
58, 66, 74, 82, 90, 20, 34, 48,
62, 76, 90, 0, 0, 0, 0, 0
};
int width = 0;
int height = 0;
byte imagedata[][];
int horizontalshift = 0;
int verticalshift = 0;
int palette[][];
public StiImage (int w, int h, int hs, int vs)
{
this.width = w;
this.height = h;
horizontalshift = hs;
verticalshift = vs;
this.imagedata = new byte[w+2][h+2];
palette = new int[256][3];
}
public StiImage (StiImage oldimage)
{
this(oldimage.width, oldimage.height, oldimage.horizontalshift, oldimage.verticalshift);
for (int i = 0; i < 256; i++) {
this.palette[i][0] = oldimage.palette[i][0];
this.palette[i][1] = oldimage.palette[i][1];
this.palette[i][2] = oldimage.palette[i][2];
}
for (int y = 0; y <= this.height+1; y++) {
for (int x = 0; x <= this.width+1; x++) {
this.imagedata[x][y] = oldimage.imagedata[x][y];
}
}
}
public StiImage Rotate(boolean direction)
{
StiImage newimage = new StiImage(this.height, this.width, this.horizontalshift, this.verticalshift);
for (int i = 0; i < 256; i++) {
newimage.palette[i][0] = this.palette[i][0];
newimage.palette[i][1] = this.palette[i][1];
newimage.palette[i][2] = this.palette[i][2];
}
for (int y = 0; y <= this.height+1; y++) {
for (int x = 0; x <= this.width+1; x++) {
if (direction == true)
newimage.imagedata[height - y + 1][x] = this.imagedata[x][y];
else
newimage.imagedata[y][width - x + 1] = this.imagedata[x][y];
}
}
return newimage;
}
public StiImage Flip(boolean direction)
{
StiImage newimage = new StiImage(this.width, this.height, this.horizontalshift, this.verticalshift);
for (int i = 0; i < 256; i++) {
newimage.palette[i][0] = this.palette[i][0];
newimage.palette[i][1] = this.palette[i][1];
newimage.palette[i][2] = this.palette[i][2];
}
for (int y = 0; y <= this.height+1; y++) {
for (int x = 0; x <= this.width+1; x++) {
if (direction == true)
newimage.imagedata[x][height - y + 1] = this.imagedata[x][y];
else
newimage.imagedata[width - x + 1][y] = this.imagedata[x][y];
}
}
return newimage;
}
public StiImage DoubleSize ()
{
StiImage newimage = new StiImage(this.width * 2, this.height * 2,
this.horizontalshift * 2, this.verticalshift * 2);
for (int i = 0; i < 256; i++) {
newimage.palette[i][0] = this.palette[i][0];
newimage.palette[i][1] = this.palette[i][1];
newimage.palette[i][2] = this.palette[i][2];
}
for (int y = 1; y <= this.height; y++) {
for (int x = 1; x <= this.width; x++) {
newimage.imagedata[x*2-1][y*2-1] = this.imagedata[x][y];
newimage.imagedata[x*2-1][y*2] = this.imagedata[x][y];
newimage.imagedata[x*2] [y*2-1] = this.imagedata[x][y];
newimage.imagedata[x*2] [y*2] = this.imagedata[x][y];
}
}
return newimage;
}
public StiImage HalfSize ()
{
int hs = this.horizontalshift / 2;
if ((this.horizontalshift & 0x8000) != 0)
hs+= 0x8000;
int vs = this.verticalshift / 2;
if ((this.verticalshift & 0x8000) != 0)
vs+= 0x8000;
StiImage newimage = new StiImage((this.width+1) / 2, (this.height+1) / 2, hs, vs);
for (int i = 0; i < 256; i++) {
newimage.palette[i][0] = this.palette[i][0];
newimage.palette[i][1] = this.palette[i][1];
newimage.palette[i][2] = this.palette[i][2];
}
for (int y = 1; y <= (this.height+1) / 2; y++) {
for (int x = 1; x <= (this.width+1) / 2; x++) {
newimage.imagedata[x][y] = this.imagedata[x*2-1][y*2-1];
}
}
return newimage;
}
public StiImage Filter2x2 ()
{
StiImage newimage = new StiImage(this);
for (int i = 0; i < 2; i++) {
newimage = newimage.Filter2x2_Sub1();
newimage = newimage.Flip(false);
}
for (int i = 0; i < 2; i++) {
newimage = newimage.Filter2x2_Sub2();
newimage = newimage.Flip(false);
}
for (int i = 0; i < 2; i++) {
newimage = newimage.Filter2x2_Sub3();
newimage = newimage.Flip(false);
newimage = newimage.Filter2x2_Sub3();
newimage = newimage.Flip(true);
newimage = newimage.Filter2x2_Sub3();
newimage = newimage.Flip(false);
newimage = newimage.Filter2x2_Sub3();
newimage = newimage.Rotate(true);
}
return newimage;
}
public StiImage Filter2x2_Sub1 ()
{
int th1 = 48;
StiImage newimage = new StiImage(this);
for (int y = 2; y <= this.height; y+=2) {
for (int x = 1; x <= this.width; x+=2) {
int d1 = ColorDist(this.imagedata[x][y], this.imagedata[x+1][y+1]);
int d2 = ColorDist(this.imagedata[x][y], this.imagedata[x-1][y-1]);
int g1 = ColorDist(this.imagedata[x-1][y-1], this.imagedata[x+1][y+1]);
int g2 = ColorDist(this.imagedata[x-1][y+1], this.imagedata[x+1][y-1]);
if (g1 < th1 && //threshold
g1 < g2 && //gradient
g1 < d1 && g1 < d2) {
if (d1 < d2) {
newimage.imagedata[x][y] = this.imagedata[x+1][y+1];
} else {
newimage.imagedata[x][y] = this.imagedata[x-1][y-1];
}
}
}
}
return newimage;
}
public StiImage Filter2x2_Sub2 ()
{
int th3 = 32;
StiImage newimage = new StiImage(this);
for (int y = 2; y <= this.height; y+=2) {
for (int x = 1; x <= this.width; x+=2) {
int d1 = ColorDist(newimage.imagedata[x][y], newimage.imagedata[x] [y-1]);
int d2 = ColorDist(newimage.imagedata[x][y], newimage.imagedata[x+1][y] );
int d3 = ColorDist(newimage.imagedata[x][y], newimage.imagedata[x-1][y-1]);
int d4 = ColorDist(newimage.imagedata[x][y], newimage.imagedata[x+1][y+1]);
int d5 = ColorDist(newimage.imagedata[x][y], newimage.imagedata[x-1][y] );
int d6 = ColorDist(newimage.imagedata[x][y], newimage.imagedata[x] [y+1]);
int g1 = ColorDist(newimage.imagedata[x-1][y-1], newimage.imagedata[x+1][y+1]);
int g2 = ColorDist(newimage.imagedata[x-1][y+1], newimage.imagedata[x+1][y-1]);
if (d1 < th3 && d2 < th3 && //threshold
g1 < g2 && //gradient
d3 > th3 && d4 > th3) {
//a line or edge
if (g1 < th3) {
if (d3 < d4)
newimage.imagedata[x][y] = newimage.imagedata[x-1][y-1];
else
newimage.imagedata[x][y] = newimage.imagedata[x+1][y+1];
} else if (ColorDist(newimage.imagedata[x+1][y+1], newimage.imagedata[x-1][y]) < th3) {
newimage.imagedata[x][y] = newimage.imagedata[x-1][y];
} else if (ColorDist(newimage.imagedata[x-1][y-1], newimage.imagedata[x][y+1]) < th3) {
newimage.imagedata[x][y] = newimage.imagedata[x][y+1];
//a point
} else if (ColorDist(newimage.imagedata[x-1][y+1], newimage.imagedata[x-1][y]) < th3) {
newimage.imagedata[x][y] = newimage.imagedata[x][y+1];
} else if (ColorDist(newimage.imagedata[x-1][y+1], newimage.imagedata[x][y+1]) < th3) {
newimage.imagedata[x][y] = newimage.imagedata[x-1][y];
//something else
} else if (d5 < d6) {
newimage.imagedata[x][y] = this.imagedata[x-1][y];
} else {
newimage.imagedata[x][y] = this.imagedata[x][y+1];
}
}
}
}
return newimage;
}
public StiImage Filter2x2_Sub3 ()
{
int th6 = 32;
StiImage newimage = new StiImage(this);
for (int y = 2; y <= this.height; y++) {
for (int x = 3; x <= this.width - 1; x++) {
if (ColorDist(this.imagedata[x][y], this.imagedata[x-3][y-2]) < th6 &&
ColorDist(this.imagedata[x][y], this.imagedata[x-2][y-2]) < th6 &&
ColorDist(this.imagedata[x][y], this.imagedata[x-1][y-1]) < th6 &&
ColorDist(this.imagedata[x][y], this.imagedata[x+1][y] ) < th6 &&
ColorDist(this.imagedata[x][y], this.imagedata[x+2][y] ) < th6 &&
ColorDist(this.imagedata[x][y], this.imagedata[x-3][y-1]) >= th6 &&
ColorDist(this.imagedata[x][y], this.imagedata[x-2][y-1]) >= th6 &&
ColorDist(this.imagedata[x][y], this.imagedata[x-1][y] ) >= th6 &&
ColorDist(this.imagedata[x][y], this.imagedata[x] [y+1]) >= th6 &&
ColorDist(this.imagedata[x][y], this.imagedata[x+1][y+1]) >= th6 &&
ColorDist(this.imagedata[x][y], this.imagedata[x+2][y+1]) >= th6) {
newimage.imagedata[x][y-1] = this.imagedata[x][y];
int d1 = ColorDist(this.imagedata[x][y], this.imagedata[x-1][y]);
int d2 = ColorDist(this.imagedata[x][y], this.imagedata[x][y+1]);
int d3 = ColorDist(this.imagedata[x][y], this.imagedata[x+1][y+1]);
if (d1 < d2 && d1 < d3)
newimage.imagedata[x][y] = this.imagedata[x-1][y];
else if (d2 < d3)
newimage.imagedata[x][y] = this.imagedata[x][y+1];
else
newimage.imagedata[x][y] = this.imagedata[x+1][y+1];
}
}
}
return newimage;
}
public StiImage Char_FixColor ()
{
StiImage newimage = new StiImage(this);
for (int y = 1; y <= this.height; y++) {
for (int x = 1; x <= this.width; x++) {
if (darkness[this.imagedata[x][y] & 0xFF] > 75) {
int newtype = 0;
int pt[] = new int[8];
pt[0] = pixeltype[this.imagedata[x-1][y-1] & 0xFF];
pt[1] = pixeltype[this.imagedata[x] [y-1] & 0xFF];
pt[2] = pixeltype[this.imagedata[x+1][y-1] & 0xFF];
pt[3] = pixeltype[this.imagedata[x+1][y] & 0xFF];
pt[4] = pixeltype[this.imagedata[x+1][y+1] & 0xFF];
pt[5] = pixeltype[this.imagedata[x] [y+1] & 0xFF];
pt[6] = pixeltype[this.imagedata[x-1][y+1] & 0xFF];
pt[7] = pixeltype[this.imagedata[x-1][y] & 0xFF];
for (int i = 0; i < 8; i++) {
if (pt[i & 7] == pt[(i+1) & 7] &&
pt[(i+4) & 7] == -1 &&
pt[(i+5) & 7] == -1)
newtype = pixeltype[(this.imagedata[x][y+1] & 0xFF)];
}
if (newtype > 0 && newtype != pixeltype[this.imagedata[x][y] & 0xFF]) {
int color = 0;
int dness = darkness[this.imagedata[x][y] & 0xFF];
while (pixeltype[color] != newtype || darkness[color] < dness)
color++;
newimage.imagedata[x][y] = (byte) color;
}
}
}
}
return newimage;
}
public StiImage Char_Hairline ()
{
StiImage newimage = new StiImage(this);
//tweaks edges
for (int y = 1; y <= this.height; y++) {
for (int x = 1; x <= this.width; x++) {
int ptype = pixeltype[this.imagedata[x][y] & 0xFF];
int pt[] = new int[8];
pt[0] = pixeltype[this.imagedata[x-1][y-1] & 0xFF];
pt[1] = pixeltype[this.imagedata[x] [y-1] & 0xFF];
pt[2] = pixeltype[this.imagedata[x+1][y-1] & 0xFF];
pt[3] = pixeltype[this.imagedata[x+1][y] & 0xFF];
pt[4] = pixeltype[this.imagedata[x+1][y+1] & 0xFF];
pt[5] = pixeltype[this.imagedata[x] [y+1] & 0xFF];
pt[6] = pixeltype[this.imagedata[x-1][y+1] & 0xFF];
pt[7] = pixeltype[this.imagedata[x-1][y] & 0xFF];
for (int i = 0; i < 8; i+= 2) {
if (ptype > 0) {
if ( pt[i & 7] <= 0 && //rounds corners
pt[(i+1) & 7] > 0 &&
pt[(i+2) & 7] > 0 &&
pt[(i+3) & 7] > 0 &&
pt[(i+4) & 7] <= 0 &&
pt[(i+5) & 7] <= 0 &&
pt[(i+6) & 7] <= 0 &&
pt[(i+7) & 7] <= 0) {
newimage.imagedata[x][y] = (byte) 0;
}
} else {
if ( pt[i & 7] <= 0 && //fills bumps
pt[(i+1) & 7] > 0 &&
pt[(i+2) & 7] > 0 &&
pt[(i+3) & 7] > 0 &&
pt[(i+4) & 7] > 0 &&
pt[(i+5) & 7] > 0 &&
pt[(i+6) & 7] <= 0 &&
pt[(i+7) & 7] <= 0) {
newimage.imagedata[x][y] = this.imagedata[x][y+1];
}
}
}
}
}
//draws hairline
for (int y = 1; y <= this.height; y++) {
for (int x = 1; x <= this.width; x++) {
if (pixeltype[newimage.imagedata[x][y] & 0xFF] > 0 &&
(pixeltype[newimage.imagedata[x][y+1] & 0xFF] <= 0 ||
pixeltype[newimage.imagedata[x][y-1] & 0xFF] <= 0 ||
pixeltype[newimage.imagedata[x+1][y] & 0xFF] <= 0 ||
pixeltype[newimage.imagedata[x-1][y] & 0xFF] <= 0)) {
newimage.imagedata[x][y] = (byte) 0xBB;
}
}
}
return newimage;
}
public int getSize ()
{
return this.height * this.width;
}
private int ColorDist(byte color1, byte color2)
{
if ((color1 == 0x00 || color2 == 0x00) && color1 != color2)
return 765;
int color1r = palette[color1 & 0xFF][0] + palette[color1 & 0xFF][1] + palette[color1 & 0xFF][2];
int color2r = palette[color2 & 0xFF][0] + palette[color2 & 0xFF][1] + palette[color2 & 0xFF][2];
return Math.abs(palette[color1 & 0xFF][0] - palette[color2 & 0xFF][0]) +
Math.abs(palette[color1 & 0xFF][1] - palette[color2 & 0xFF][1]) +
Math.abs(palette[color1 & 0xFF][2] - palette[color2 & 0xFF][2]);
}
}
private static int GetInt (List data, int pos, int length)
{
int value = 0;
for (int i = 0; i < length; i++)
{
value <<= 8;
value += data.get(pos+length-1-i)& 0xFF;
}
return value;
}
private static void SetInt (List data, int pos, int length, int value)
{
for (int i = 0; i < length; i++)
{
data.set(pos+i, (byte) (value & 0xFF));
value >>>= 8;
}
}
private static void AddInt (List data, int length, int value)
{
for (int i = 0; i < length; i++)
{
data.add(new Byte((byte) (value & 0xFF)));
value >>>= 8;
}
}
}
You are free to copy, use and modify the code. I take no responsibilities for any troubles it may cause.
Compile (JDK 5.0 or later):
javac StiDouble.java
Generate sti-files (Command Prompt or .bat file):
java -Xmx1024m StiDouble ZOOM EDGES FOLDERIN FOLDEROUT
ZOOM:
I= zoom in
O= zoom out
EDGES:
P= process edges
N= do not process edges
FOLDER IN: read all sti-files from this folder
FOLDER OUT: write all sti-files to this folder
Example 1 (overwrites original files):
java -Xmx1024m StiDouble I N "C:\Ja2\tilesets\0" "C:\Ja2\tilesets\0"
java -Xmx1024m StiDouble I P "C:\Ja2\Anims\F_MERC" "C:\Ja2\Anims\F_MERC"
java -Xmx1024m StiDouble I P "C:\Ja2\Anims\M_MERC" "C:\Ja2\Anims\M_MERC"
java -Xmx1024m StiDouble I P "C:\Ja2\Anims\S_MERC" "C:\Ja2\Anims\S_MERC"
Example 2 (saves files to different location):
java -Xmx1024m StiDouble I N "C:\Ja2\tilesets\0" "C:\Ja2\tilesets\0_HI"
java -Xmx1024m StiDouble I P "C:\Ja2\Anims\F_MERC" "C:\Ja2\Anims\F_MERC_HI"
java -Xmx1024m StiDouble I P "C:\Ja2\Anims\M_MERC" "C:\Ja2\Anims\M_MERC_HI"
java -Xmx1024m StiDouble I P "C:\Ja2\Anims\S_MERC" "C:\Ja2\Anims\S_MERC_HI"
The output folders have to be created before running the program.
I hope someone in the JA community would continue from here:
- Fix possible errors in the code.
- Figure out how to implement this in JA2 in such a way that Jagged Alliance (and other?) Copyrights are respected.
Waiting for high-resolution version of Jagged Alliance 2!
Report message to a moderator
|
Civilian
|
|
|
|
Re: Doubling image size[message #247255]
|
Thu, 18 March 2010 11:22 ![Go to previous message Go to previous message](/theme/Bear_Classic_Brown/images/up.png)
|
|
Nephut |
Messages:4
Registered:March 2010 |
|
|
Probably most tiles were not in sti-folders:
Data/Anims/F_MERC/*
Data/Anims/M_MERC/*
Data/Anims/S_MERC/*
tilesets/0/* (excluding subdirectories)
In the jpeg there are small tiles in the center of the road (brown squares on green grass).
I also checked some buildings; there were small tiles.
It looks like there is some default grass tiles under every tile.
But probably the default tiles are also in some sti-file (but were not in those processed).
Report message to a moderator
|
Civilian
|
|
|
|
|
|
|
|
|
|
|
|
|
Re: Doubling image size[message #247316]
|
Fri, 19 March 2010 02:19 ![Go to previous message Go to previous message](/theme/Bear_Classic_Brown/images/up.png)
|
|
Nephut |
Messages:4
Registered:March 2010 |
|
|
Sorry, I can't enlarge by 1.5.
If you are going to resize on-the-fly, those filter-functions are not difficult to translate into C or C++. But they are probably too slow. If on-the-fly resizing can be done in 24 bits or 32 bits, my (8-bit) filter-functions would be worse.
Thanks for everyone who has worked with 1.13 and Mods! IMO without 1.13 and Mods this game would have been dead for years.
I'm signing out now. Bye.
Report message to a moderator
|
Civilian
|
|
|
|
|
|
|
|
Re: Doubling image size[message #266121]
|
Mon, 01 November 2010 21:09 ![Go to previous message Go to previous message](/theme/Bear_Classic_Brown/images/up.png)
|
|
marcinfp |
![](/images/ranks/private.png) |
Messages:19
Registered:June 2009 Location: Poland |
|
|
DepressivesBrotThe background for the strategic map is a 714x612 .pcx image file, scaled to half the width and height to fit the screen region.
Retail WF, running only on 1024x768 indeed increased the strategic map to fill all the available space.
Now the problem with increasing the size of the strategic map is, that you'd have to adjust scores of offsets for all the functions, mouseregions, map controls...
It's possible. Silversurfer once changed some variables to see what would happen, it basically worked but some stuff was messed up, movement path drawing e.g., don't know if he continued on this. See here
I guess it's more complicated then I thought at first.
It'd be cool if one could just rip this part out of the Wildfire code, hehe
Report message to a moderator
|
Private
|
|
|
|
|
|
|
|
|
|
|
|
Goto Forum:
Current Time: Tue Feb 11 11:21:49 GMT+2 2025
Total time taken to generate the page: 0.02372 seconds
|