Created
May 10, 2018 21:06
-
-
Save shahbaz-momi/f0640844708d183daa5fda9b29e792c6 to your computer and use it in GitHub Desktop.
Binary to image converter in Kotlin
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.asdev.bin2img | |
import java.awt.Color | |
import java.awt.image.BufferedImage | |
import java.io.ByteArrayOutputStream | |
import java.io.File | |
import java.nio.file.Files | |
import javax.imageio.ImageIO | |
/** | |
* Created by Asdev on 08/26/16. All rights reserved. | |
* Unauthorized copying via any medium is stricitly | |
* prohibited. | |
* | |
* Authored by Shahbaz Momi as part of BinToImg | |
* under the package com.asdev.bin2img | |
*/ | |
fun main(args: Array<String>) { | |
if(args[0] == "bin-in") { | |
val img = bin2img(Files.readAllBytes(File(args[1]).toPath())!!.toTypedArray()) | |
ImageIO.write(img, "png", File(args[2])) | |
} else if(args[0] == "img-in") { | |
val bytes = img2bin(ImageIO.read(File(args[1]))) | |
Files.write(File(args[2]).toPath()!!, bytes.toByteArray()) | |
} | |
} | |
fun bin2img(data: Array<Byte>): BufferedImage { | |
println("SIZE: " + data.size) | |
// compute optimal width and height | |
val sqrt = Math.sqrt(data.size.toDouble() / 3.0) | |
// add some and call it a day | |
val width = sqrt.toInt() | |
var height = sqrt.toInt() | |
// make sure it fits | |
while (width * height < data.size / 3.0) { | |
height ++ | |
} | |
println("WIDTH $width HEIGHT $height") | |
// convert the data byte to pixel data | |
val out = BufferedImage(width, height, BufferedImage.TYPE_3BYTE_BGR) | |
var index = 0 | |
for(y in 0 until height) { | |
for(x in 0 until width) { | |
// value index..index + 2 | |
out.setRGB(x, y, Color(data.getOrElse(index){-128}.toInt() + 128, data.getOrElse(index + 1){-128}.toInt() + 128, data.getOrElse(index + 2){-128}.toInt() + 128).rgb) | |
index += 3 | |
if(index >= data.size) { | |
// realign to last three bytes | |
index -=3 | |
// add marker bit | |
out.setRGB(x + 1, y, Color( if(index < data.size) 255 else 0, if(index + 1 < data.size) 255 else 0, if(index + 2 < data.size) 255 else 0 ).rgb) | |
break | |
} | |
} | |
} | |
// set last 3 bytes to 255 | |
return out | |
} | |
fun img2bin(img: BufferedImage): Array<Byte> { | |
// get size of data | |
var size = img.width * img.height | |
// start from end and read all black pixels | |
for(x in img.width - 1 downTo 0) { | |
// if black, continue | |
if(img.getRGB(x, img.height - 1) == Color.BLACK.rgb) { | |
size -- | |
} else { | |
// not black no more | |
// sub this bit from the size | |
size -- | |
// three bytes per color | |
size *= 3 | |
// this color tells which bits of last is legit | |
val lC = Color(img.getRGB(x, img.height - 1)) | |
// see if there is an actual blue component | |
if(lC.blue == 0) | |
size -- | |
// see if there is an actual red component | |
if(lC.green == 0) | |
size -- | |
break | |
} | |
} | |
println("DECODE SIZE: $size") | |
val output = ByteArrayOutputStream(size) | |
var index = 0 | |
for(y in 0 until img.height) { | |
for(x in 0 until img.width) { | |
val c = Color(img.getRGB(x, y)) | |
if(index < size) { | |
output.write(c.red - 128) | |
} | |
if(index + 1 < size) { | |
output.write(c.green - 128) | |
} | |
if(index + 2 < size) { | |
output.write(c.blue - 128) | |
} | |
index += 3 | |
if(index >= size) { | |
break | |
} | |
} | |
} | |
return output.toByteArray().toTypedArray() | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment