Printing POS/ESC Apex3 image S.O.S - java

I have an Apex3 and I have been able to follow most of the documentation without problem, but when it comes to images things turns very weird (lack of examples + lack of consistency in how to do it).
First I try the naive approach of trying to pass a Bitmap byte[] array compress with JPEG and 0 quality since I did not mind, using the command:
ESC V n1 n2 data
That did not work out well.
Then I discover there is an android library for apex3 that accept a bitmap and supose to print it but it does not work just print weird symbols like this:
I try to decode the jar source using JD gui and they seem to do some work with the bitmap bytes this is their code (piece of advice code like addToDoc(m_Document, ESC + "B"); just put the code in a ByteArrayOutputStream the data), (decompiled source from here):
public void writeImage(Bitmap imageObject, int printHeadWidth)
throws IllegalArgumentException
{
if (imageObject == null) {
throw new IllegalArgumentException("Parameter 'imageObject' was null.");
}
if (printHeadWidth < 1) {
throw new IllegalArgumentException("Parameter 'printHeadWidth' must be greater than 0.");
}
int height = imageObject.getHeight();
int width = imageObject.getWidth();
byte blanklineCount = 0;
byte[] dataline = new byte[printHeadWidth + 7 >> 3];
int[] imageData = new int[height * width];
imageObject.getPixels(imageData, 0, width, 0, 0, width, height);
addToDoc(m_Document, ESC + "B");
for (int row = 0; row < height; row++)
{
boolean blankLine = true;
for (int index = 0; index < width; index += 8)
{
byte currentByte = 0;
int offset = row * width + index;
if (index >= printHeadWidth) {
break;
}
int value = index + 0 < width ? imageData[(offset + 0)] & 0xFFFFFF : 16777215;
boolean set = (value >> 0 & 0xFF) + (value >> 8 & 0xFF) + (value >> 16 & 0xFF) < 384;
currentByte = (byte)(currentByte | (set ? -128 : 0));
value = index + 1 < width ? imageData[(offset + 1)] & 0xFFFFFF : 16777215;
set = (value >> 0 & 0xFF) + (value >> 8 & 0xFF) + (value >> 16 & 0xFF) < 384;
currentByte = (byte)(currentByte | (set ? 64 : 0));
value = index + 2 < width ? imageData[(offset + 2)] & 0xFFFFFF : 16777215;
set = (value >> 0 & 0xFF) + (value >> 8 & 0xFF) + (value >> 16 & 0xFF) < 384;
currentByte = (byte)(currentByte | (set ? 32 : 0));
value = index + 3 < width ? imageData[(offset + 3)] & 0xFFFFFF : 16777215;
set = (value >> 0 & 0xFF) + (value >> 8 & 0xFF) + (value >> 16 & 0xFF) < 384;
currentByte = (byte)(currentByte | (set ? 16 : 0));
value = index + 4 < width ? imageData[(offset + 4)] & 0xFFFFFF : 16777215;
set = (value >> 0 & 0xFF) + (value >> 8 & 0xFF) + (value >> 16 & 0xFF) < 384;
currentByte = (byte)(currentByte | (set ? 8 : 0));
value = index + 5 < width ? imageData[(offset + 5)] & 0xFFFFFF : 16777215;
set = (value >> 0 & 0xFF) + (value >> 8 & 0xFF) + (value >> 16 & 0xFF) < 384;
currentByte = (byte)(currentByte | (set ? 4 : 0));
value = index + 6 < width ? imageData[(offset + 6)] & 0xFFFFFF : 16777215;
set = (value >> 0 & 0xFF) + (value >> 8 & 0xFF) + (value >> 16 & 0xFF) < 384;
currentByte = (byte)(currentByte | (set ? 2 : 0));
value = index + 7 < width ? imageData[(offset + 7)] & 0xFFFFFF : 16777215;
set = (value >> 0 & 0xFF) + (value >> 8 & 0xFF) + (value >> 16 & 0xFF) < 384;
currentByte = (byte)(currentByte | (set ? 1 : 0));
dataline[(index >> 3)] = currentByte;
blankLine &= currentByte == 0;
}
if (!blankLine)
{
if (blanklineCount > 0)
{
addToDoc(m_Document, "A");
addToDoc(m_Document, blanklineCount);
blanklineCount = 0;
}
addToDoc(m_Document, compressGraphicLine(dataline));
}
else
{
blanklineCount = (byte)(blanklineCount + 1);
if (blanklineCount == 255)
{
addToDoc(m_Document, "A");
addToDoc(m_Document, blanklineCount);
blanklineCount = 0;
}
}
}
if (blanklineCount > 0)
{
addToDoc(m_Document, "A");
addToDoc(m_Document, blanklineCount);
blanklineCount = 0;
}
addToDoc(m_Document, ESC + "E");
}
private byte[] compressGraphicLine(byte[] dataline)
{
byte count = 0;
byte currentByte = 0;
ByteArrayOutputStream rleString = new ByteArrayOutputStream(128);
addToDoc(rleString, "G");
for (int index = 0; index < dataline.length; index++) {
if (count == 0)
{
currentByte = dataline[index];
addToDoc(rleString, currentByte);
count = (byte)(count + 1);
}
else if ((count < 255) && (currentByte == dataline[index]))
{
count = (byte)(count + 1);
}
else
{
addToDoc(rleString, count);
count = 0;
currentByte = dataline[index];
addToDoc(rleString, currentByte);
count = (byte)(count + 1);
}
}
if (count > 0) {
addToDoc(rleString, count);
}
if (rleString.size() > dataline.length + 1)
{
rleString.reset();
addToDoc(rleString, "U");
for (int item = 0; item < dataline.length; item++) {
addToDoc(rleString, dataline[item]);
}
}
return rleString.toByteArray();
}
But I don't get why it is not working.
Finally I try to use How can I print an image on a Bluetooth printer in Android? with the same algorithm as a guide but still printing random weird symbols.

instead of wasting time with decompiling some apk, why not having a look in the offical SDK? On the manufacturer webpage Downloads & Drivers there is a link to the Java SDK which includes a source Sample.java. In the source an BufferedImage is created so I guess (I don't own such a printer) this will give you an entry point for your problem. And most probably they provide on the same page the source for the Android demo Printer Demo Source code for Android
edit Ok. Let's summarize: You have an image and want to print it. In the example Sample.java this case is covered
BufferedImage newImage = new BufferedImage(1024, 512, BufferedImage.TYPE_4BYTE_ABGR);
// some lines and rectangles are drawn in the image
...
// the image is printed, following the SDK javadoc for DocumentLP.writeImage
// "This will cause the image specified to be printed. Images will be expanded to occupy
// the entire width of the printer, so the correct current width of the printer must be
// specified. Images that are too wide will be cropped, and images that are too narrow
// will be padded on the right."
testDoc.writeImage(newImage, m_PrinterWidth);
For me the only things you have to do:
create an BufferedImage object
draw your image from the file into the buffered image
call the writeImage method of your DocumentLP object
edit 2 pseudo code snippet
// taken from SDK javadoc
DocumentLP docLP;
docLP = new DocumentLP("$");
// own code
BufferedInputStream bis = new BufferedInputStream(--from your image--);
BufferedImage bufImage = ImageIO.read(bis);
// have a look into Sample.java for the expected value of m_PrinterWidth
testDoc.writeImage(bufImage, m_PrinterWidth);
edit 3 code snippet for Android (taken from the DO_AndroidSDKDemo_MainActivity.java provided with the datamax o´neil Android SDK
File file = new File(selectedPath);
byte[] readBuffer = new byte[(int)file.length()];
InputStream inputStream= new BufferedInputStream(new FileInputStream(file));
inputStream.read(readBuffer);
inputStream.close();
fileData = readBuffer;
Bitmap m_imageObject = BitmapFactory.decodeByteArray(fileData, 0, fileData.length);
documentLP.clear();
ocumentLP.writeImage(m_imageObject, m_printHeadWidth);

Related

Increment a counter inside a byte array

I have an array of 5 bytes (fixed length). First 21 bits represent a counter and the rest 19 some id. I need to increment the counter by one. How do I do that?
This answer is based on the memory layout as I understand it from the OP's comments:
array[0]: bits 0..7 are counter bits 0..7 (lsb)
array[1]: bits 0..7 are counter bits 8..15
array[2]: bits 0..4 are counter bits 16..20 (msb)
bits 5..7 are part of the id
array[3]: bits 0..7 are part of the id
array[3]: bits 0..7 are part of the id
Then
int byte0 = (int) array[0] & 0xff;
int byte1 = (int) array[1] & 0xff;
int byte2 = (int) array[2] & 0x1f;
int count = byte0 | (byte1 << 8) | (byte2 << 16);
count = (count+1) & 0x1fffff;
array[0] = (byte) (count & 0x0000ff);
array[1] = (byte) ((count & 0x00ff00) >> 8);
array[2] = (array[2] & 0xe0) | (byte) ((count & 0x1f0000) >> 16);
should do the trick.
I'm not sure I solved your problem. Since the memory layout is not described in detail, I assumed a layout. You can obtain the counter, increase it by 1, and then set the counter. If the layout is as desired, it needs to be fully tested. I'm not dealing with data overflow situations, and you may need to add some restrictions.
public class Test {
public static void main(String[] args) {
byte[] bytes = new byte[5];
bytes[2] = 5;
for (int i = 0; i <= 0x1fffff; i++) {
setCount(bytes, i);
if (getCount(bytes) != i) {
System.out.println(i);
debug(bytes);
}
}
}
public static int getCount(byte[] bytes) {
return ((bytes[2] >> 3) & 0x1f) + ((bytes[1] << 5) & 0x1fff) + ((bytes[0] << 13) & 0x1fffff);
}
public static void setCount(byte[] bytes, int count) {
bytes[0] = (byte) (count >> 13 & 0xff);
bytes[1] = (byte) (count >> 5 & 0xff);
bytes[2] = (byte) ((bytes[2] & 0x7) + ((count & 0x1f) << 3));
}
public static void debug(byte[] bytes) {
for (byte b : bytes) {
for (int i = 7; i >= 0; i--) {
System.out.print(b >> i & 1);
}
System.out.print(" ");
}
System.out.println();
System.out.println("Count:" + getCount(bytes));
}
public static void printInt(int num) {
for (int i = 31; i >= 0; i--) {
System.out.print(num >> i & 1);
}
System.out.println();
}
}
I'm not sure I solved your problem.
public class Main
{
public static void main(String[] args)
{
//################
//# BIG ENDIAN #
//################
//initial counter == 1 (b0000_0000_0000_0000_0000_1)
//initial ids == 3 (b000_0000_0000_0000_0011)
byte[] array = { 0, 0, 8, 0, 3 };
int counter = ((array[0] & 0xFF) << 13)
| ((array[1] & 0xFF) << 5)
| ((array[2] & 0xF8) >> 3);
System.out.println(counter); //1
++counter;
System.out.println(counter); //2
//Repack the counter into the array.
array[0] = (byte)((counter & 0x1FE000) >> 13);
array[1] = (byte)((counter & 0x1FE0) >> 5);
array[2] = (byte)(((counter & 0x1F) << 3)| (array[2] & 0x7));
System.out.println(Arrays.toString(array)); //[0, 0, 16, 0, 3]
//Retry & Verify
counter = ((array[0] & 0xFF) << 13) //Same as above. Nothing is changed.
| ((array[1] & 0xFF) << 5)
| ((array[2] & 0xF8) >> 3);
System.out.println(counter); //2
++counter;
System.out.println(counter); //3
//###################
//# LITTLE ENDIAN #
//###################
//initial ids == 3 (b0000_0000_0000_0000_011)
//initial counter == 1 (b0_0000_0000_0000_0000_0001)
byte[] arr = { 0, 0, 96, 0, 1 };
counter = ((arr[2] & 0x1F) << 16)
| ((arr[3] & 0xFF) << 8)
| (arr[4] & 0xFF);
System.out.println(counter); //1
++counter;
System.out.println(counter); //2
//Repack the counter into the array.
arr[2] = (byte)((arr[2] & 0xE0) | ((counter & 0x1F0000) >> 16));
arr[3] = (byte)((counter & 0xFF00) >> 8);
arr[4] = (byte)(counter & 0xFF);
System.out.println(Arrays.toString(arr)); //[0, 0, 96, 0, 2]
//Retry & Verify
counter = ((arr[2] & 0x1F) << 16) //Same as above. Nothing is changed.
| ((arr[3] & 0xFF) << 8)
| (arr[4] & 0xFF);
System.out.println(counter); //2
++counter;
System.out.println(counter); //3
}
}

multiplication in GF(p)

I am developing software in JavaCard to addition points in ECC.
the issue is I need some basis operations, so for the moment, I need multiplication and inversion, I already have addition and subtraction.
I was trying to develop montgomery multiplication but it is for GF(2^m) (I think).
so my example is:
public static void multiplicationGF_p2(){
byte A = (byte) 7;
byte p = (byte) 5;
byte B = (byte) 2;
byte C = (byte) 0;
byte n = (byte)8;
byte i = (byte)(n - 1);
for(; i >= 0; i--){
C = (byte)(((C & 0xFF) + (C & 0xFF) ) + ((A & 0xff) << getBytePos(B,i)));
if((C & 0xFF) >= (byte)(p & 0xFF)){
C = (byte) ((C & 0xFF)-(p & 0xFF));
}
if((C & 0xFF) >= (byte)(p & 0xFF)){
C = (byte) ((C & 0xFF)-(p & 0xFF));
}
}
}
for example A = 2, B =3, p= 3 C must be 0, C = A. B (mode p)
but this example A = 7, B=2, p=5 , C must be 4, but I have 49.
can someone help me with that?
more methods:
public static byte getBytePos(byte b, byte pos){
return (byte)(((b & 0xff) >> pos) & 1);
}
I am trying to be simple, for the moment, but the idea is make multiplication of very big number like arrays[10] of bytes
I have supposed that something was wrong here:
C = (byte)(((C & 0xFF) + (C & 0xFF) ) + ((A & 0xff) << getBytePos(B,i)));
I have created a method to multiply byte numbers, not just using shift to the right <<
So:
public static byte bmult(byte x, byte y){
byte total = (byte)0;
byte i;
byte n = (byte)8; // multiplication for 8 bits or 1 byte
for(i = n ; i >= 0 ; i--)
{
total <<= 1;
if( (((y & 0xff) & (1 << i)) >> i) != (byte)0 )
{
total = (byte)(total + x);
}
}
return total;
}
so then I have added it in my original method, (in the line marked):
C = (byte)(((C & 0xFF) + (C & 0xFF) ) + bmult(A, getBytePos(B,i)) );
for now it is working correctly, I need to test it more
someone has another solution ?

Converting Byte[4] to float - Integer[4] array works but byte[4] does not

This is probably a basic question for out more experienced programmers out there. I'm a bit of a noob and can't work this one out. I'm trying to unpack a binary file and the doco is not too clear on how floats are stored. I have found a routine that does this, but it will only work if I pass an integer array of the bytes. The correct answer is -1865.0. I need to be able to pass the byte array and get the correct answer. How do I need to change the code to make float4byte return -1865.0. Thanks in advance.
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
public class HelloWorld {
public static void main(String[] args) {
byte[] bytes = {(byte) 0xC3,(byte) 0X74,(byte) 0X90,(byte) 0X00 };
int[] ints = {(int) 0xC3,(int) 0X74,(int) 0X90,(int) 0X00 };
// This give the wrong answer
float f = ByteBuffer.wrap(bytes).order(ByteOrder.BIG_ENDIAN).getFloat();
System.out.println("VAL ByteBuffer BI: " + f);
// This give the wrong answer
f = ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN).getFloat();
System.out.println("VAL ByteBuffer LI: " + f);
//This gives the RIGHT answer
f = float4int (ints[0], ints[1], ints[2], ints[3]);
System.out.println("VAL Integer : " + f);
// This gives the wrong answer
f = float4byte (bytes[0], bytes[1], bytes[2], bytes[3]);
System.out.println("VAL Bytes : " + f);
}
private static float float4int(int a, int b, int c, int d)
{
int sgn, mant, exp;
System.out.println ("IN Int: "+String.format("%02X ", a)+
String.format("%02X ", b)+String.format("%02X ", c)+String.format("%02X ", d));
mant = b << 16 | c << 8 | d;
if (mant == 0) return 0.0f;
sgn = -(((a & 128) >> 6) - 1);
exp = (a & 127) - 64;
return (float) (sgn * Math.pow(16.0, exp - 6) * mant);
}
private static float float4byte(byte a, byte b, byte c, byte d)
{
int sgn, mant, exp;
System.out.println ("IN Byte : "+String.format("%02X ", a)+
String.format("%02X ", b)+String.format("%02X ", c)+String.format("%02X ", d));
mant = b << 16 | c << 8 | d;
if (mant == 0) return 0.0f;
sgn = -(((a & 128) >> 6) - 1);
exp = (a & 127) - 64;
return (float) (sgn * Math.pow(16.0, exp - 6) * mant);
}
}
The reason why your solution with ByteBuffer doesn't work: the bytes do not match the (Java) internal representation of the float value.
The Java representation is
System.out.println(Integer.toHexString(Float.floatToIntBits(-1865.0f)));
which gives c4e92000
bytes are signed in Java. When calculating the mantissa mant, the bytes are implicitly converted from bytes to ints - with the sign "extended", i.e. (byte)0x90 (decimal -112) gets converted 0xFFFFFF90 (32 bits int). However what you want is just the original bytes' 8 bits (0x00000090).
In order to compensate for the effect of sign extension, it suffices to change one line:
mant = (b & 0xFF) << 16 | (c & 0xFF) << 8 | (d & 0xFF)
Here, in (c & 0xFF), the 1-bits caused by sign extension are stripped after (implicit) conversion to int.
Edit:
The repacking of floats could be done via the IEEE 754 representation which can be obtained by Float.floatToIntBits (which avoids using slow logarithms). Some complexity in the code is caused by the change of base from 2 to 16:
private static byte[] byte4float(float f) {
assert !Float.isNaN(f);
// see also JavaDoc of Float.intBitsToFloat(int)
int bits = Float.floatToIntBits(f);
int s = (bits >> 31) == 0 ? 1 : -1;
int e = (bits >> 23) & 0xFF;
int m = (e == 0) ? (bits & 0x7FFFFF) << 1 : (bits& 0x7FFFFF) | 0x800000;
int exp = (e - 150) / 4 + 6;
int mant;
int mantissaShift = (e - 150) % 4; // compensate for base 16
if (mantissaShift >= 0) mant = m << mantissaShift;
else { mant = m << (mantissaShift + 4); exp--; }
if (mant > 0xFFFFFFF) { mant >>= 4; exp++; } // loose of precision
byte a = (byte) ((1 - s) << 6 | (exp + 64));
return new byte[]{ a, (byte) (mant >> 16), (byte) (mant >> 8), (byte) mant };
}
The code does not take into account any rules that may exist for the packaging, e.g. for representing zero or normalization of the mantissa. But it might serve as a starting point.
Thanks to #halfbit and a bit of testing and minor changes, this routine appears convert IEEE 754 float into IBM float.
public static byte[] byte4float(float f) {
assert !Float.isNaN(f);
// see also JavaDoc of Float.intBitsToFloat(int)
int bits = Float.floatToIntBits(f);
int s = (bits >> 31) == 0 ? 1 : -1;
int e = (bits >> 23) & 0xFF;
int m = (e == 0) ? (bits & 0x7FFFFF) << 1 : (bits& 0x7FFFFF) | 0x800000;
int exp = (e - 150) / 4 + 6;
int mant;
int mantissaShift = (e - 150) % 4; // compensate for base 16
if (mantissaShift >= 0) mant = m >> mantissaShift;
else mant = m >> (Math.abs(mantissaShift));
if (mant > 0xFFFFFFF) { mant >>= 4; exp++; } // loose of precision */
byte a = (byte) ((1 - s) << 6 | (exp + 64));
return new byte[]{ a, (byte) (mant >> 16), (byte) (mant >> 8), (byte) mant };
}
I think this is right and appears to be working.

How to convert number to argb value?

How can you convert a number into an argb value such that
0 -> 0,0,0,0
1 -> 0,0,0,1
...
(16^8)-1 -> 255,255,255,255
and vice versa so
0,0,0,0 -> 0
0,0,0,1 -> 1
...
255,255,255,255 -> (16^8)-1
Thanks
As additional solution to the answer above, given the sample code below, the result of (16^8)-1 is 23. Which you would like to be of color white. Is there any special reason to do this? Refering to Color
This is what you want to do:
int argb = (16 ^ 8) - 1; //Result is 23 any reason for this?
If we use the same color conversion of Color object.
Color c = Color.FromArgb(255, 255, 255, 255);
c.ToArgb(); //We get -1
Which we will get on the same result with this solution:
int v = (c.A << 24) + (c.R << 16) + (c.G << 8) + c.B; //Result is -1
Revert it back:
int a = (v >> 24) & 0xFF;
int r = (v >> 16) & 0xFF;
int g = (v >> 8) & 0xFF;
int b = (v) & 0xFF;
Try to check the above reference (and experiment) if this will fit your need.
Completely ignoring system methods, you can implement a custom method to do what you ask in C# like the following:
public static long argbToLong(int a, int r, int g, int b)
{
new[] { a, r, g, b }.Select((v, i) => new { Name = "argb"[i].ToString(), Value = v }).ToList()
.ForEach(arg =>
{
if (arg.Value > 255 || arg.Value < 0)
throw new ArgumentOutOfRangeException(arg.Name, arg.Name + " must be between or equal to 0-255");
});
long al = (a << 24) & 0xFF000000;
long rl = (r << 16) & 0x00FF0000;
long gl = (g << 8) & 0x0000FF00;
long bl = b & 0x000000FF;
return al | rl | gl | bl;
}
public static Tuple<int, int, int, int> longToArgb(long argb)
{
var max = Math.Pow(16, 8) - 1;
if (argb < 0 || argb > max)
throw new ArgumentOutOfRangeException("argb", "argb must be between or equal to 0-" + max);
int a = (int)((argb & 0xFF000000) >> 24);
int r = (int)((argb & 0x00FF0000) >> 16);
int g = (int)((argb & 0x0000FF00) >> 8);
int b = (int)(argb & 0x000000FF);
return new Tuple<int, int, int, int>(a, r, g, b);
}
Wasn't sure what language, since C# and Java is tagged.
You can use bitwise operators with 8 bits offset. For example, in RGB 255,255,128 to integer would be (255 << 16) + (255 << 8) + (128)
If you need another octet just add it with << 24.. Like (a << 24) + (r << 16) + (g << 8) + b ..

Java little endian order

I need to store data as LITTLE_ENDIAN instead of default BIG_ENDIAN.
Here's my sample code:
for (int i = 0; i < logo.length; i++) {
logoArray[i] = ((Integer) logo[i]).byteValue();
logoArray[i] = (byte) (((logoArray[i] & 1) << 7) + ((logoArray[i] & 2) << 5) + ((logoArray[i] & 4) << 3)
+ ((logoArray[i] & 8) << 1) + ((logoArray[i] & 16) >> 1) + ((logoArray[i] & 32) >> 3)
+ ((logoArray[i] & 64) >> 5) + ((logoArray[i] & 128) >> 7));
}
How should it be rewritten with ByteBuffer, for LITTLE_ENDIAN, as the following code doesn't work for me:
ByteBuffer record = ByteBuffer.allocate(logo.length);
record.order(ByteOrder.LITTLE_ENDIAN);
...
record.put(((Integer) logo[i]).byteValue());
...
record.array(); // get
ByteBuffer will work for you, if you use putInt and not put.
record.putInt((Integer) logo[i]);
A byte array (as Integer.byteValue()) has no "endianness" so it is stored as it is.
As andcoz says, the endian isn't taken into account when you put one byte at a time. Here is an example to show you how to do it:
import java.nio.*;
public class Test {
public static void main(String[] args) {
int[] logo = { 0xAABBCCDD, 0x11223344 };
byte[] logoLE = new byte[logo.length * 4];
ByteBuffer rec = ByteBuffer.wrap(logoLE).order(ByteOrder.LITTLE_ENDIAN);
for (int i = 0; i < logo.length; i++)
rec.putInt(logo[i]);
// Debug printouts...
System.out.println("logo:");
for (int b : logo)
System.out.println(Integer.toHexString((b < 0 ? b + 256 : b)));
System.out.println("\nlogoLE:");
int tmp = 0;
for (byte b : logoLE) {
System.out.print(Integer.toHexString((b < 0 ? b + 256 : b)));
if (++tmp % 4 == 0)
System.out.println();
}
}
}
Output:
logo:
aabbccdd
11223344
logoLE:
ddccbbaa
44332211

Categories

Resources