How to correctly convert from rgb565 to rgb888 - java

I'm trying to convert a value from rgb565 to rgb888 but I can't seem to get it right.
I've also checked a few existing answers like this one but there are values that don't seem to be properly convert.
Here's what I've tried so far:
PImage picker;
int c;
void setup(){
size(285,240);
picker = loadImage("hsv.gif");
int c = color(255,255,255);
byte[] word = colorToWord(c);
int[] rgb = wordToRGB(word);
noStroke();
fill(c);
rect(0,0,50,100);
fill(rgb[0],rgb[1],rgb[2]);
rect(50,0,50,100);
}
void draw(){
image(picker,0,0);
if((mouseX >= 0 && mouseX <= picker.width)&&
(mouseY >= 0 && mouseY <= picker.height)) c = picker.get(mouseX,mouseY);
byte[] word = colorToWord(c);
int[] rgb = wordToRGB(word);
// int[] rgb = rgbWordToRGB(word);
int cc = color(rgb[0],rgb[1],rgb[2]);
fill(c);
rect(0,159,142,80);
fill(cc);
rect(142,159,143,80);
fill(0);
text("original\n"+hex(c),10,185);
text("converted\n"+hex(cc),152,185);
}
byte[] colorToWord(int c){
int r = (c >> 16) & 0xFF;
int g = (c >> 8) & 0xFF;
int b = c & 0xFF;
return new byte[]{(byte)((r&248)|g>>5),(byte)((g&28)<<3|b>>3)};
}
int[] wordToRGB3(byte[] data){
// Reconstruct 16 bit rgb565 value from two bytes
int rgb565 = (data[0] & 255) | ((data[1] & 255) << 8);
// Extract raw component values (range 0..31 for g and b, 0..63 for g)
int b5 = rgb565 & 0x1f;
int g6 = (rgb565 >> 5) & 0x3f;
int r5 = (rgb565 >> 11) & 0x1f;
// Scale components up to 8 bit:
// Shift left and fill empty bits at the end with the highest bits,
// so 00000 is extended to 000000000 but 11111 is extended to 11111111
int b = (b5 << 3) | (b5 >> 2);
int g = (g6 << 2) | (g6 >> 4);
int r = (r5 << 3) | (r5 >> 2);
return new int[]{r,g,b};
}
int[] wordToRGB2(byte[] word){
int r = word[0]&248;
int g = (word[0]<<5) | ((word[1]&28)>>3);
int b = word[1] << 3;
r <<= 3;
g <<= 2;
b <<= 3;
return new int[]{r,g,b};
}
int[] wordToRGB(byte[] word){
int c = (word[0] << 8) | (word[1]);
//RGB565
int r = (c >> (6+5)) & 0x01F;
int g = (c >> 5) & 0x03F;
int b = (c) & 0x01F;
//RGB888 - amplify
r <<= 3;
g <<= 2;
b <<= 3;
return new int[]{r,g,b};
}
final int RGB565_MASK_RED = 0xF800;
final int RGB565_MASK_GREEN = 0x07E0;
final int RGB565_MASK_BLUE = 0x001F;
int[] rgbWordToRGB(byte[] word){
int rgb565 = (word[0] << 8) | (word[1]);
int[] rgb24 = new int[3];
rgb24[2] = (rgb565 & RGB565_MASK_RED) >> 11;
rgb24[1] = (rgb565 & RGB565_MASK_GREEN) >> 5;
rgb24[0] = (rgb565 & RGB565_MASK_BLUE);
//amplify the image
rgb24[2] <<= 3;
rgb24[1] <<= 2;
rgb24[0] <<= 3;
return rgb24;
}
using this image as a colour palette:
The problem is with certain values:
Why does that happen ? Is there a way to fix that ?

ok so here's the fix if I understand correctly:
in your wordToRGB() method replace the first line:
int c = (word[0] << 8) | (word[1]);
with
int c = (word[0] << 8) | (word[1] & 0xFF);
The problem happens when you convert from byte to int. Example 1:
int a = 255;
println(binary(a));
int b = (byte) 255;
println(binary(b));
prints:
00000000000000000000000011111111
11111111111111111111111111111111
Example 2:
int a = 127;
println(binary(a));
int b = (byte) 127;
println(binary(b));
prints:
00000000000000000000000001111111
00000000000000000000000001111111
Processing pads with to the left with whatever your last bit was, so essentially after that, your | distorts all the values.

>> is arithmetic shift, so it will sign extends the value. Use logic shift >>> instead
In C, there's no >>> operators, the right shift depends on implementation but most will do a logical shift if the variable is unsigned, so just cast or define it as unsigned

Related

Convert two unsigned bytes to an int in Java

So let's say I've got two unsigned bytes coming from a device to my software:
And I can read their value by:
int first = buffer[0] & 0xFF;
int second = buffer[1] & 0xFF;
And then how can convert these two numbers into an int in Java?
In short: convert unsigned byte buffer array into an int
More details:
So let's say if I have a signed byte array, I can convert it to an int by this way:
int val = ((bytes[0] & 0xff) << 8) | (bytes[1] & 0xff);
but then what should I do to convert an unsigned byte array to an int?
// UPDATED:
Just figured out the way to convert it:
private int toInt(byte[] b) {
int x = (0 << 24) | (0 << 16)
| ((b[1] & 0xFF) << 8) | ((b[0] & 0xFF) << 0);
return x;
}
I don't know whether this is what you want, but you can do it this way:
int b1 = ...; // first byte
int b2 = ...; // second byte
String binaryString = pad0s(Integer.toBinaryString(b1), 8) + pad0s(Integer.toBinaryString(b2), 8);
System.out.println(Integer.valueOf(binaryString, 2));
Where pad0s is defined as:
private static String pad0s(String str, int length) {
if (str.length() >= length) return str;
int diff = length - str.length();
StringBuilder sb = new StringBuilder(str);
for (int i = 0 ; i < diff ; i++) {
sb.insert(0, "0");
}
return sb.toString();
}

Sending Java int to C over TCP

I'm trying to send Java's signed integers over TCP to a C client.
At the Java side, I write the integers to the outputstream like so:
static ByteBuffer wrapped = ByteBuffer.allocateDirect(4); // big-endian by default
public static void putInt(OutputStream out, int nr) throws IOException {
wrapped.rewind();
wrapped.putInt(nr);
wrapped.rewind();
for (int i = 0; i < 4; i++)
out.write(wrapped.get());
}
At the C side, I read the integers like so:
int cnt = 0;
char buf[1];
char sizebuf[4];
while(cnt < 4) {
iResult = recv(ConnectSocket, buf, 1, 0);
if (iResult <= 0) continue;
sizebuf[cnt] = buf[0];
cnt++;
}
However, how do I convert the char array to an integer in C?
Edit
I have tried the following (and the reverse):
int charsToInt(char* array) {
return (array[3] << 24) | (array[2] << 16) | (array[1] << 8) | array[0];
}
Edited again, because I forgot the tags.
Data
For example of what happens currently:
I receive:
char 0
char 0
char 12
char -64
the int becomes 2448
and use the function for creating the int from the char array:
int charsToInt(char* array) {
return ntohl(*((int*) array));
}
I expect the signed integer: 3264
Update
I will investigate more after some sleep..
Update
I have a Java client which interprets the integers correctly and receives the exact same bytes:
0
0
12
-64
That depends on endianness, but you want either:
int x = sizebuf[0] +
(sizebuf[1] << 8) +
(sizebuf[2] << 16) +
(sizebuf[3] << 24);
or:
int x = sizebuf[3] +
(sizebuf[2] << 8) +
(sizebuf[1] << 16) +
(sizebuf[0] << 24);
Note that sizebuf needs to have an unsigned type for this to work correctly. Otherwise you need to mask off any sign-extended values you don't want:
int x = (sizebuf[3] & 0x000000ff) +
((sizebuf[2] << 8) & 0x0000ff00) +
((sizebuf[1] << 16) & 0x00ff0000) +
((sizebuf[0] << 24) & 0xff000000);
The classical C library has the method you want already, and it is independent from the machine endianness: ntohl!
// buf is a char */uint8_t *
uint32_t from_network = *((uint32_t *) buf);
uint32_t ret = ntohl(from_network);
This, and htonl for the reverse etc expect that the "network order" is big endian.
(the code above presupposes that buf has at least 4 bytes; the return type, and argument type, of ntohl and htonl are uint32_t; the JLS defines an int as 4 bytes so you are guaranteed the result)
To convert you char array, one possibility is to cast it to int* and to store the result :
int result = *((int*) sizebuf)
This is valid and one line. Other possibility is to compute integer from chars.
for (i = 0 ; i < 4; i++)
result = result << sizeof(char) + buf[0]
Choose the one that you prefer.
Alexis.
Edit :
sizeof(char) is 1 because sizeof return a Byte result. So the right line is :
result = result << (sizeof(char) * 8) + buf[0]

Reverse all bits in an int and return the int

What integer should be returned when we reverse all bits of integer 1? How do we do that with Java code?
No java built in functions should be used. Shouldn't use String reverse, converting to string etc. Only bitwise operations allowed.
import java.util.*;
import java.lang.*;
import java.io.*;
class BitReverseInt
{
public static void main (String[] args) throws java.lang.Exception{
System.out.println(reverser(1));
}
public static int reverser(int given){
int input = given;
int temp = 0;
int output = 0;
while(input > 0){
output = output << 1;
temp = input & 1;
input = input >> 1;
output = output | temp;
}
return output;
}
}
Bit reversal can be done by interchanging adjacent single bits, then interchanging adjacent 2-bit fields, then 4-bits, and so on as shown below. These five assignment statements can be executed in any order.
/********************************************************
* These are the bit masks used in the bit reversal process
0x55555555 = 01010101010101010101010101010101
0xAAAAAAAA = 10101010101010101010101010101010
0x33333333 = 00110011001100110011001100110011
0xCCCCCCCC = 11001100110011001100110011001100
0x0F0F0F0F = 00001111000011110000111100001111
0xF0F0F0F0 = 11110000111100001111000011110000
0x00FF00FF = 00000000111111110000000011111111
0xFF00FF00 = 11111111000000001111111100000000
0x0000FFFF = 00000000000000001111111111111111
0xFFFF0000 = 11111111111111110000000000000000
*/
uint x = 23885963; // 00000001011011000111100010001011
x = (x & 0x55555555) << 1 | (x & 0xAAAAAAAA) >> 1;
x = (x & 0x33333333) << 2 | (x & 0xCCCCCCCC) >> 2;
x = (x & 0x0F0F0F0F) << 4 | (x & 0xF0F0F0F0) >> 4;
x = (x & 0x00FF00FF) << 8 | (x & 0xFF00FF00) >> 8;
x = (x & 0x0000FFFF) << 16 | (x & 0xFFFF0000) >> 16;
// result x == 3508418176 11010001000111100011011010000000
By looking at each intermediary result you can see what is happening.
Hopefully this will give you what you need to sort it out in your head. John Doe's answer consolidates steps 4 and 5 in to a single expression. This will work on most machines.
Here is the actual implementation of Integer.reverse(int).
public static int reverse(int i) {
// HD, Figure 7-1
i = (i & 0x55555555) << 1 | (i >>> 1) & 0x55555555;
i = (i & 0x33333333) << 2 | (i >>> 2) & 0x33333333;
i = (i & 0x0f0f0f0f) << 4 | (i >>> 4) & 0x0f0f0f0f;
i = (i << 24) | ((i & 0xff00) << 8) |
((i >>> 8) & 0xff00) | (i >>> 24);
return i;
}
You can use a do while loop like this:
public static int reverse(int number){
int reverse = 0;
int remainder = 0;
do{
remainder = number%10;
reverse = reverse*10 + remainder;
number = number/10;
}while(number > 0);
return reverse;
}
And for bitwise operation: here it goes:
// value=your integer, numBitsInt=how much bit you will use to reverse
public static int reverseIntBitwise(int value, int numBitsInt) {
int i = 0, rev = 0, bit;
while (i++ < numBitsInt) {
bit = value & 1;
value = value >> 1;
rev = rev ^ bit;
if (i < numBitsInt)
rev = rev << 1;
}
return rev;
}
Well there are multiple ways to reverse the bits of the given number in Java.
First, Java language has inbuild bitwise complement operator(~). So (~number) reverses the bits of number.
Second, one can use the Integer.reverse(number)
Third, if this is a part of test or you just want to play with bits, you can refer the code below.
/*
The logic uses moving bitmask from right to left:
1. Get the bit of given number, by binary and(&) with bitmask
2. XOR(^) with the bitmask, so here we reverse the bit.
3. OR(|) this reversed bit with the result(result has all Zero initially)
This logic is repeated for each 32 bits by moving the mask from right to left,
one bit at a time using (<<) left shift operator on bitmask.
*/
public class ReverseBits {
public static int reverseBits(int input) {
print("Input", input);
int bitmask = 1;
int result = 0;
do {
//print("Bitmask", bitmask);
result = result | (bitmask ^ (input & bitmask)) ;
//print("Result", result);
bitmask = bitmask << 1;
} while (bitmask != 0);
print("Reverse", result);
return result;
}
public static void print(String label, int input) {
System.out.println(label +"\t:"+Integer.toBinaryString(input));
}
public static void main(String[] args) {
reverseBits(Integer.MIN_VALUE);
reverseBits(Integer.MAX_VALUE);
reverseBits(reverseBits(170));
}
}
Output:
Input :10000000000000000000000000000000
Reverse :1111111111111111111111111111111
Input :1111111111111111111111111111111
Reverse :10000000000000000000000000000000
Input :10101010
Reverse :11111111111111111111111101010101
Input :11111111111111111111111101010101
Reverse :10101010
return Integer.reverse(given);
Integer.reverse Reference

I need to convert C code block, which calculate checksum to Java code. I have no idea how to do this (

I have an electronic board on which I am printing the data. To calculate the checksum byte of output are using the following algorithm:
word CountCS(byte *Buff, byte Cnt) //Cnt - count of bytes
{
dword cs1, cs2, m;
byte k;
k=0;
cs1=0;
cs2=0;
while (Cnt) {
m=*Buff;
cs1 +=m;
m ^=0x5A;
if (k) m=(m >> k) | (m << (8-k));
k=(k+1) & 0x07;
cs2 +=m;
Buff++;
Cnt--;
};
return (cs2<<8) | (cs1 & 0xFF);
}
The manufacturer of scoreboard provide code in C, I need to convert it to java. I've try to convert, but result is wrong, here java code
public int checksum(int [] buffer, int count) {
int cs1 =0, cs2 = 0, m;
int k = 0, i = 0;
while (count != 0) {
m = buffer[i];
cs1 += m;
m ^= 0x5a;
if (k != 0) m = (m >> k) | (m << (8-k));
k = (k +1) & 0x07;
cs2 += m;
i++;
count--;
}
return (cs2 << 8) | (cs1 & 0xff);
}
Can anyone see what I'm doing wrong?
Just sorry, but I'm new to java.
Thanks a lot, problem is solved
if (k) m=(m >> k) | (m << (8-k));
should be
if (k != 0) m = (m >> k) | (m << (8-k));
not
if (k == 0) m = (m >> k) | (m << (8-k));
Your variable sizes are different: k (byte vs int). In java int is 32 bit signed. byte in C++ may be dependent on platform, more likely 8 or 16 bits unsigned. So it would have different values as you add and multiply/shift, etc.

Interval Partitioning on IP address range

I'm dealing with a problem to partition specific IP address ranges (in Java). Suppose I have:
startIP endIP
1.2.3.4 1.2.5.6
and I need cut this range into every [0, 255] interval so we have:
startIP endIP
1.2.3.4 1.2.3.255
1.2.4.0 1.2.4.255
1.2.5.0 1.2.5.6
I'm looking at this problem more or less like partitioning a decimal range for instance from 7 to 26 and we have [7, 9], [10, 19], [20, 26]. The only difference is we are dealing with 256-simal numbers. Any ideas, folks? Thank you!
You can use InetAddress for this, and run a straightforward loop to do the increments:
InetAddress from = InetAddress.getByName("1.2.3.4");
InetAddress to = InetAddress.getByName("1.2.5.6");
byte[] partsTo = to.getAddress();
for (;;) {
System.out.print(from+" - ");
byte[] parts = from.getAddress();
boolean sameUpperPart = true;
for (int i = 0 ; sameUpperPart && i < parts.length-1 ; i++) {
sameUpperPart &= (partsTo[i] == parts[i]);
}
if (sameUpperPart) {
System.out.println(to);
break;
}
int last = parts.length-1;
parts[last] = (byte)0xFF;
System.out.println(InetAddress.getByAddress(parts));
parts[last] = 0x00;
for (int i = last-1 ; i >= 0 ; i--) {
if (++parts[i] != 0) {
break;
}
}
from = InetAddress.getByAddress(parts);
}
This code produces the following output on ideone:
/1.2.3.4 - /1.2.3.255
/1.2.4.0 - /1.2.4.255
/1.2.5.0 - /1.2.5.6
Some sample code (assumes the initial translation to a int[] is done outside) and which doesn't really return useful data (just prints). But the idea is there.
public class Convertor {
public static void convert(int []a, int []b) {
int left = (a[0] << 24) | (a[1] << 16) | (a[2] << 8) | a[3];
int right = left | 0xff;
int end = (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | b[3];
while ( right < end ) {
System.out.printf("%s -> %s\n", toIp(left), toIp(right));
left = right + 1; right += 256;
}
System.out.printf("%s -> %s\n", toIp(left), toIp(end));
}
private static String toIp(int value) {
return String.format("%d.%d.%d.%d",
value >> 24 & 0xFF,
value >> 16 & 0xFF,
value >> 8 & 0xFF,
value & 0xFF);
}
}
call site:
Convertor.convert(new int[]{1, 2, 3, 4}, new int[]{1, 2, 5, 6});
output:
1.2.3.4 -> 1.2.3.255
1.2.4.0 -> 1.2.4.255
1.2.5.0 -> 1.2.5.6
First convert the IP address into a single integer, then partition by just adding 256 repeatedly, and converting back to an IP address.
public class IPPartition {
public static void main(String[] args) {
String startIP = "1.2.3.4";
String endIP = "1.2.5.6";
long start = toLong(startIP);
long end = toLong(endIP);
long last = start;
long part = (start / 256 + 1) * 256;
for (; part < end; last = part, part += 256) {
System.out.println(toIP(last) + " " + toIP(part));
}
System.out.println(toIP(last) + " " + toIP(end));
}
private static long toLong(String ip) {
String[] tokens = ip.split("\\.");
long sum = 0;
for (int i = 0; i < 4; i++) {
sum *= 256;
sum += Integer.parseInt(tokens[i]);
}
return sum;
}
private static String toIP(long num) {
String result = "";
for (int i = 0; i < 4; i++) {
long section = num % 256;
result = section + result;
if (i < 3) result = "." + result;
num /= 256;
}
return result;
}
}
I used longs here just to be safe, but you might be able to use integers, I haven't tried it. There could also be some off-by-one errors or something, I haven't tested it thoroughly.
I wouldn't know the specific solution for Java, but there is an algorithm in C. It will partition the IP range to largest possible subnets and print them. The resulting ranges will be aligned on subnet boundaries.
#define NETWORK_ZEROS(ip, prefix) ((ip) & (0xffffffff << (32 - (prefix))))
#define NETWORK_ONES(ip, prefix) ((ip) | (~ (0xffffffff << (32 - (prefix)))))
void print_ip(unsigned long ip)
{
unsigned char bytes[4];
bytes[0] = ip & 0xFF;
bytes[1] = (ip >> 8) & 0xFF;
bytes[2] = (ip >> 16) & 0xFF;
bytes[3] = (ip >> 24) & 0xFF;
printf("%d.%d.%d.%d", bytes[3], bytes[2], bytes[1], bytes[0]);
}
void partition_ip(unsigned long start, unsigned long stop)
{
int i;
while (start < stop)
{
// Change the start of the loop to 24 if you
// need to align on /24 boundaries
for (i=0; i <= 32; i++)
{
if (NETWORK_ZEROS(start, i) == start &&
NETWORK_ONES(start, i) <= stop)
{
print_ip(NETWORK_ZEROS(start, i));
printf(" - ");
print_ip(NETWORK_ONES(start, i));
printf("\n");
start = NETWORK_ONES(start, i) + 1;
break;
}
}
}
}
To convert IP to binary number just do something like this
a.b.c.d => ((((a*256)+b)*256)+c)*256+d
or
ip = (a << 24) | (b << 16) | (c << 8) | d
if you want it to be more efficient by utilizing bit shifting.

Categories