I want to print image along with some other texts through zebra printer from android application. I am able to create zpl code for text data but I am having to problem to create zpl code for image. The zpl do not supports base64 code. The image needs to be converted to hex ascii and print using ^GF command.
The raw data with both text and image is available on this Pastebin link, and can be viewed in labelary viewer.
Is there any image conversion process?
I solved the problem and I am posting the answer so that other people can take benefit from the solution. The bitmap image can be converted to zpl code using following converter class.
public class ZPLConverter {
private int blackLimit = 380;
private int total;
private int widthBytes;
private boolean compressHex = false;
private static Map<Integer, String> mapCode = new HashMap<Integer, String>();
{
mapCode.put(1, "G");
mapCode.put(2, "H");
mapCode.put(3, "I");
mapCode.put(4, "J");
mapCode.put(5, "K");
mapCode.put(6, "L");
mapCode.put(7, "M");
mapCode.put(8, "N");
mapCode.put(9, "O");
mapCode.put(10, "P");
mapCode.put(11, "Q");
mapCode.put(12, "R");
mapCode.put(13, "S");
mapCode.put(14, "T");
mapCode.put(15, "U");
mapCode.put(16, "V");
mapCode.put(17, "W");
mapCode.put(18, "X");
mapCode.put(19, "Y");
mapCode.put(20, "g");
mapCode.put(40, "h");
mapCode.put(60, "i");
mapCode.put(80, "j");
mapCode.put(100, "k");
mapCode.put(120, "l");
mapCode.put(140, "m");
mapCode.put(160, "n");
mapCode.put(180, "o");
mapCode.put(200, "p");
mapCode.put(220, "q");
mapCode.put(240, "r");
mapCode.put(260, "s");
mapCode.put(280, "t");
mapCode.put(300, "u");
mapCode.put(320, "v");
mapCode.put(340, "w");
mapCode.put(360, "x");
mapCode.put(380, "y");
mapCode.put(400, "z");
}
public String convertFromImage(Bitmap image, Boolean addHeaderFooter) {
String hexAscii = createBody(image);
if (compressHex) {
hexAscii = encodeHexAscii(hexAscii);
}
String zplCode = "^GFA," + total + "," + total + "," + widthBytes + ", " + hexAscii;
if (addHeaderFooter) {
String header = "^XA " + "^FO0,0^GFA," + total + "," + total + "," + widthBytes + ", ";
String footer = "^FS" + "^XZ";
zplCode = header + zplCode + footer;
}
return zplCode;
}
private String createBody(Bitmap bitmapImage) {
StringBuilder sb = new StringBuilder();
int height = bitmapImage.getHeight();
int width = bitmapImage.getWidth();
int rgb, red, green, blue, index = 0;
char auxBinaryChar[] = {'0', '0', '0', '0', '0', '0', '0', '0'};
widthBytes = width / 8;
if (width % 8 > 0) {
widthBytes = (((int) (width / 8)) + 1);
} else {
widthBytes = width / 8;
}
this.total = widthBytes * height;
for (int h = 0; h < height; h++) {
for (int w = 0; w < width; w++) {
rgb = bitmapImage.getPixel(w, h);
red = (rgb >> 16) & 0x000000FF;
green = (rgb >> 8) & 0x000000FF;
blue = (rgb) & 0x000000FF;
char auxChar = '1';
int totalColor = red + green + blue;
if (totalColor > blackLimit) {
auxChar = '0';
}
auxBinaryChar[index] = auxChar;
index++;
if (index == 8 || w == (width - 1)) {
sb.append(fourByteBinary(new String(auxBinaryChar)));
auxBinaryChar = new char[]{'0', '0', '0', '0', '0', '0', '0', '0'};
index = 0;
}
}
sb.append("\n");
}
return sb.toString();
}
private String fourByteBinary(String binaryStr) {
int decimal = Integer.parseInt(binaryStr, 2);
if (decimal > 15) {
return Integer.toString(decimal, 16).toUpperCase();
} else {
return "0" + Integer.toString(decimal, 16).toUpperCase();
}
}
private String encodeHexAscii(String code) {
int maxlinea = widthBytes * 2;
StringBuilder sbCode = new StringBuilder();
StringBuilder sbLinea = new StringBuilder();
String previousLine = null;
int counter = 1;
char aux = code.charAt(0);
boolean firstChar = false;
for (int i = 1; i < code.length(); i++) {
if (firstChar) {
aux = code.charAt(i);
firstChar = false;
continue;
}
if (code.charAt(i) == '\n') {
if (counter >= maxlinea && aux == '0') {
sbLinea.append(",");
} else if (counter >= maxlinea && aux == 'F') {
sbLinea.append("!");
} else if (counter > 20) {
int multi20 = (counter / 20) * 20;
int resto20 = (counter % 20);
sbLinea.append(mapCode.get(multi20));
if (resto20 != 0) {
sbLinea.append(mapCode.get(resto20)).append(aux);
} else {
sbLinea.append(aux);
}
} else {
sbLinea.append(mapCode.get(counter)).append(aux);
}
counter = 1;
firstChar = true;
if (sbLinea.toString().equals(previousLine)) {
sbCode.append(":");
} else {
sbCode.append(sbLinea.toString());
}
previousLine = sbLinea.toString();
sbLinea.setLength(0);
continue;
}
if (aux == code.charAt(i)) {
counter++;
} else {
if (counter > 20) {
int multi20 = (counter / 20) * 20;
int resto20 = (counter % 20);
sbLinea.append(mapCode.get(multi20));
if (resto20 != 0) {
sbLinea.append(mapCode.get(resto20)).append(aux);
} else {
sbLinea.append(aux);
}
} else {
sbLinea.append(mapCode.get(counter)).append(aux);
}
counter = 1;
aux = code.charAt(i);
}
}
return sbCode.toString();
}
public void setCompressHex(boolean compressHex) {
this.compressHex = compressHex;
}
public void setBlacknessLimitPercentage(int percentage) {
blackLimit = (percentage * 768 / 100);
}
}
Example usage:
You need to convert the your image to bitmap, convert to monochrome image and do hex acii conversion. The generated zpl code can be checked at labelary viewer.
public class Utils {
public static String getZplCode(Bitmap bitmap, Boolean addHeaderFooter) {
ZPLConverter zp = new ZPLConverter();
zp.setCompressHex(true);
zp.setBlacknessLimitPercentage(50);
Bitmap grayBitmap = toGrayScale(bitmap);
return zp.convertFromImage(grayBitmap, addHeaderFooter);
}
public static Bitmap toGrayScale(Bitmap bmpOriginal) {
int width, height;
height = bmpOriginal.getHeight();
width = bmpOriginal.getWidth();
Bitmap grayScale = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(grayScale);
Paint paint = new Paint();
ColorMatrix cm = new ColorMatrix();
cm.setSaturation(0);
ColorMatrixColorFilter f = new ColorMatrixColorFilter(cm);
paint.setColorFilter(f);
c.drawBitmap(bmpOriginal, 0, 0, paint);
return grayScale;
}
}
The converter code has been referenced from here and added support for android use.
I know this is kind of done deal but I still struggle a lot with the current answer. I wanted to share my experience for those who might need it.
First of all,^GFA stands for hexadecial representation of the pixel but it has to be converted into readable text (ASCII). Here is an example :
Pixels white = 1, black = 1
1011 0100 translate into 0xB4
In the data section of ^GFA, you need to have B4 as data.
If we go with
Pixel line 1 : 1011 0100 1001 1100 = 0xBA 0x9C
Pixel line 2 : 0011 0110 0001 1111 = 0x36 0x1F
the resulting ZPL code will be :
^XA (needed to start a ZPL file)
^F10,0 (offsets 10 pixel horizontal, 0 pixel vertical)
^GFA,4,4,2,BA9C361F (4 is the total number of byte, 2 is the number of byte per line)
^F0^XZ (end of file)
Now, the interesting point. How to get to code that :
You need a gray-scale bitmap. You need pixel-wise access to the bitmap. In another words, an array containing integer which values varies from 0 to 255.
With that array you take each bunch of 8 pixels, convert it to hexadecimal value and then to text representation of these hexadecimals. Here is the c++ code made with Borland :
Graphics::TBitmap *imageFax = new Graphics::TBitmap();
unsigned char r;
unsigned char b;
ofstream outFile;
char listeHex[16];
int lineByteWidth;
int j;
int bytesCount = 0;
int widthHeight;
AnsiString testOut;
listeHex[0] = '0';
listeHex[1] = '1';
listeHex[2] = '2';
listeHex[3] = '3';
listeHex[4] = '4';
listeHex[5] = '5';
listeHex[6] = '6';
listeHex[7] = '7';
listeHex[8] = '8';
listeHex[9] = '9';
listeHex[10] = 'A';
listeHex[11] = 'B';
listeHex[12] = 'C';
listeHex[13] = 'D';
listeHex[14] = 'E';
listeHex[15] = 'F';
imageFax->Monochrome = true;
imageFax->PixelFormat = pf8bit;
imageFax->LoadFromFile("c:/testEtiquette/test.bmp"); //1200x300pixels bitmap test image
testOut = "c:/testEtiquette/outputfile.txt";
outFile.open(testOut.c_str());
imageFax->PixelFormat = pf8bit;
lineByteWidth = imageFax->Width/8;//Number of byte per line
widthHeight = lineByteWidth*imageFax->Height;//number of total byte to be written into the output file
testOut = "^XA^FO10,0^GFA,";
outFile << testOut.c_str() << widthHeight << ',' << widthHeight << ',' << lineByteWidth << ',' ;
for(int i = 0; i < imageFax->Height; i++)
{
unsigned char * pixel = (unsigned char *)imageFax->ScanLine[i];
bytesCount = 0;
b=0x00;
for(j = 0; j < imageFax->Width; j++)
{
//Here is the "switch" : what is not white (255) bit = 0, is black bit = 1.
//You can set your switch at whatever value you think is best. 0, 255 or anything between.
//I think 255 (white) is a good for my application
if(pixel[j] != 255)
{
b = b<<1;
//It is not white (hence black), we force value 1 into current position
b = b|0x01;
}
else
{
//Since it white, we move 1 bit to the left, pushing 0 into current position
b = b<<1;
b = b&0xFE;//Forcing a 0 in the current position
}
//If we've got a full byte (8-bits), we write it into the file
//This will lead into cutting off part of images that width is not a multiple of 8
if(j%8 == 7)
{
bytesCount++;
r = b;
r = r&0xF0; //Cleaning last digits
r=r>>4; //Moving the bits to the left 0xF0 => 0x0F
outFile << listeHex[r%16]; //Reaching into the conversion array listeHex, ASCII representation of hex value
r = listeHex[r%16]; //For debug only
r = b;
r = r&0x0F;//Cleaning first digits
outFile << listeHex[r%16];//Reaching into the conversion array listeHex, ASCII representation of hex value
r = listeHex[r%16]; //For debug only
b = 0x00; //Reseting for next Byte
}
}
}
testOut = "^F0^XZ";
outFile << testOut.c_str();
outFile.close();
delete imageFax;
Some links :
ZPL PDF doc (see page 191 for Graphic conversion) https://www.zebra.com/content/dam/zebra/manuals/printers/common/programming/zpl-zbi2-pm-en.pdf
(If link does not work, try "zpl-zbi2-pm-en.pdf" on google)
https://www.rapidtables.com/convert/number/binary-to-hex.html
here is the complete working code of IP printer (Model GK420t ZPL And you can access any IP printer). Just replace only three things 1) Add you IP address 2) add your port number 3) Add you PNG File path
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Management;
using System.Net.Http;
using System.ServiceModel.Channels;
using System.Web;
using System.Web.Http;
using System.Net.Sockets;
using System.Net;
using System.Text;
using System.IO;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Printing;
using System.Net.NetworkInformation;
using System.Drawing.Imaging;
using System.Text.RegularExpressions;
using System.Drawing.Drawing2D;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Drawing.Printing;
namespace ConsoleApplication2
{
class Program
{
static void Main(string[] args)
{
string ipAddress = "Your IP address";
int port = Your port number;
string zplImageData = string.Empty;
string filePath = #"your png file path";
byte[] binaryData = System.IO.File.ReadAllBytes(filePath);
foreach (Byte b in binaryData)
{
string hexRep = String.Format("{0:X}", b);
if (hexRep.Length == 1)
hexRep = "0" + hexRep;
zplImageData += hexRep;
}
string zplToSend = "^XA" + "^FO50" + "50^GFA,120000,120000,100" + binaryData.Length + ",," + zplImageData + "^XZ";
string printImage = "^XA^FO115,50^IME:LOGO.PNG^FS^XZ";
try
{
// Open connection
System.Net.Sockets.TcpClient client = new System.Net.Sockets.TcpClient();
client.Connect(ipAddress, port);
// Write ZPL String to connection
System.IO.StreamWriter writer = new System.IO.StreamWriter(client.GetStream(), Encoding.UTF8);
writer.Write(zplToSend);
writer.Flush();
writer.Write(printImage);
writer.Flush();
// Close Connection
writer.Close();
client.Close();
}
catch (Exception ex)
{
// Catch Exception
}
}
}
}
I want to know how to hide some numbers in TextView and some are shown just like that
(****-****-1234)
Thank you
Try This Method...
public static String StrRpl(String str) {
char[] chars = str.toCharArray();
for (int i = 0, j = 0; i < chars.length && j < 5; i++) {
char ch = chars[i];
if (!Character.isWhitespace(ch)) {
chars[i] = '*';
j++;
}
}
str = new String(chars);
return str;
}
Output : *****234
pass a string to this method and it will return string with '*' character till first 5 characters (You can change your number of count.. current is 5)
How can i add "-" before each capital letter of my string apart from first capital letter of my string.
I have a string like this "HelloWorldMyNameIsCarl" and i am using this
"HelloWorldMyNameIsCarl".replaceAll("(.)(\\p{Lu})", "$1-$2")
it's working fine.
solution is
"Hello_World_My_Name_Is_Carl"
but for "THisForNEWTest" it's not working and solution is
"T-His-For-NEw-Test"
But i want
"T-His-For-N-Ew-Test"
please suggest me what i do for this problem.
thanks.
if there is a too complex problem for regular expressions, you can always use normal programming. it might even be a little bit more efficient :
public static String doIt(String input)
{
int size=input.length();
if(size==0)
return "";
StringBuilder sb=new StringBuilder(size);
sb.append(input.charAt(0));
for(int i=1;i<size;++i)
{
char c=input.charAt(i);
if(Character.isUpperCase(c))
sb.append('-');
sb.append(c);
}
return sb.toString();
}
in any case, for regular expressions tests, you can check out this website.
so, for regular expressions, the solution can be:
return input.charAt(0)+input.substring(1).replaceAll("(\\p{Lu})","-$1");
Why aren't you just doing this:
replaceAll("(\\p{Lu})", "-$1").replaceAll("^-", "")
Try Below Code:
String test = "THisForNEwTest";
int size = test.length();
StringBuffer sb = new StringBuffer();
if(size!=0)
sb.append(test.charAt(0));
for (int i = 1; i < size; i++) {
if(Character.isUpperCase(test.charAt(i))){
sb.append("-"+test.charAt(i));
}else{
sb.append(test.charAt(i));
}
}
System.out.println("result is::::"+sb.toString());
Try this:
public static String function(String str) {
StringBuilder result = new StringBuilder();
List<Integer> capital = new ArrayList<Integer>();
for (int i = 0; i < str.length(); i++)
if (Character.isUpperCase(str.charAt(i)))
capital.add(i);
int capIndex = 0;
int x = 0;
for (int y = 0; y < str.length(); y++) {
if(x < capital.size())
capIndex = capital.get(x);
if (y == 0) {
result.append(str.charAt(y));
x++;
} else if(y == capIndex){
result.append("-" + str.charAt(y));
x++;
} else {
if(str.charAt(y) != ' ')
result.append(str.charAt(y));
}
}
return result.toString();
}
I would like to check if the current char is a blank space as i dont want to change that. So i would like to change all the letters like i do now, but keep the spaces.
e.g. "that man" with C = 2 should become "vjcv ocp".
thanks in advance :)
String initialString = yourString.getText().toString();
char[] chars = initialString.toCharArray();
for (int i = 1; i <= chars.length; i++) {
C = Integer.valueOf(ceasarNr);
chars[i-1] = characters.get((characters.indexOf(chars[i-1]) + C)%29);
}
String resultString = new String(chars);
krypteredeTekst.setText(resultString);
}
Just skip the iteration if the character is a space:
String initialString = yourString.getText().toString();
char[] chars = initialString.toCharArray();
for (int i = 1; i <= chars.length; i++) {
//Skip if it is space.
if chars[i-1] == ' ';
continue;
C = Integer.valueOf(ceasarNr);
chars[i-1] = characters.get((characters.indexOf(chars[i-1]) + C)%29);
}
String resultString = new String(chars);
krypteredeTekst.setText(resultString);
}
There is method for checking if char is blank space ->
String initialString = yourString.getText().toString();
char[] chars = initialString.toCharArray();
for (int i = 1; i <= chars.length; i++) {
C = Integer.valueOf(ceasarNr);
if(!Character.isWhitespace(chars.charAt(i-1)) {
chars[i-1] = characters.get((characters.indexOf(chars[i-1]) + C)%29);
}
}
String resultString = new String(chars);
krypteredeTekst.setText(resultString);
TelephonyManager.getDeiceId() only return 14 digits of IMEI number.
But under Setting->Phone->Status show 15 digits.
I want to get 15 digit as appear under phone settings.
The IMEI (14 digits) is complemented by a check digit. The check digit is not
part of the digits transmitted at IMEI check occasions. The Check Digit shall
avoid manual transmission errors, e.g. when customers register stolen mobiles
at the operator's customer care desk.
http://www.tele-servizi.com/Janus/texts/imei.txt
http://en.wikipedia.org/wiki/International_Mobile_Equipment_Identity
TelephonyManager mTelephonyMgr;
mTelephonyMgr = (TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE);
mTelephonyMgr.getDeviceId()
This is what i have done and i getting all the 15 digits may this can help u ...
Or you can manually calculate the check-sum of the 14-digit IMEI number. e.g.
private int GetCheckSumDigit(String id) {
int digit = -1;
try{
if(id.length() == 14)
{
String str = "";
char[] digits = new char[id.length()];
id.getChars(0, id.length(), digits, 0);
for(int i=0; i<digits.length; i++)
{
String ch = digits[i]+"";
if((i+1)%2==0)
{
int x = Integer.parseInt(digits[i]+"");
x *= 2;
ch = x+"";
}
str += ch;
}
digits = new char[str.length()];
str.getChars(0, str.length(), digits, 0);
int total = 0;
for(int i=0; i<str.length(); i++)
total += Integer.parseInt(digits[i]+"");
//
int count = 0;
while((total+count)%10 != 0)
count++;
digit = count;
}
}catch(Exception exx)
{
exx.printStackTrace();
}
return digit;
}
Good Luck.
Some devices don't add last digit, we need to calculate last digit instead using Luhn algorithm:
private int getImeiCheckDigit(String imei14digits) {
if (imei14digits == null || imei14digits.length() != 14) {
throw new IllegalArgumentException("IMEI should be 14 digits");
}
int[] imeiArray = new int[imei14digits.length()];
final int DIVIDER = 10;
char[] chars = imei14digits.toCharArray();
for (int i = 0; i < chars.length; i++) {
imeiArray[i] = Character.getNumericValue(chars[i]);
}
int sum = 0;
for (int i = 0; i < imeiArray.length; i++) {
if (i % 2 == 0) {
sum += imeiArray[i];
} else {
int multi = imeiArray[i] * 2;
if (multi >= DIVIDER) {
sum += multi % DIVIDER;
sum += multi / DIVIDER;
} else {
sum += multi;
}
}
}
return (DIVIDER - sum % DIVIDER) % DIVIDER;
}