Thread: [Java] Image recoloring

Results 1 to 9 of 9
  1. #1 [Java] Image recoloring 
    Community Veteran

    mige5's Avatar
    Join Date
    Aug 2008
    Posts
    5,528
    Thanks given
    573
    Thanks received
    1,410
    Rep Power
    2114
    EDIT: New problem. I need to change the current code so that: I get yellow in the center of the black area, and it would slowly turn to red towards the edges of the black area. (I will use the original black/white image for transparency, so with the current code, I barely get any red at all on the final product after transparency is applied)

    Heres the current code and pics how it works:
    https://www.rune-server.ee/programmi...ml#post5464513


    OLD BELOW
    **********

    How would I recolor a black/white image where the color slowly fades to the other color... so for example instead of black and white, it would be yellow and red?
    Attached image
    Number of page #1 releases with most views & posts: (Updated: 2023)
    RS2 server section: 1
    RS2 client section: 2
    Reply With Quote  
     

  2. #2  
    Renown Programmer

    Join Date
    Oct 2017
    Posts
    198
    Thanks given
    167
    Thanks received
    302
    Rep Power
    1567
    Hey man, just made this on a test class. Have not tested on a client, so not sure if the fading would even look @ 50 fps, but maybe some of the code can be of use

    Code:
    import org.junit.Test;
    
    import javax.imageio.ImageIO;
    import java.awt.image.BufferedImage;
    import java.awt.image.DataBufferInt;
    import java.io.IOException;
    import java.nio.file.Paths;
    import java.text.DecimalFormat;
    import java.util.ArrayList;
    import java.util.List;
    
    public final class BlendTest {
    
        @Test
        public void benchmark() {
            final int iterations = 25;
    
            List<Blend> blendList = new ArrayList<>(iterations);
            for (int i = 0; i != iterations; ++i) {
                blendList.add(new Blend(320, 280, 0.2f));
            }
    
            long start = System.currentTimeMillis();
            while (!blendList.isEmpty()) {
                blendList.removeIf(Blend::blend);
            }
            System.out.printf("Iteration of %s blends took %d ms.\n", new DecimalFormat().format(iterations), (System.currentTimeMillis() - start));
        }
    
        @Test
        public void visualization() throws IOException {
            Blend blend = new Blend(320, 280, 0.2f);
            int stage = 0;
            while (true) {
                BufferedImage image = new BufferedImage(blend.width, blend.height, BufferedImage.TYPE_INT_RGB);
                int[] data = ((DataBufferInt) image.getRaster().getDataBuffer()).getData();
                System.arraycopy(blend.src, 0, data, 0, data.length);
    
                ImageIO.write(image, "png", Paths.get("../", "dev", "blend").resolve("blend#" + (stage++) + ".png").toFile());
    
                if (blend.blend()) {
                    break;
                }
            }
        }
    
        public static final class Blend {
    
            private final int width;
    
            private final int height;
    
            private final int[] src;
    
            private final int[] dst;
    
            private final float t;
    
            Blend(int width, int height, float t) {
                this.width = width;
                this.height = height;
                this.src = new int[width * height];
                this.dst = new int[width * height];
                this.t = t;
    
                fillDummyData();
            }
    
            void fillDummyData() {
                for (int i = 0; i != (width * height); ++i) {
                    if (i < ((width * height + width * 2) / 3)) {
                        src[i] = 0x000000;
                        dst[i] = 0xFFFF00;
                    } else {
                        src[i] = 0xFFFFFF;
                        dst[i] = 0xFF0000;
                    }
                }
            }
    
            boolean blend() {
                for (int i = 0; i != src.length; i += width) {
                    int srcColor = src[i];
                    int dstColor = dst[i];
                    int r = (int) (QuickMaffs.lerp(((float)((srcColor >> 16) & 0xFF) / 255.0f), ((float) ((dstColor >> 16) & 0xFF) / 255.0f), t) * 255);
                    int g = (int) (QuickMaffs.lerp(((float)((srcColor >> 8) & 0xFF) / 255.0f), ((float) ((dstColor >> 8) & 0xFF) / 255.0f), t) * 255);
                    int b = (int) (QuickMaffs.lerp(((float)(srcColor & 0xFF) / 255.0f), ((float) (dstColor & 0xFF) / 255.0f), t) * 255);
    
                    int newColor = (r << 16) | (g << 8) | b;
                    if (newColor == srcColor) {
                        newColor = dstColor;
                    }
                    for (int x = 0; x != width; ++x) {
                        src[i + x] = newColor;
                    }
                }
                return src[width * height - width] == dst[width * height - width];
            }
        }
    
        private static final class QuickMaffs {
    
            static float lerp(float src, float dst, float t) {
                return (1 - t) * src + t * dst;
            }
        }
    }
    The code assumes you're using a horizontal gradient, could of course just calculate the rgb value for each pixel instead to add support for any type of gradient or image all together; just did it to save some cpu power which might be an unnecessary micro-optimization. We also assume the pixels store rgb and not rgba value, which is easy to add in the Blend#blend method.

    If you want maximum performance, you could cache the results of the rgb values and just loop through them for this specific case. However, that would mean the system would lack the feature of being "dynamic".

    The src pixels I'm using here don't exactly represent a gradient, but didn't want to spend more time on this than needed. Results: https://imgur.com/a/MURKN
    Reply With Quote  
     

  3. #3  
    Community Veteran

    mige5's Avatar
    Join Date
    Aug 2008
    Posts
    5,528
    Thanks given
    573
    Thanks received
    1,410
    Rep Power
    2114
    Quote Originally Posted by Indova View Post
    Hey man, just made this on a test class. Have not tested on a client, so not sure if the fading would even look @ 50 fps, but maybe some of the code can be of use

    Code:
    import org.junit.Test;
    
    import javax.imageio.ImageIO;
    import java.awt.image.BufferedImage;
    import java.awt.image.DataBufferInt;
    import java.io.IOException;
    import java.nio.file.Paths;
    import java.text.DecimalFormat;
    import java.util.ArrayList;
    import java.util.List;
    
    public final class BlendTest {
    
        @Test
        public void benchmark() {
            final int iterations = 25;
    
            List<Blend> blendList = new ArrayList<>(iterations);
            for (int i = 0; i != iterations; ++i) {
                blendList.add(new Blend(320, 280, 0.2f));
            }
    
            long start = System.currentTimeMillis();
            while (!blendList.isEmpty()) {
                blendList.removeIf(Blend::blend);
            }
            System.out.printf("Iteration of %s blends took %d ms.\n", new DecimalFormat().format(iterations), (System.currentTimeMillis() - start));
        }
    
        @Test
        public void visualization() throws IOException {
            Blend blend = new Blend(320, 280, 0.2f);
            int stage = 0;
            while (true) {
                BufferedImage image = new BufferedImage(blend.width, blend.height, BufferedImage.TYPE_INT_RGB);
                int[] data = ((DataBufferInt) image.getRaster().getDataBuffer()).getData();
                System.arraycopy(blend.src, 0, data, 0, data.length);
    
                ImageIO.write(image, "png", Paths.get("../", "dev", "blend").resolve("blend#" + (stage++) + ".png").toFile());
    
                if (blend.blend()) {
                    break;
                }
            }
        }
    
        public static final class Blend {
    
            private final int width;
    
            private final int height;
    
            private final int[] src;
    
            private final int[] dst;
    
            private final float t;
    
            Blend(int width, int height, float t) {
                this.width = width;
                this.height = height;
                this.src = new int[width * height];
                this.dst = new int[width * height];
                this.t = t;
    
                fillDummyData();
            }
    
            void fillDummyData() {
                for (int i = 0; i != (width * height); ++i) {
                    if (i < ((width * height + width * 2) / 3)) {
                        src[i] = 0x000000;
                        dst[i] = 0xFFFF00;
                    } else {
                        src[i] = 0xFFFFFF;
                        dst[i] = 0xFF0000;
                    }
                }
            }
    
            boolean blend() {
                for (int i = 0; i != src.length; i += width) {
                    int srcColor = src[i];
                    int dstColor = dst[i];
                    int r = (int) (QuickMaffs.lerp(((float)((srcColor >> 16) & 0xFF) / 255.0f), ((float) ((dstColor >> 16) & 0xFF) / 255.0f), t) * 255);
                    int g = (int) (QuickMaffs.lerp(((float)((srcColor >> 8) & 0xFF) / 255.0f), ((float) ((dstColor >> 8) & 0xFF) / 255.0f), t) * 255);
                    int b = (int) (QuickMaffs.lerp(((float)(srcColor & 0xFF) / 255.0f), ((float) (dstColor & 0xFF) / 255.0f), t) * 255);
    
                    int newColor = (r << 16) | (g << 8) | b;
                    if (newColor == srcColor) {
                        newColor = dstColor;
                    }
                    for (int x = 0; x != width; ++x) {
                        src[i + x] = newColor;
                    }
                }
                return src[width * height - width] == dst[width * height - width];
            }
        }
    
        private static final class QuickMaffs {
    
            static float lerp(float src, float dst, float t) {
                return (1 - t) * src + t * dst;
            }
        }
    }
    The code assumes you're using a horizontal gradient, could of course just calculate the rgb value for each pixel instead to add support for any type of gradient or image all together; just did it to save some cpu power which might be an unnecessary micro-optimization. We also assume the pixels store rgb and not rgba value, which is easy to add in the Blend#blend method.

    If you want maximum performance, you could cache the results of the rgb values and just loop through them for this specific case. However, that would mean the system would lack the feature of being "dynamic".

    The src pixels I'm using here don't exactly represent a gradient, but didn't want to spend more time on this than needed. Results: https://imgur.com/a/MURKN
    Does that also work for pictures like this:
    Attached image
    I dont always have fading on them, so will it also work on these:
    Attached image
    Number of page #1 releases with most views & posts: (Updated: 2023)
    RS2 server section: 1
    RS2 client section: 2
    Reply With Quote  
     

  4. #4  
    Renown Programmer

    Join Date
    Oct 2017
    Posts
    198
    Thanks given
    167
    Thanks received
    302
    Rep Power
    1567
    Quote Originally Posted by mige5 View Post
    Does that also work for pictures like this:
    Attached image
    I dont always have fading on them, so will it also work on these:
    Attached image
    Do you just want this to replace black with X color and white with Y color? That's a bit different, I can write something up for you in a bit though.

    Edit:

    Code:
    import org.junit.Test;
    
    import javax.imageio.ImageIO;
    import java.awt.image.BufferedImage;
    import java.awt.image.DataBufferInt;
    import java.io.IOException;
    import java.nio.file.Paths;
    import java.text.DecimalFormat;
    import java.util.ArrayList;
    import java.util.List;
    
    public final class BlendTest {
    
        @Test
        public void benchmark() {
            final int iterations = 1;
    
            List<Blend> blendList = new ArrayList<>(iterations);
            for (int i = 0; i != iterations; ++i) {
                blendList.add(new Blend(320, 280, 0.2f));
            }
    
            long start = System.currentTimeMillis();
            while (!blendList.isEmpty()) {
                blendList.removeIf(Blend::blend);
            }
            System.out.printf("Iteration of %s blends took %d ms.\n", new DecimalFormat().format(iterations), (System.currentTimeMillis() - start));
        }
    
        @Test
        public void visualization() throws IOException {
            Blend blend = new Blend(ImageIO.read(Paths.get(System.getProperty("user.home"), "Downloads", "two.png").toFile().toURI().toURL()), 0.1f);
            int stage = 0;
            while (true) {
                BufferedImage image = new BufferedImage(blend.width, blend.height, BufferedImage.TYPE_INT_RGB);
                int[] data = ((DataBufferInt) image.getRaster().getDataBuffer()).getData();
                System.arraycopy(blend.src, 0, data, 0, data.length);
    
                ImageIO.write(image, "png", Paths.get("../", "dev", "blend").resolve("blend#" + (stage++) + ".png").toFile());
    
                if (blend.blend()) {
                    break;
                }
            }
        }
    
        public static final class Blend {
    
            private final int width;
    
            private final int height;
    
            private final int[] src;
    
            private final int[] dst;
    
            private final float t;
    
            Blend(int width, int height, float t) {
                this.width = width;
                this.height = height;
                this.src = new int[width * height];
                this.dst = new int[width * height];
                this.t = t;
    
                fillDummyData();
            }
    
            Blend(BufferedImage image, float t) {
                this.width = image.getWidth();
                this.height = image.getHeight();
                this.src = new int[width * height];
                this.dst = new int[width * height];
                this.t = t;
    
                fillData(image);
            }
    
            void fillData(BufferedImage image) {
                for (int y = 0; y != height; ++y) {
                    for (int x = 0; x != width; ++x) {
                        int color = image.getRGB(x, y);
                        src[y * width + x] = color;
    
                        // We have to calculate the luminance to see if the pixel RGB is closer to white or black.
                        int luminance = (int) ((((color >> 16) & 0xFF) * 0.2126) + (((color >> 8) & 0xFF) * 0.7152) + ((color & 0xFF) * 0.0722));
                        color = luminance < 128 ? 0x000000 : 0xFFFFFF;
                        if (color == 0x000000) {
                            // We are setting the primary filter color replacement to yellow.
                            // We can add a parameter for this.
                            dst[y * width + x] = 0xFFFF00;
                        } else {
                            // We are setting the secondary filter color replacement to red.
                            // We can add a parameter for this.
                            dst[y * width + x] = 0xFF0000;
                        }
                    }
                }
            }
    
            void fillDummyData() {
                for (int i = 0; i != (width * height); ++i) {
                    if (i < ((width * height + width * 2) / 3)) {
                        src[i] = 0x000000;
                        dst[i] = 0xFFFF00;
                    } else {
                        src[i] = 0xFFFFFF;
                        dst[i] = 0xFF0000;
                    }
                }
            }
    
            boolean blend() {
                for (int y = 0; y != height; ++y) {
                    for (int x = 0; x != width; ++x) {
                        int srcColor = src[y * width + x];
                        int dstColor = dst[y * width + x];
                        int r = (int) (QuickMaffs.lerp(((float)((srcColor >> 16) & 0xFF) / 255.0f), ((float) ((dstColor >> 16) & 0xFF) / 255.0f), t) * 255);
                        int g = (int) (QuickMaffs.lerp(((float)((srcColor >> 8) & 0xFF) / 255.0f), ((float) ((dstColor >> 8) & 0xFF) / 255.0f), t) * 255);
                        int b = (int) (QuickMaffs.lerp(((float)(srcColor & 0xFF) / 255.0f), ((float) (dstColor & 0xFF) / 255.0f), t) * 255);
    
                        int newColor = (r << 16) | (g << 8) | b;
                        if (newColor == srcColor) {
                            newColor = dstColor;
                        }
                        src[y * width + x] = newColor;
                    }
                }
                return src[width * height - width] == dst[width * height - width];
            }
        }
    
        private static final class QuickMaffs {
    
            static float lerp(float src, float dst, float t) {
                return (1 - t) * src + t * dst;
            }
        }
    }
    Results: https://imgur.com/a/svSXZ
    Reply With Quote  
     

  5. #5  
    Community Veteran

    mige5's Avatar
    Join Date
    Aug 2008
    Posts
    5,528
    Thanks given
    573
    Thanks received
    1,410
    Rep Power
    2114
    Quote Originally Posted by Indova View Post
    Do you just want this to replace black with X color and white with Y color? That's a bit different, I can write something up for you in a bit though.

    Edit:

    Code:
    import org.junit.Test;
    
    import javax.imageio.ImageIO;
    import java.awt.image.BufferedImage;
    import java.awt.image.DataBufferInt;
    import java.io.IOException;
    import java.nio.file.Paths;
    import java.text.DecimalFormat;
    import java.util.ArrayList;
    import java.util.List;
    
    public final class BlendTest {
    
        @Test
        public void benchmark() {
            final int iterations = 1;
    
            List<Blend> blendList = new ArrayList<>(iterations);
            for (int i = 0; i != iterations; ++i) {
                blendList.add(new Blend(320, 280, 0.2f));
            }
    
            long start = System.currentTimeMillis();
            while (!blendList.isEmpty()) {
                blendList.removeIf(Blend::blend);
            }
            System.out.printf("Iteration of %s blends took %d ms.\n", new DecimalFormat().format(iterations), (System.currentTimeMillis() - start));
        }
    
        @Test
        public void visualization() throws IOException {
            Blend blend = new Blend(ImageIO.read(Paths.get(System.getProperty("user.home"), "Downloads", "two.png").toFile().toURI().toURL()), 0.1f);
            int stage = 0;
            while (true) {
                BufferedImage image = new BufferedImage(blend.width, blend.height, BufferedImage.TYPE_INT_RGB);
                int[] data = ((DataBufferInt) image.getRaster().getDataBuffer()).getData();
                System.arraycopy(blend.src, 0, data, 0, data.length);
    
                ImageIO.write(image, "png", Paths.get("../", "dev", "blend").resolve("blend#" + (stage++) + ".png").toFile());
    
                if (blend.blend()) {
                    break;
                }
            }
        }
    
        public static final class Blend {
    
            private final int width;
    
            private final int height;
    
            private final int[] src;
    
            private final int[] dst;
    
            private final float t;
    
            Blend(int width, int height, float t) {
                this.width = width;
                this.height = height;
                this.src = new int[width * height];
                this.dst = new int[width * height];
                this.t = t;
    
                fillDummyData();
            }
    
            Blend(BufferedImage image, float t) {
                this.width = image.getWidth();
                this.height = image.getHeight();
                this.src = new int[width * height];
                this.dst = new int[width * height];
                this.t = t;
    
                fillData(image);
            }
    
            void fillData(BufferedImage image) {
                for (int y = 0; y != height; ++y) {
                    for (int x = 0; x != width; ++x) {
                        int color = image.getRGB(x, y);
                        src[y * width + x] = color;
    
                        // We have to calculate the luminance to see if the pixel RGB is closer to white or black.
                        int luminance = (int) ((((color >> 16) & 0xFF) * 0.2126) + (((color >> 8) & 0xFF) * 0.7152) + ((color & 0xFF) * 0.0722));
                        color = luminance < 128 ? 0x000000 : 0xFFFFFF;
                        if (color == 0x000000) {
                            // We are setting the primary filter color replacement to yellow.
                            // We can add a parameter for this.
                            dst[y * width + x] = 0xFFFF00;
                        } else {
                            // We are setting the secondary filter color replacement to red.
                            // We can add a parameter for this.
                            dst[y * width + x] = 0xFF0000;
                        }
                    }
                }
            }
    
            void fillDummyData() {
                for (int i = 0; i != (width * height); ++i) {
                    if (i < ((width * height + width * 2) / 3)) {
                        src[i] = 0x000000;
                        dst[i] = 0xFFFF00;
                    } else {
                        src[i] = 0xFFFFFF;
                        dst[i] = 0xFF0000;
                    }
                }
            }
    
            boolean blend() {
                for (int y = 0; y != height; ++y) {
                    for (int x = 0; x != width; ++x) {
                        int srcColor = src[y * width + x];
                        int dstColor = dst[y * width + x];
                        int r = (int) (QuickMaffs.lerp(((float)((srcColor >> 16) & 0xFF) / 255.0f), ((float) ((dstColor >> 16) & 0xFF) / 255.0f), t) * 255);
                        int g = (int) (QuickMaffs.lerp(((float)((srcColor >> 8) & 0xFF) / 255.0f), ((float) ((dstColor >> 8) & 0xFF) / 255.0f), t) * 255);
                        int b = (int) (QuickMaffs.lerp(((float)(srcColor & 0xFF) / 255.0f), ((float) (dstColor & 0xFF) / 255.0f), t) * 255);
    
                        int newColor = (r << 16) | (g << 8) | b;
                        if (newColor == srcColor) {
                            newColor = dstColor;
                        }
                        src[y * width + x] = newColor;
                    }
                }
                return src[width * height - width] == dst[width * height - width];
            }
        }
    
        private static final class QuickMaffs {
    
            static float lerp(float src, float dst, float t) {
                return (1 - t) * src + t * dst;
            }
        }
    }
    Results: https://imgur.com/a/svSXZ
    Hey, not quite what im looking for. Dont need multiple images, I would need it to nicely turn into the other colour in the same image: (so full black could be yellow, and full white red, and when it slowly turns to the other color, I think the middle area would be different levels of orange)

    But if the original image doesnt have different levels of darkness, so its either full white or full black, then a direct color replacement works fine.

    Heres side-by-side comparisons with original/result: (with the current code)
    Attached image
    Attached image
    Number of page #1 releases with most views & posts: (Updated: 2023)
    RS2 server section: 1
    RS2 client section: 2
    Reply With Quote  
     

  6. #6  
    Banned

    Join Date
    Jan 2012
    Posts
    593
    Thanks given
    527
    Thanks received
    319
    Rep Power
    0
    wrote code cause fuk it. dunno if it always works because I barely tested it:

    Code:
    import java.awt.image.*;
    import java.io.*;
    import javafx.scene.paint.*;
    import javax.imageio.*;
    
    public final class BWGradMod
    {
    
        /**
         * @param args
         * arg0=IN monochrome B/W IMG,
         * arg1=OUT color IMG,
         * arg2=desired white color replacement (hexcode: eg: FFFF00),
         * arg3=desired black color replacement (hexcode: eg: FF0000).
         */
        public static void main(final String[] args)
        {
            if (args.length != 4/*IN,OUT,HEX1,HEX2*/)
            {
                System.err.println("error:BWGradMod: Invalid arguments");
                System.err.println("usage:BWGradMod <IN> <OUT> HEX1 HEX2");
                System.err.println("example:BWGradMod a.png b.png FFFF00 FF0000");
                System.exit(-1);
            }
            final BufferedImage buf;
            /*Reference to internal buf ARGB buffer*/
            final int[] px;
            try
            {
                final BufferedImage tmp = ImageIO.read(new File(args[0]));
                /**
                 * BufferedImage read from disk could have any color model. The IMG
                 * is copied to a BufferedImage with an ARGB color model as we want
                 * to grab the pixel buffer directly to perform ops, and we need it
                 * in a predictable format.
                 */
                buf = new BufferedImage(
                        /*w*/tmp.getWidth(),
                        /*h*/ tmp.getHeight(),
                        /*t*/ BufferedImage.TYPE_INT_ARGB);
                buf.getGraphics().drawImage(tmp, 0, 0, null);
                px = ((DataBufferInt) buf.getRaster().getDataBuffer()).getData();
            }
            catch (final IOException ex)
            {
                System.err.println("error:BWGradMod: ERROR IMG <" + args[0] + ">");
                System.exit(-1);
                return;
            }
            /*Iterate over the IN-IMG and confirm it is B/W monochrome*/
            for (final int p : px)
            {
                if (((p >> 24) & 0xFF/*ALPHA*/) != 255/**/)
                {
                    System.err.println("error:BWGradMod: Transparency in IN-IMG");
                    System.exit(-1);
                }
                /*UGLY COMPARE THAT RED,GREEN,BLUE ARE ALL THE SAME*/
                if (!(((p >> 16) & 0xFF/*RED*/) == ((p >> 8) & 0xFF/*BLUE*/)
                        && ((p >> 8) & 0xFF/*GREEN*/) == (p & 0xFF/*BLUE*/)
                        && (p & 0xFF/*BLUE*/) == ((p >> 16) & 0xFF/*RED*/)))
                {
                    System.err.println("error:BWGradMod: IN-IMG NOT B/W");
                    System.exit(-1);
                }
            }
            final String hreg = "[0-9a-fA-F]{6}+";
            /*REGEXP to test if HEX1 and HEX2 in correct format*/
            if (!args[2].matches(hreg)/*HEX1*/ || !args[3/*HEX2*/].matches(hreg))
            {
                System.err.println("error:BWGradMod:COLHEX messed up");
                System.exit(-1);
            }
            /*parse colors*/
            final Color c1 = Color.valueOf("#" + args[2]);
            final Color c2 = Color.valueOf("#" + args[3]);
            /*IN-IMG->OUT-IMG*/
            for (int x = 0; x < px.length; ++x)
            {
                /*get % difference the B/W pixel is between BLACK&WHITE,DIVIDE BY*/
                /*100 to translate between 0.0 and 1.0 for interpolate method*/
                final double bw = 100D / 255D * ((px[x] >> 8) & 0xFF) / 100D;
                final Color out = c1.interpolate(c2, bw);
                /*UGLY GET PIXELS FROM COLOR CLASS AND PACK INTO OUTPUT*/
                final int or = (int) (out.getRed() * 255) & 0xFF;/*OUT-RED*/
                final int og = (int) (out.getGreen() * 255) & 0xFF;/*OUT-GREEN*/
                final int ob = (int) (out.getBlue() * 255) & 0xFF;/*OUT-BLUE*/
                px[x] = ((0xFF << 24) | (or << 16) | (og << 8) | ob);
            }
            try
            {
                ImageIO.write(buf, "PNG", new File(args[1]));
            }
            catch (final IOException ex)
            {
                System.err.println("error:BWGradMod: OUT-IMG OUTPUT ERROR");
                System.exit(-1);
            }
        }
    }
    example IN/OUTS (using colours in this thread)

    Attached image

    Attached image
    Reply With Quote  
     

  7. Thankful user:


  8. #7  
    Renown Programmer

    Join Date
    Oct 2017
    Posts
    198
    Thanks given
    167
    Thanks received
    302
    Rep Power
    1567
    Quote Originally Posted by mige5 View Post
    Hey, not quite what im looking for. Dont need multiple images, I would need it to nicely turn into the other colour in the same image: (so full black could be yellow, and full white red, and when it slowly turns to the other color, I think the middle area would be different levels of orange)

    But if the original image doesnt have different levels of darkness, so its either full white or full black, then a direct color replacement works fine.
    Sorry, don't quite understand what you need. The reason it's multiple images is because I'm using it to make visual examples as I do not know what sort of client you're working with (don't even know if it's rs related or not as this is app dev sub forum). I store an int array 'src' that holds the color of each pixel, this is pretty similar to how rs client handles Sprites. So you would just update the src pixels on the client's render loop (by calling Blend#blend) and it'll update the sprite every frame and draw a 'smooth' transition of the images in the examples I showed.

    The way the code is currently set up, it will work on any type of image, including one that is all white or black; it'll still lerp to the target color.

    Maybe @Silly Boss' response might be better suited to what you need. I will try to help otherwise
    Reply With Quote  
     

  9. #8  
    Community Veteran

    mige5's Avatar
    Join Date
    Aug 2008
    Posts
    5,528
    Thanks given
    573
    Thanks received
    1,410
    Rep Power
    2114
    Quote Originally Posted by Silly boss View Post
    wrote code cause fuk it. dunno if it always works because I barely tested it:

    Code:
    import java.awt.image.*;
    import java.io.*;
    import javafx.scene.paint.*;
    import javax.imageio.*;
    
    public final class BWGradMod
    {
    
        /**
         * @param args
         * arg0=IN monochrome B/W IMG,
         * arg1=OUT color IMG,
         * arg2=desired white color replacement (hexcode: eg: FFFF00),
         * arg3=desired black color replacement (hexcode: eg: FF0000).
         */
        public static void main(final String[] args)
        {
            if (args.length != 4/*IN,OUT,HEX1,HEX2*/)
            {
                System.err.println("error:BWGradMod: Invalid arguments");
                System.err.println("usage:BWGradMod <IN> <OUT> HEX1 HEX2");
                System.err.println("example:BWGradMod a.png b.png FFFF00 FF0000");
                System.exit(-1);
            }
            final BufferedImage buf;
            /*Reference to internal buf ARGB buffer*/
            final int[] px;
            try
            {
                final BufferedImage tmp = ImageIO.read(new File(args[0]));
                /**
                 * BufferedImage read from disk could have any color model. The IMG
                 * is copied to a BufferedImage with an ARGB color model as we want
                 * to grab the pixel buffer directly to perform ops, and we need it
                 * in a predictable format.
                 */
                buf = new BufferedImage(
                        /*w*/tmp.getWidth(),
                        /*h*/ tmp.getHeight(),
                        /*t*/ BufferedImage.TYPE_INT_ARGB);
                buf.getGraphics().drawImage(tmp, 0, 0, null);
                px = ((DataBufferInt) buf.getRaster().getDataBuffer()).getData();
            }
            catch (final IOException ex)
            {
                System.err.println("error:BWGradMod: ERROR IMG <" + args[0] + ">");
                System.exit(-1);
                return;
            }
            /*Iterate over the IN-IMG and confirm it is B/W monochrome*/
            for (final int p : px)
            {
                if (((p >> 24) & 0xFF/*ALPHA*/) != 255/**/)
                {
                    System.err.println("error:BWGradMod: Transparency in IN-IMG");
                    System.exit(-1);
                }
                /*UGLY COMPARE THAT RED,GREEN,BLUE ARE ALL THE SAME*/
                if (!(((p >> 16) & 0xFF/*RED*/) == ((p >> 8) & 0xFF/*BLUE*/)
                        && ((p >> 8) & 0xFF/*GREEN*/) == (p & 0xFF/*BLUE*/)
                        && (p & 0xFF/*BLUE*/) == ((p >> 16) & 0xFF/*RED*/)))
                {
                    System.err.println("error:BWGradMod: IN-IMG NOT B/W");
                    System.exit(-1);
                }
            }
            final String hreg = "[0-9a-fA-F]{6}+";
            /*REGEXP to test if HEX1 and HEX2 in correct format*/
            if (!args[2].matches(hreg)/*HEX1*/ || !args[3/*HEX2*/].matches(hreg))
            {
                System.err.println("error:BWGradMod:COLHEX messed up");
                System.exit(-1);
            }
            /*parse colors*/
            final Color c1 = Color.valueOf("#" + args[2]);
            final Color c2 = Color.valueOf("#" + args[3]);
            /*IN-IMG->OUT-IMG*/
            for (int x = 0; x < px.length; ++x)
            {
                /*get % difference the B/W pixel is between BLACK&WHITE,DIVIDE BY*/
                /*100 to translate between 0.0 and 1.0 for interpolate method*/
                final double bw = 100D / 255D * ((px[x] >> 8) & 0xFF) / 100D;
                final Color out = c1.interpolate(c2, bw);
                /*UGLY GET PIXELS FROM COLOR CLASS AND PACK INTO OUTPUT*/
                final int or = (int) (out.getRed() * 255) & 0xFF;/*OUT-RED*/
                final int og = (int) (out.getGreen() * 255) & 0xFF;/*OUT-GREEN*/
                final int ob = (int) (out.getBlue() * 255) & 0xFF;/*OUT-BLUE*/
                px[x] = ((0xFF << 24) | (or << 16) | (og << 8) | ob);
            }
            try
            {
                ImageIO.write(buf, "PNG", new File(args[1]));
            }
            catch (final IOException ex)
            {
                System.err.println("error:BWGradMod: OUT-IMG OUTPUT ERROR");
                System.exit(-1);
            }
        }
    }
    example IN/OUTS (using colours in this thread)

    Attached image

    Attached image
    Thx, seems to work just the way I wanted it to
    Number of page #1 releases with most views & posts: (Updated: 2023)
    RS2 server section: 1
    RS2 client section: 2
    Reply With Quote  
     

  10. #9  
    Community Veteran

    mige5's Avatar
    Join Date
    Aug 2008
    Posts
    5,528
    Thanks given
    573
    Thanks received
    1,410
    Rep Power
    2114
    Updated 1st post with new issue.
    Number of page #1 releases with most views & posts: (Updated: 2023)
    RS2 server section: 1
    RS2 client section: 2
    Reply With Quote  
     


Thread Information
Users Browsing this Thread

There are currently 1 users browsing this thread. (0 members and 1 guests)


User Tag List

Similar Threads

  1. Images Recolored
    By Arithium in forum Buying
    Replies: 4
    Last Post: 09-20-2015, 06:17 AM
  2. [Java] Image Drag And Dropping
    By Gluon in forum Application Development
    Replies: 2
    Last Post: 09-16-2012, 03:43 AM
  3. Java Imaging
    By brendan hayai in forum Application Development
    Replies: 8
    Last Post: 03-11-2011, 01:35 PM
  4. Java image zooming
    By mige5 in forum Application Development
    Replies: 1
    Last Post: 02-05-2011, 06:02 PM
  5. Replies: 2
    Last Post: 11-15-2008, 08:18 AM
Posting Permissions
  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •