[Tool] GD Stash

you see, i just finished playing soldier on hardcore, level 50. SoT and everything cleared, but im having tough luck finding the items i already found on other characters. that said i dont think its not “legit”. but thats all a matter of preference really. all that matters is that the option is there :slight_smile:

It´s look very good. Top work!

Ok, i like the storage part very much! Reminds me of TL2’s StashNinja. gw

i just discover it and it looks totally awesome !

great work mamba, very impressive !

thanks :smiley:

I really would like to release it soon, but without being able to read / write the current shared stash, there is not much point (other than the crafting side)

Anyone who still has his collection in the old format could use it to store that, but not add new drops

My exclamation for using Java stems from a personal habit in which I rarely build anything that I intend to release to the public in Java, unless I’m coming up with a messy scratchwork program with the intent to translate it to a different language after the fact. Don’t ask me why, Java is a great and easy tool to use for programming in, I just have the personal feeling (it’s not even an opinion) that it’s not terribly professional. :stuck_out_tongue: Which is ironic I guess, since ~70% of what I program is in Java.

Anyways, have you solved the black-pixel problem yet? If not, how are you displaying the images in the program - i.e., do you have an external library for working with DDS images and displaying them in the format of that library, or are you converting and displaying them as, say, BufferedImages? If the latter, there’s some decent logic that can be done to make the black pixels transparent.

no, I kinda am waiting to see what Envy is releasing in C# and if he has a fix, I can probably grab that, so it is not the highest priority for me.

I even like the black background in the tables, just not in the stash.

If not, how are you displaying the images in the program - i.e., do you have an external library for working with DDS images and displaying them in the format of that library, or are you converting and displaying them as, say, BufferedImages? If the latter, there’s some decent logic that can be done to make the black pixels transparent.

I found a Java class that ‘reads’ the .dds, I do use it as a BufferedImage.

[spoiler]

//THIS CODE IS WRONG

import java.awt.image.BufferedImage;
import java.awt.image.DataBufferByte;
/**
 * Used for converting an image with black borders (or no black borders) to an image with transparent borders.
 * 
 * @author Ceno
 * @version 1.0
 */
public abstract class AlphaConverter
{
    public static BufferedImage convertBlackBordersToAlpha(BufferedImage img)
    {
        int[][] representation = asInt2D(img);
        return convertBorders(img, representation);
    }
    
    /**
     * Gets a 2D array of all the pixels in the image supplied. A less-complicated implementation would use
     * int[row][col] = img.getRGB(row, col);
     * But that is orders of magnitude slower.
     * 
     * BufferedImages are stored as 1D arrays internally, this method runs a simple algorithm to convert that
     * to a 2D array based on the image's width.
     */
    private static int[][] asInt2D(BufferedImage img)
    {
        byte[] pixels = ((DataBufferByte) img.getRaster().getDataBuffer()).getData();
        int width = img.getWidth();
        
        int[][] ret = new int[img.getHeight()][width];
        //We only need getHeight once whereas we will need getWidth several times;
        //Saving memeory usage, we don't store the height in a variable, we just call it here.
        
        int pxLen = 3;
        for(int pix = 0, row = 0, col = 0; row < ret.length; pix+=pxLen)
        {
            int argb = -16777216;
            argb += ((int) pixels[pix] & 0xFF);
            argb += (((int) pixels[pix + 1] & 0xFF) << 8);
            argb += (((int) pixels[pix + 2] & 0xFF) << 16);
            ret[row][col] = argb;
            ++col;
            if(col == width)
            {
                col = 0;
                row++;
            }
        }
        
        return ret;
    }
    
    private static BufferedImage convertBorders(BufferedImage img, int[][] rep)
    {
        //iterate from left-to-right until finding first nonblack pixel
        ROWS: 
        for(int i = 0; i < rep.length; i++)
            for(int j = 0; j < rep[i].length; j++)
            {
                if(img.getRGB(i, j) == 0xFF000000)
                    img.setRGB(i, j, 0x0);
                else
                    continue ROWS;
            }
        
        //iterate from right-to-left until finding first nonblack pixel
        ROWS_BACK:
        for(int i = 0; i < rep.length; i++)
            for(int j = rep[i].length - 1; i >= 0; j--)
            {
                if(img.getRGB(i, j) == 0xFF000000)
                    img.setRGB(i, j, 0x0);
                else
                    continue ROWS_BACK;
            }
        
        //rotate the matrix 90 degrees to account for internal array storage arrangement
        rep = rotate90CW(rep);
        
        //iterate left-to-right (or, in the original array, top-to-bottom) until finding first nonblack pixel
        COLS:
        for(int i = 0; i < rep.length; i++)
            for(int j = 0; j < rep[i].length; j++)
            {
                if(img.getRGB(i, j) == 0xFF000000)
                    img.setRGB(j, rep.length - 1 - j, 0x0);
                else
                    continue COLS;
            }
        
        //iterate right-to-left (or, in the original array, bottom-to-top) until finding first nonblack pixel
        COLS_BACK:
        for(int i = 0; i < rep.length; i++)
            for(int j = rep[i].length - 1; j >= 0; j++)
            {
                if(img.getRGB(i, rep.length - 1 - j) == 0xFF000000)
                    img.setRGB(j, rep.length - 1 - j, 0x0);
                else
                    continue COLS_BACK;
            }
            
        return img;
    }
    
    /**
     * Rotates an integer array 90 degrees clockwise.
     */
    private static int[][] rotate90CW(int[][] i_arr)
    {
        if(i_arr == null || i_arr.length == 0)
            return null;
        int M = i_arr.length;
        int N = i_arr[0].length;
        int[][] newArr = new int[N][M];
        for(int i = 0; i < M; i++)
            for(int j = 0; j < N; j++)
                newArr[j][M-1-i] = i_arr[i][j];
        return newArr;
    }
}

Test Case:

Original Image:

Altered Image:

How-it-Works Image:
[/spoiler]

Pretty simple process, really. Removes all black borders from left to right, then right to left, then top to bottom, and finally bottom to top from a BufferedImage. There’s some fancy logic you can do in rotating the matrix to speed things up (i.e., by not rotating the matrix and abusing pointers instead :stuck_out_tongue: ;)), but this is probably the clearest way to do it.

Might have to do some fine-tuning of hardcoded values incase the DDS-converted BufferedImages’ borders aren’t pure-black but are instead some other color that is really close to black.

Edit: Actually there’s a problem with my code. Looking into that. Processing the image pre-rotation is incorrect, as can be seen in the altered image…

Edit 2: Screwed over by alpha channels, too! :stuck_out_tongue: Fixing… Edit3: I have no idea what I broke. While I overcome my own ineptitude, the TL;DR of it is to convert all 0xFF000000 (pure black) pixels to 0x00000000 (pure black with transperancy). Of course, some items may have black pixels within the item, so you need to perform this operation until you hit a nonblack pixel, and then restart one layer of pixels down; performing this operation 4 times, once from each cardinal direction, will remove all black borders from an image.

Thanks, the idea is clear, will look into that eventually. For now I am still working on completing some features (and hope someone else solves it in the meantime, I am lazy :wink: )

This looks awesome, mamba!

Looking foward for the final release. Managing multiple transfer stash files is taking out the fun from farming.:undecided:

There’s a misunderstanding about Java security in this thread.

The browser plugins that run Java applets are the things that have the security problems. Those are written in C++, not Java. Installing java is fine, just disable the plugins.

yeah but with java when you are installing it they try to trick you into installing a toolbar -.- whereas c#/.net apps work without any hassle or external downloads for the user as windows usually comes with it. of course, microsoft has interest in making windows better overall so (if you are developing for windows) you have shared interest, whereas oracle doesnt, so they try to milk people in worse ways than microsoft.

looking at this thread and how the discussion is about java now, justified or not, there is a clear dislike. nobody likes having java.

I think its time to start avoiding it where feasible :stuck_out_tongue:

Can be downloaded ? dont see the link :3

Noperino.

Might be wise to keep it unreleased until the game releases…

No, this so far is only to announce it, as I cannot read the current stash format, it does not work as smoothly as an infinite stash as I would want it to (cannot store items from the new stash format, have move files around manually to retrieve them back into the transfer file).

It works nicely for crafting though, so would take care of requests like this :wink:

Sounds good, could you make 2 items for me?

i need:

  • Incorruptible Star of Supremacy
  • Savage Raider Warsword of Fervor

thx so much :smiley:

Thanks Mamba. I’m so going to need this. :smiley: Packrat is what I am.

Great job, hope we can use this asap!

You can never have enough storage space :smiley:

When I wrote “It works nicely for crafting though, so would take care of requests like this” I meant the program in its current state, not me :wink:

oh, lol, got it

thx anyways