Which type of Charset suitable for image encoding ? [Kotlin] - arrays

I had tried to convert btye array to string in charset-8, but it's not working. Can someone guide me please.
Here is how I convert Bitmap to bytearray
private fun BitmapToByteArray(): ByteArray
{
val stream = ByteArrayOutputStream()
btm1!!.compress(Bitmap.CompressFormat.PNG, 100, stream)
val bitmapdata: ByteArray = stream.toByteArray()
return bitmapdata
}
Here is how I encrypt the data
private fun encrypting_data(bitmapdata: ByteArray): String {
val key = secretkey!!.text.toString()
val btm1 = bitmapdata.toString(Charsets.UTF_8)
val s = btm1
//generating key from given secret key
val skey: Key = SecretKeySpec(key.toByteArray(), "AES")
print(skey.toString())
val c: Cipher = Cipher.getInstance("AES")
c.init(Cipher.ENCRYPT_MODE, skey)
//encrypting text string
val re = c.doFinal(s.toByteArray())
//converting encrypted string to base64
val re_base64 = Base64.encodeToString(re, Base64.NO_WRAP or Base64.NO_PADDING)
Log.e("aaAA", re_base64.toString())
//converting each chr of base64 string to binary and combining it
for (i in re_base64) {
var single_b_string = Integer.toBinaryString((i.toInt()))
//if binary str is less than 8 bit then making it 8 bit by adding 0's
if (single_b_string.length < 8) {
for (j in 1..(8 - single_b_string.length)) {
single_b_string = "0" + single_b_string
}
}
//final binary string to hide in image
b_string = b_string + single_b_string
}
Log.e("barraylength", b_string.toString())
Log.e("barray", b_string!!.length.toString())
return b_string.toString()
}
please guide me, thank you

Short answer: none.
Charsets are used to map characters to binary and vice-versa. It doesn't make sense to decode the bytes of an image into a string using a character encoding. There is even a chance that you find sequences of bytes that are not valid sequences in the character encoding that you choose, so they will not be converted to characters correctly.
Sometimes it's necessary to use text to represent binary data (e.g. when using text-only transports/media to store it).
In these cases, you can use other kinds of encodings, for instance Base64, but I guess you know about it because you're already sort of using base64 here as well.
Note that, in your current code, you are converting a ByteArray (bitmapdata) into a String (btm1/s) only to convert it back into a ByteArray (s.toByteArray()). Why do you even need to do so?

Related

Kotlin Int to Byte Conversion

What is the Kotlin 1.5 command to convert a 16 bit integer to a Byte of length 2? Secondary problem is that outputstream needs a string at the end so it can convert with toByteArray()
# Original Python Code
...
i = int((2**16-1)*ratio) # 16 bit int
i.to_bytes(2, byteorder='big')
output = (i).to_bytes(2, byteorder='big')
# Kotlin Code so far
var i = ((2.0.pow(16) - 1) * ratio).toInt() // Convert to 16 bit Integer
print("16 bit Int: " + i)
output = .....
....
...
val outputStream: OutputStream = socket.getOutputStream()
outputStream.write(output.toByteArray()) // write requires ByteArray for some reason
It is simple math, so it is probably the best to calculate manually and define as an extension function:
fun Int.to2ByteArray() : ByteArray = byteArrayOf(toByte(), shr(8).toByte())
Then you can use it:
output = i.to2ByteArray()
outputStream.write(output)
Note, this function writes the integer in little-endian. If you need big-endian the just reverse the order of items in the array. You can also add some min/max checks if you need them.
Also, if you only need 16-bit values then you can consider using Short or UShort instead of Int. It doesn't change much regarding the memory usage, but it could be a cleaner approach - we could name our extension just toByArray() and we would not need min/max checks.

Binary String to Byte array in Java

I want to do a method to convert binary String to byte array and I wanted to use Java 8 Stream API but I cannot use map to get a byte array. So I have done like this. Do you know any better way to do it?
private static byte[] getBytes(String bitString)
{
int [] range = IntStream.range(0, bitString.length() / 8).toArray();
byte[] byteArray = new byte[range.length];
for (int i = 0; i < range.length; i++) {
int pos = range[i];
byteArray[i] = Byte.parseByte(StringUtils.netSubstring(bitString, pos * 8, 8), 2);
}
return byteArray;
}
First, it’s important to know that Byte.parseByte(…, 2) expects an optional + or - sign, followed by a positive magnitude. So, if the string has no sign, eight digits, and the leftmost is a one, it will throw an exception, because that positive number wouldn’t fit into the signed byte type. You have to use Integer.parseInt(…,2) instead and cast the result to a byte.
Further, it’s a bit strange to create that int[] range array containing strictly ascending numbers. Within the subsequent loop, pos and i will always have the same value. So the array is entirely obsolete.
Considering these two points, you get the simplified
private static byte[] getBytes(String bitString) {
byte[] byteArray = new byte[bitString.length()/8];
for(int i = 0; i < byteArray.length; i++) {
byteArray[i] = (byte)Integer.parseInt(bitString.substring(i * 8, i * 8 + 8), 2);
}
return byteArray;
}
There is no byte variant of Stream, so the only way to express this via the Stream API would be
private static byte[] getBytes2(String bitString) {
byte[] byteArray = new byte[bitString.length()/8];
IntStream.range(0, byteArray.length)
.forEach(i -> byteArray[i] = (byte)Integer.parseInt(
bitString.substring(i * 8, i * 8 + 8), 2));
return byteArray;
}
which has no real benefit.
But the whole operation can be seen as an academic exercise anyway, as we can simply use
byte[] ba = new BigInteger(bitString, 2).toByteArray();
This creates an additional first zero byte, if the value would otherwise be negative. If that’s a problem, you can remove it afterwards like
if(ba[0] == 0 && bitString.charAt(0) == '1') ba = Arrays.copyOfRange(ba, 1, ba.length);
and it’s still simpler than doing it manually.

Typecast String to ByteArray in kotlin

I have variable in String format in kotlin:
var a ="[B#53c1c428"
I want to change it's datatype from String to ByteArray i.e typecast it to ByteArray, somewhat like:
var b: ByteArray = a
I also tried:
var b = a as ByteArray, but this throws an Exception
If I do:
var b = a.toByteArray(), I get output like:
[B#3aea9e4
But I want [B#53c1c428 as ByteArray.
Any suggestions?
Just to clarify:
[B#53c1c428 is the hexadecimal hash code of that object with a B[# prefix. The string "[B#53c1c428" itself does not contain the data needed to reconstruct the ByteArray.
Consider this:
val str = "Test"
val byteArray = str.toByteArray()
println(Integer.toHexString(byteArray.hashCode())) // 1f32e575
println(byteArray) // [B# + hash code as hexadecimal representation
val str2 = "This is a really long text and no 8 digit hex number in this world could encode it."
val byteArray2 = str2.toByteArray()
println(Integer.toHexString(byteArray2.hashCode())) // 279f2327
println(byteArray2) // [B# + hash code as hexadecimal representation
toByteArray() already gives you a ByteArray. If you want to print the single digits as integers do it like this:
val str = "Test"
println(str.toByteArray().joinToString(" "){ "$it" })
Output:
84 101 115 116
This output would be enough to fully restore the ByteArray, because it contains all necessary information.

Encode UTF8String to ASN1 with CryptoAPI

I use this code to encode UTF8String in ASN1:
const char *charExtensionValue = "test value тест тест with some cyrillic symbols";
CERT_NAME_VALUE myNameValue;
myNameValue.dwValueType = CERT_RDN_UTF8_STRING;
myNameValue.Value.cbData = (DWORD)(strlen(charExtensionValue)+1)*2;
myNameValue.Value.pbData = (LPBYTE)charExtensionValue;
CERT_BLOB encodedBlob;
bool checkASN1Encoding = CryptEncodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, X509_ANY_STRING, &myNameValue, CRYPT_ENCODE_ALLOC_FLAG, NULL, &encodedBlob.pbData, &encodedBlob.cbData);
CryptEncodeObjectEx works well, without any errors, but the result is not expected:
OCTET STRING, encapsulates {
UTF8String "ø§³û¦© Ґѐô´
What am I doing wrong?
the docs say CERT_RDN_UTF8_STRING means the value member must be "An array of 16 bit Unicode characters UTF8 encoded on the wire as a sequence of one, two, or three, eight-bit characters." but charExtensionValue points to an array of 8 bit characters. Also you are calculating the string as if it is a UTF-16 string which it is not. – Stuart

In Swift, how do I read an existing binary file into an array?

As part of my projects, I have a binary data file consisting of a large series of 32 bit integers that one of my classes reads in on initialization. In my C++ library, I read it in with the following initializer:
Evaluator::Evaluator() {
m_HandNumbers.resize(32487834);
ifstream inputReader;
inputReader.open("/path/to/file/7CHands.dat", ios::binary);
int inputValue;
for (int x = 0; x < 32487834; ++x) {
inputReader.read((char *) &inputValue, sizeof (inputValue));
m_HandNumbers[x] = inputValue;
}
inputReader.close();
};
and in porting to Swift, I decided to read the entire file into one buffer (it's only about 130 MB) and then copy the bytes out of the buffer.
So, I've done the following:
public init() {
var inputStream = NSInputStream(fileAtPath: "/path/to/file/7CHands.dat")!
var inputBuffer = [UInt8](count: 32478734 * 4, repeatedValue: 0)
inputStream.open()
inputStream.read(&inputBuffer, maxLength: inputBuffer.count)
inputStream.close()
}
and it works fine in that when I debug it, I can see inputBuffer contains the same array of bytes that my hex editor says it should. Now, I'd like to get that data out of there effectively. I know it's stored in.. whatever format you call it where the least significant bytes are first (i.e. the number 0x00011D4A is represented as '4A1D 0100' in the file). I'm tempted to just iterate through it manually and calculate the byte values by hand, but I'm wondering if there's a quick way I can pass an array of [Int32] and have it read those bytes in. I tried using NSData, such as with:
let data = NSData(bytes: handNumbers, length: handNumbers.count * sizeof(Int32))
data.getBytes(&inputBuffer, length: inputBuffer.count)
but that didn't seem to load the values (all the values were still zero). Can anyone please help me convert this byte array into some Int32 values? Better yet would be to convert them to Int (i.e. 64 bit integer) just to keep my variable sizes the same across the project.
Not sure about your endian-ness, but I use the following function. The difference from your code is using NSRanges of the actual required type, rather than lengths of bytes. This routine reads one value at a time (it's for ESRI files whose contents vary field by field), but should be easily adaptable.
func getBigIntFromData(data: NSData, offset: Int) -> Int {
var rng = NSRange(location: offset, length: 4)
var i = [UInt32](count: 1, repeatedValue:0)
data.getBytes(&i, range: rng)
return Int(i[0].bigEndian)// return Int(i[0]) for littleEndian
}
Grimxn provided the backbone of the solution to my problem, which showed me how to read sections of the buffer into an array; he then showed me a way to read the entire buffer in all at once. Rather than convert all of the items of the array needlessly to Int, I simply read the array into the buffer as UInt32 and did the casting to Int in the function that accesses that array.
For now, since I don't have my utility class defined yet, I integrated Grimxn's code directly into my initializer. The class initializer now looks like this:
public class Evaluator {
let HandNumberArraySize = 32487834
var handNumbers: [Int32]
public init() {
let data = NSData(contentsOfFile: "/path/to/file/7CHands.dat")!
var dataRange = NSRange(location: 0, length: HandNumberArraySize * 4)
handNumbers = [Int32](count: HandNumberArraySize, repeatedValue: 0)
data.getBytes(&handNumbers, range: dataRange)
println("Evaluator loaded successfully")
}
...
}
... and the function that references them is now:
public func cardVectorToHandNumber(#cards: [Int], numberToUse: Int) -> Int {
var output: Int
output = Int(handNumbers[53 + cards[0] + 1])
for i in 1 ..< numberToUse {
output = Int(handNumbers[output + cards[i] + 1])
}
return Int(handNumbers[output])
}
Thanks to Grimxn and thanks once again to StackOverflow for helping me in a very real way!

Resources