From eedcba5b7946923bfac73b7d4d9b9d7157c19fba Mon Sep 17 00:00:00 2001 From: Trudu Laurent Date: Fri, 20 Dec 2024 10:41:56 +0100 Subject: [PATCH] Revert to previous version with CPP optimized Bitmap to CPCL/ZPL --- PrintWrapper/build.gradle | 19 ++ PrintWrapper/proguard-rules.pro | 17 ++ PrintWrapper/src/main/cpp/CMakeLists.txt | 47 ++++ PrintWrapper/src/main/cpp/CPCHelper.cpp | 135 +++++++++ PrintWrapper/src/main/cpp/Internal.h | 43 +++ PrintWrapper/src/main/cpp/ZPLHelper.cpp | 227 +++++++++++++++ PrintWrapper/src/main/cpp/base64.h | 259 ++++++++++++++++++ PrintWrapper/src/main/cpp/jni.cpp | 140 ++++++++++ .../printwrapper/RasterizationHelper.java | 8 +- gradle.properties | 2 +- jitpack.yml | 45 ++- 11 files changed, 937 insertions(+), 5 deletions(-) create mode 100644 PrintWrapper/src/main/cpp/CMakeLists.txt create mode 100644 PrintWrapper/src/main/cpp/CPCHelper.cpp create mode 100644 PrintWrapper/src/main/cpp/Internal.h create mode 100644 PrintWrapper/src/main/cpp/ZPLHelper.cpp create mode 100644 PrintWrapper/src/main/cpp/base64.h create mode 100644 PrintWrapper/src/main/cpp/jni.cpp diff --git a/PrintWrapper/build.gradle b/PrintWrapper/build.gradle index 48e767d..766fd6b 100644 --- a/PrintWrapper/build.gradle +++ b/PrintWrapper/build.gradle @@ -14,6 +14,7 @@ ext { android { namespace 'com.zebra.printwrapper' + ndkVersion '28.0.12674087 rc2' compileSdkVersion 34 defaultConfig { @@ -21,6 +22,18 @@ android { targetSdkVersion 34 versionCode 17 versionName "1.17" + + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + consumerProguardFiles "consumer-rules.pro" + + externalNativeBuild { + cmake { + cppFlags "-std=c++14" + } + } + ndk { + abiFilters 'x86', 'x86_64', 'armeabi-v7a', 'arm64-v8a' + } } buildTypes { @@ -33,6 +46,12 @@ android { debuggable true } } + externalNativeBuild { + cmake { + path "src/main/cpp/CMakeLists.txt" + version "3.22.1" + } + } compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 diff --git a/PrintWrapper/proguard-rules.pro b/PrintWrapper/proguard-rules.pro index f1b4245..6ed490b 100644 --- a/PrintWrapper/proguard-rules.pro +++ b/PrintWrapper/proguard-rules.pro @@ -19,3 +19,20 @@ # If you keep the line number information, uncomment this to # hide the original source file name. #-renamesourcefileattribute SourceFile + +#-renamesourcefileattribute SourceFile +#noinspection ShrinkerUnresolvedReference +-keepclassmembers class **.RasterizationHelper { + native ; + #noinspection ShrinkerUnresolvedReference + String getUtilsVersion(); + #noinspection ShrinkerUnresolvedReference,ShrinkerUnresolvedReference + String createBitmapZPL(Bitmap); + #noinspection ShrinkerUnresolvedReference,ShrinkerUnresolvedReference + String createBitmapCPC(Bitmap); +} + +# Parceler library +-keep interface org.parceler.Parcel +-keep @org.parceler.Parcel class * { *; } +-keep class **$$Parcelable { *; } \ No newline at end of file diff --git a/PrintWrapper/src/main/cpp/CMakeLists.txt b/PrintWrapper/src/main/cpp/CMakeLists.txt new file mode 100644 index 0000000..7eb1cd5 --- /dev/null +++ b/PrintWrapper/src/main/cpp/CMakeLists.txt @@ -0,0 +1,47 @@ +# For more information about using CMake with Android Studio, read the +# documentation: https://d.android.com/studio/projects/add-native-code.html + +# Sets the minimum version of CMake required to build the native library. + +cmake_minimum_required(VERSION 3.4.1) + +add_definitions(-DANDROID) + +if (CMAKE_BUILD_TYPE STREQUAL "Release") + add_definitions(-DNDEBUG) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=hidden -fvisibility-inlines-hidden -ffunction-sections -fdata-sections") + set(LINKER_FLAGS "${LINKER_FLAGS} --strip-all") + Message("--- Release Mode ---") +endif() + +include_directories(src/main/cpp/) + +add_library( # Sets the name of the library. + ZebraUtils + + # Sets the library as a shared library. + SHARED + + # Provides a relative path to your source file(s). + jni.cpp + ZPLHelper.cpp + CPCHelper.cpp + Internal.h) + +find_library( # Sets the name of the path variable. + log-lib + z + jnigraphics + # Specifies the name of the NDK library that + # you want CMake to locate. + log) + +target_link_libraries( # Specifies the target library. + ZebraUtils + -ljnigraphics + -lz + -llog + + # Links the target library to the log library + # included in the NDK. + ${log-lib}) \ No newline at end of file diff --git a/PrintWrapper/src/main/cpp/CPCHelper.cpp b/PrintWrapper/src/main/cpp/CPCHelper.cpp new file mode 100644 index 0000000..3c63d47 --- /dev/null +++ b/PrintWrapper/src/main/cpp/CPCHelper.cpp @@ -0,0 +1,135 @@ +#include "Internal.h" + +const char hexmap[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; + + +bool CPCconvertImage(AndroidBitmapInfo *info, void *pixels, char **out) +{ + uint32_t iWidth = info->width; + uint32_t iHeight = info->height; + uint32_t iMonoSize = ((iWidth * iHeight) / 8); + uint32_t iGreySize = iHeight * iWidth * sizeof(int16_t); + void *pPtr = pixels; + + *out = nullptr; + int16_t* bGreyImg = (int16_t*) malloc(iGreySize); + if (bGreyImg == nullptr) + { + LOGE("Memory allocation failed (GreyImage)"); + return false; + } + int8_t* bMonoImg = (int8_t *) malloc(iMonoSize); + if (bMonoImg == nullptr) + { + LOGE("Memory allocation failed (Mono Image)"); + free(bGreyImg); + return false; + } + + uint8_t bValue = 0; + int oldpixel, newpixel, error; + bool nbottom, nleft, nright; + + //RGB888 Format + if (info->format == ANDROID_BITMAP_FORMAT_RGBA_8888) + { + for (int y=0; y < iHeight; y++) + { + uint32_t *line = (uint32_t *) pPtr; + for (int x=0; x> 24; + int r = (col & 0xff0000 ) >> 16; + int g = (col & 0x00ff00 ) >> 8; + int b = (col & 0x0000ff ); + int m = (int)(0.299 * (double)r + 0.587 * (double)g + 0.114 * (double)b); + m = ((a * m) + ((255-a) * 255)) / 255; + if (m > 255) m = 255; + if (m < 0) m = 0; + bGreyImg[AT(x,y)] = m; + } + pPtr = (char *) pPtr + info->stride; + } + } + // RGB565 Format + else if (info->format == ANDROID_BITMAP_FORMAT_RGB_565) + { + for (int y=0; y < iHeight; y++) + { + uint16_t *line = (uint16_t *) pPtr; + for (int x=0; x 255) m = 255; + if (m < 0) m = 0; + bGreyImg[AT(x,y)] = m; + } + pPtr = (char *) pPtr + info->stride; + } + }else { + LOGE("Bitmap format not supported"); + free(bGreyImg); + free(bMonoImg); + return false; + } + + // Dither the Image + for (int y = 0; y < iHeight; y++) + { + nbottom = y < iHeight - 1; + for (int x = 0; x < iWidth; x++) + { + nleft = x > 0; + nright = x < iWidth - 1; + + oldpixel = bGreyImg[AT(x,y)]; + newpixel = oldpixel < 128 ? 0 : 255; + bGreyImg[AT(x,y)] = newpixel; + + error = oldpixel - newpixel; + if (nright) bGreyImg[AT(x+1,y)] += (int) (error * (7. / 16)); + if (nleft & nbottom) bGreyImg[AT(x-1,y+1)] += (int) (error * (3. / 16)); + if (nbottom) bGreyImg[AT(x,y+1)] += (int) (error * (5. / 16)); + if (nright && nbottom) bGreyImg[AT(x+1,y+1)] += (int) (error * (1. / 16)); + } + } + + //Convert to Mono + int iPos = 0; + for (int y = 0; y < iHeight; y++) + { + for (int x = 0; x < iWidth; x++) + { + bValue <<= 1; + if (bGreyImg[AT(x,y)] < 128) bValue |=1; + if (iPos % 8 == 7) bMonoImg[iPos >> 3] = (bValue & 0xff); + iPos++; + } + } + + //Free some space + free(bGreyImg); + + char *outPtr = (char *) malloc((iMonoSize << 1) + 2); + if (outPtr == nullptr) + { + LOGE("Memory allocation failed (CPC Data)"); + free(bGreyImg); + } + memset(outPtr,0,((iMonoSize << 1) + 2)); + *out = outPtr; + + //Return CPC data + for (int p=0; p < iMonoSize; p++) + { + outPtr[p * 2] = hexmap[(bMonoImg[p] & 0xF0) >> 4]; + outPtr[p * 2 + 1] = hexmap[(bMonoImg[p] & 0x0F)]; + } + free(bMonoImg); + return true; +} \ No newline at end of file diff --git a/PrintWrapper/src/main/cpp/Internal.h b/PrintWrapper/src/main/cpp/Internal.h new file mode 100644 index 0000000..4ebd70e --- /dev/null +++ b/PrintWrapper/src/main/cpp/Internal.h @@ -0,0 +1,43 @@ +#ifndef ZEBRA_UTILS_INTERNAL_H +#define ZEBRA_UTILS_INTERNAL_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "base64.h" + +//Globals +extern JavaVM* g_JVM; + +#ifdef NDEBUG +#define ENGINE_VERSION "1.1.0.0 ( " __DATE__ " )" +#else +#define ENGINE_VERSION "1.1.0.0 ( " __DATE__ " ) - Debug" +#endif + +//Useful defines +#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG,__VA_ARGS__) +#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG,__VA_ARGS__) +#define SIZE(s) (sizeof(s) / sizeof(s[0])) +#define ZPLHELPER_CLASS "com/zebra/printwrapper/RasterizationHelper" +#define LOG_TAG "Zebra-Utils" +#define RED(a) (((((a >> 11) & 0x1F) * 527) + 23) >> 6) +#define GREEN(a) (((((a >> 5) & 0x3F) * 259) + 33) >> 6) +#define BLUE(a) ((((a & 0x1F) * 527) + 23) >> 6) +#define AT(x,y) ((iWidth * (y)) + (x)) + +//RasterizationHelper.cpp +bool ZPLconvertImage(AndroidBitmapInfo *info, void *pixels, char **out); + +//CPCHelper.cpp +bool CPCconvertImage(AndroidBitmapInfo *info, void *pixels, char **out); + + +#endif //ZEBRA_UTILS_INTERNAL_H diff --git a/PrintWrapper/src/main/cpp/ZPLHelper.cpp b/PrintWrapper/src/main/cpp/ZPLHelper.cpp new file mode 100644 index 0000000..2e7476b --- /dev/null +++ b/PrintWrapper/src/main/cpp/ZPLHelper.cpp @@ -0,0 +1,227 @@ +#include "Internal.h" + +static int crcTable[] = { + 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, + 0x60c6, 0x70e7, 0x8108, 0x9129, 0xa14a, 0xb16b, + 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef, 0x1231, 0x0210, + 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6, + 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, + 0xf3ff, 0xe3de, 0x2462, 0x3443, 0x0420, 0x1401, + 0x64e6, 0x74c7, 0x44a4, 0x5485, 0xa56a, 0xb54b, + 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d, + 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, + 0x5695, 0x46b4, 0xb75b, 0xa77a, 0x9719, 0x8738, + 0xf7df, 0xe7fe, 0xd79d, 0xc7bc, 0x48c4, 0x58e5, + 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823, + 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, + 0xa90a, 0xb92b, 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, + 0x1a71, 0x0a50, 0x3a33, 0x2a12, 0xdbfd, 0xcbdc, + 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a, + 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, + 0x0c60, 0x1c41, 0xedae, 0xfd8f, 0xcdec, 0xddcd, + 0xad2a, 0xbd0b, 0x8d68, 0x9d49, 0x7e97, 0x6eb6, + 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70, + 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, + 0x9f59, 0x8f78, 0x9188, 0x81a9, 0xb1ca, 0xa1eb, + 0xd10c, 0xc12d, 0xf14e, 0xe16f, 0x1080, 0x00a1, + 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067, + 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, + 0xe37f, 0xf35e, 0x02b1, 0x1290, 0x22f3, 0x32d2, + 0x4235, 0x5214, 0x6277, 0x7256, 0xb5ea, 0xa5cb, + 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d, + 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, + 0x5424, 0x4405, 0xa7db, 0xb7fa, 0x8799, 0x97b8, + 0xe75f, 0xf77e, 0xc71d, 0xd73c, 0x26d3, 0x36f2, + 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634, + 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, + 0xb98a, 0xa9ab, 0x5844, 0x4865, 0x7806, 0x6827, + 0x18c0, 0x08e1, 0x3882, 0x28a3, 0xcb7d, 0xdb5c, + 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a, + 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, + 0x2ab3, 0x3a92, 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, + 0xbdaa, 0xad8b, 0x9de8, 0x8dc9, 0x7c26, 0x6c07, + 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1, + 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, + 0x8fd9, 0x9ff8, 0x6e17, 0x7e36, 0x4e55, 0x5e74, + 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0 }; + +/***************************************************************************************/ +static int CRC16(char *in, int input_len) +{ + int i; + int crc_value = 0; + + for (int len = 0; len > 8)) & 0xff; + crc_value = crcTable[i] ^ (crc_value << 8); + } + return crc_value & 0xffff; +} +/***************************************************************************************/ +bool ZPLconvertImage(AndroidBitmapInfo *info, void *pixels, char **out) +{ + uint32_t iWidth = info->width; + uint32_t iHeight = info->height; + uint32_t iMonoSize = ((iWidth * iHeight) / 8); + uint32_t iGreySize = iHeight * iWidth * sizeof(int16_t); + void *pPtr = pixels; + char crc[10]; + + *out = nullptr; + int16_t* bGreyImg = (int16_t*) malloc(iGreySize); + if (bGreyImg == nullptr) + { + LOGE("Memory allocation failed (GreyImage)"); + return false; + } + int8_t* bMonoImg = (int8_t *) malloc(iMonoSize); + if (bMonoImg == nullptr) + { + LOGE("Memory allocation failed (Mono Image)"); + free(bGreyImg); + return false; + } + + z_stream strm; + uint8_t bValue = 0; + + int oldpixel, newpixel, error; + bool nbottom, nleft, nright; + + //RGB888 Format + if (info->format == ANDROID_BITMAP_FORMAT_RGBA_8888) + { + for (int y=0; y < iHeight; y++) + { + uint32_t *line = (uint32_t *) pPtr; + for (int x=0; x> 24; + int r = (col & 0xff0000 ) >> 16; + int g = (col & 0x00ff00 ) >> 8; + int b = (col & 0x0000ff ); + int m = (int)(0.299 * (double)r + 0.587 * (double)g + 0.114 * (double)b); + m = ((a * m) + ((255-a) * 255)) / 255; + if (m > 255) m = 255; + if (m < 0) m = 0; + bGreyImg[AT(x,y)] = m; + } + pPtr = (char *) pPtr + info->stride; + } + } + // RGB565 Format + else if (info->format == ANDROID_BITMAP_FORMAT_RGB_565) + { + for (int y=0; y < iHeight; y++) + { + uint16_t *line = (uint16_t *) pPtr; + for (int x=0; x 255) m = 255; + if (m < 0) m = 0; + bGreyImg[AT(x,y)] = m; + } + pPtr = (char *) pPtr + info->stride; + } + }else { + LOGE("Bitmap format not supported"); + free(bGreyImg); + free(bMonoImg); + return false; + } + + // Dither the Image + for (int y = 0; y < iHeight; y++) + { + nbottom = y < iHeight - 1; + for (int x = 0; x < iWidth; x++) + { + nleft = x > 0; + nright = x < iWidth - 1; + + oldpixel = bGreyImg[AT(x,y)]; + newpixel = oldpixel < 128 ? 0 : 255; + bGreyImg[AT(x,y)] = newpixel; + + error = oldpixel - newpixel; + if (nright) bGreyImg[AT(x+1,y)] += (int) (error * (7. / 16)); + if (nleft & nbottom) bGreyImg[AT(x-1,y+1)] += (int) (error * (3. / 16)); + if (nbottom) bGreyImg[AT(x,y+1)] += (int) (error * (5. / 16)); + if (nright && nbottom) bGreyImg[AT(x+1,y+1)] += (int) (error * (1. / 16)); + } + } + + //Convert to Mono + int iPos = 0; + for (int y = 0; y < iHeight; y++) + { + for (int x = 0; x < iWidth; x++) + { + bValue <<= 1; + if (bGreyImg[AT(x,y)] < 128) bValue |=1; + if (iPos % 8 == 7) bMonoImg[iPos >> 3] = (bValue & 0xff); + iPos++; + } + } + + //Compress the Image + memset(&strm, 0, sizeof(strm)); + int ret = deflateInit(&strm, Z_BEST_COMPRESSION); + if (ret != Z_OK) + { + LOGE("Deflate allocation failed"); + free(bGreyImg); + free(bMonoImg); + return false; + } + + //Compress the data + strm.next_in = reinterpret_cast(bMonoImg); + strm.avail_in = iMonoSize; + strm.next_out = reinterpret_cast(bGreyImg); + strm.avail_out = iGreySize; + ret = deflate(&strm, Z_FINISH); + + uint32_t compressed_size = iGreySize - strm.avail_out; + deflateEnd(&strm); + + //Report Fail if compression failed + if (ret != Z_STREAM_END) + { + LOGE("Deflate failed"); + free(bGreyImg); + free(bMonoImg); + return false; + } + + //Free some space + free(bMonoImg); + + //Allocate B64 Buffer + uint32_t allocSize = Base64::EncodedLength(compressed_size); + char *outPtr = (char *) malloc(allocSize + 20); + if (outPtr == nullptr) + { + LOGE("Memory allocation failed (Z64 Data)"); + free(bGreyImg); + } + *out = outPtr; + + //Return Base 64 with CRC16 + strcpy(outPtr,":Z64:"); + outPtr += 5; + Base64::Encode((const char*) bGreyImg,compressed_size,outPtr,allocSize); + sprintf(crc,":%04X",CRC16(outPtr, strlen(outPtr))); + strcat(outPtr,crc); + + free(bGreyImg); + return true; +} + diff --git a/PrintWrapper/src/main/cpp/base64.h b/PrintWrapper/src/main/cpp/base64.h new file mode 100644 index 0000000..c713d3e --- /dev/null +++ b/PrintWrapper/src/main/cpp/base64.h @@ -0,0 +1,259 @@ +// +// Created by PHXN34 on 02/10/2017. +// + +#ifndef EMSCRIPT_BASE64_H +#define EMSCRIPT_BASE64_H + +#include + +const char kBase64Alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789+/"; + +class Base64 { +public: + static bool Encode(const std::string &in, std::string *out) { + int i = 0, j = 0; + size_t enc_len = 0; + unsigned char a3[3]; + unsigned char a4[4]; + + out->resize(EncodedLength(in)); + + int input_len = in.size(); + std::string::const_iterator input = in.begin(); + + while (input_len--) { + a3[i++] = *(input++); + if (i == 3) { + a3_to_a4(a4, a3); + + for (i = 0; i < 4; i++) { + (*out)[enc_len++] = kBase64Alphabet[a4[i]]; + } + + i = 0; + } + } + + if (i) { + for (j = i; j < 3; j++) { + a3[j] = '\0'; + } + + a3_to_a4(a4, a3); + + for (j = 0; j < i + 1; j++) { + (*out)[enc_len++] = kBase64Alphabet[a4[j]]; + } + + while ((i++ < 3)) { + (*out)[enc_len++] = '='; + } + } + + return (enc_len == out->size()); + } + + static bool Encode(const char *input, size_t input_length, char *out, size_t out_length) { + int i = 0, j = 0; + char *out_begin = out; + unsigned char a3[3]; + unsigned char a4[4]; + + size_t encoded_length = EncodedLength(input_length); + + if (out_length < encoded_length) return false; + + while (input_length--) { + a3[i++] = *input++; + if (i == 3) { + a3_to_a4(a4, a3); + + for (i = 0; i < 4; i++) { + *out++ = kBase64Alphabet[a4[i]]; + } + + i = 0; + } + } + + if (i) { + for (j = i; j < 3; j++) { + a3[j] = '\0'; + } + + a3_to_a4(a4, a3); + + for (j = 0; j < i + 1; j++) { + *out++ = kBase64Alphabet[a4[j]]; + } + + while ((i++ < 3)) { + *out++ = '='; + } + } + + *out++ = 0; + return (out == (out_begin + encoded_length)); + } + + static bool Decode(const std::string &in, std::string *out) { + int i = 0, j = 0; + size_t dec_len = 0; + unsigned char a3[3]; + unsigned char a4[4]; + + int input_len = in.size(); + std::string::const_iterator input = in.begin(); + + out->resize(DecodedLength(in)); + + while (input_len--) { + if (*input == '=') { + break; + } + + a4[i++] = *(input++); + if (i == 4) { + for (i = 0; i <4; i++) { + a4[i] = b64_lookup(a4[i]); + } + + a4_to_a3(a3,a4); + + for (i = 0; i < 3; i++) { + (*out)[dec_len++] = a3[i]; + } + + i = 0; + } + } + + if (i) { + for (j = i; j < 4; j++) { + a4[j] = '\0'; + } + + for (j = 0; j < 4; j++) { + a4[j] = b64_lookup(a4[j]); + } + + a4_to_a3(a3,a4); + + for (j = 0; j < i - 1; j++) { + (*out)[dec_len++] = a3[j]; + } + } + + return (dec_len == out->size()); + } + + static bool Decode(const char *input, size_t input_length, char *out, size_t out_length) { + int i = 0, j = 0; + char *out_begin = out; + unsigned char a3[3]; + unsigned char a4[4]; + + size_t decoded_length = DecodedLength(input, input_length); + + if (out_length < decoded_length) return false; + + while (input_length--) { + if (*input == '=') { + break; + } + + a4[i++] = *(input++); + if (i == 4) { + for (i = 0; i <4; i++) { + a4[i] = b64_lookup(a4[i]); + } + + a4_to_a3(a3,a4); + + for (i = 0; i < 3; i++) { + *out++ = a3[i]; + } + + i = 0; + } + } + + if (i) { + for (j = i; j < 4; j++) { + a4[j] = '\0'; + } + + for (j = 0; j < 4; j++) { + a4[j] = b64_lookup(a4[j]); + } + + a4_to_a3(a3,a4); + + for (j = 0; j < i - 1; j++) { + *out++ = a3[j]; + } + } + + return (out == (out_begin + decoded_length)); + } + + static int DecodedLength(const char *in, size_t in_length) { + int numEq = 0; + + const char *in_end = in + in_length; + while (*--in_end == '=') ++numEq; + + return ((6 * in_length) / 8) - numEq; + } + + static int DecodedLength(const std::string &in) { + int numEq = 0; + int n = in.size(); + + for (std::string::const_reverse_iterator it = in.rbegin(); *it == '='; ++it) { + ++numEq; + } + + return ((6 * n) / 8) - numEq; + } + + inline static int EncodedLength(size_t length) { + return (length + 2 - ((length + 2) % 3)) / 3 * 4; + } + + inline static int EncodedLength(const std::string &in) { + return EncodedLength(in.length()); + } + + inline static void StripPadding(std::string *in) { + while (!in->empty() && *(in->rbegin()) == '=') in->resize(in->size() - 1); + } + +private: + static inline void a3_to_a4(unsigned char * a4, unsigned char * a3) { + a4[0] = (a3[0] & 0xfc) >> 2; + a4[1] = ((a3[0] & 0x03) << 4) + ((a3[1] & 0xf0) >> 4); + a4[2] = ((a3[1] & 0x0f) << 2) + ((a3[2] & 0xc0) >> 6); + a4[3] = (a3[2] & 0x3f); + } + + static inline void a4_to_a3(unsigned char * a3, unsigned char * a4) { + a3[0] = (a4[0] << 2) + ((a4[1] & 0x30) >> 4); + a3[1] = ((a4[1] & 0xf) << 4) + ((a4[2] & 0x3c) >> 2); + a3[2] = ((a4[2] & 0x3) << 6) + a4[3]; + } + + static inline unsigned char b64_lookup(unsigned char c) { + if(c >='A' && c <='Z') return c - 'A'; + if(c >='a' && c <='z') return c - 71; + if(c >='0' && c <='9') return c + 4; + if(c == '+') return 62; + if(c == '/') return 63; + return 255; + } +}; + +#endif //EMSCRIPT_BASE64_H diff --git a/PrintWrapper/src/main/cpp/jni.cpp b/PrintWrapper/src/main/cpp/jni.cpp new file mode 100644 index 0000000..5c5b907 --- /dev/null +++ b/PrintWrapper/src/main/cpp/jni.cpp @@ -0,0 +1,140 @@ +#include "Internal.h" + +//Globals +JavaVM* g_JVM = NULL; + +//Forward References +jstring JNICALL JNI_getUtilsVersion(JNIEnv *JEnv, jclass JCls); +jstring JNICALL JNI_createBitmapZPL(JNIEnv *JEnv, jclass JCls, jobject bitmap); +jstring JNICALL JNI_createBitmapCPC(JNIEnv *JEnv, jclass JCls, jobject bitmap); + +/***************************************************************************************/ +/* Signature Java Type */ +/* Z boolean */ +/* B byte */ +/* C char */ +/* S short */ +/* I int */ +/* J long */ +/* F float */ +/* D double */ +/* L class */ +/* V void */ +/* [type array type */ +/* (Args) Return Type method type */ +/* */ +/* (Ljava/lang/String;)Ljava/lang/String; */ +/* ([java/lang/String;)V */ +/* */ +/***************************************************************************************/ +static JNINativeMethod sMethods[] = + { + /* name, signature, funcPtr */ + { "getUtilsVersion", "()Ljava/lang/String;", (void*)JNI_getUtilsVersion }, + { "createBitmapZPL", "(Landroid/graphics/Bitmap;)Ljava/lang/String;", (void*)JNI_createBitmapZPL }, + { "createBitmapCPC", "(Landroid/graphics/Bitmap;)Ljava/lang/String;", (void*)JNI_createBitmapCPC }, + + }; +/***************************************************************************************/ +JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) +{ + JNIEnv* JEnv = NULL; + jclass klass; + g_JVM = vm; + + //Get JVM Pointer + if (vm->GetEnv((void**)&JEnv, JNI_VERSION_1_6) != JNI_OK) + { + LOGE("GetEnv failed!"); + return -1; + } + + //Find the class to register the natives against + klass = JEnv->FindClass(ZPLHELPER_CLASS); + + if (klass == NULL) + { + LOGE("Unable to find class %s", ZPLHELPER_CLASS); + return -1; + } + + if (JEnv->RegisterNatives(klass, sMethods, SIZE(sMethods))) + { + LOGE("Register Natives Failed for class %s", ZPLHELPER_CLASS); + return -1; + } + + LOGI("**************************************************"); + LOGI("* Zebra Utils Initialized *"); + LOGI("* (c)2020 Thunderlight Software *"); + LOGI("**************************************************"); + LOGI("Version : %s",ENGINE_VERSION); + return JNI_VERSION_1_6; +} +/***************************************************************************************/ +jstring JNICALL JNI_getUtilsVersion(JNIEnv *JEnv, jclass JCls) +{ + return JEnv->NewStringUTF(ENGINE_VERSION); +} +/***************************************************************************************/ +jstring JNICALL JNI_createBitmapZPL(JNIEnv *JEnv, jclass JCls, jobject bitmap) +{ + AndroidBitmapInfo info; + int ret; + void *pixels; + char* retValue; + + //Get Bitmap Info + if ((ret = AndroidBitmap_getInfo(JEnv, bitmap, &info)) < 0) + { + LOGE("AndroidBitmap_getInfo() failed ! error=%d", ret); + return nullptr; + } + + if ((ret = AndroidBitmap_lockPixels(JEnv, bitmap, &pixels)) < 0) + { + LOGE("AndroidBitmap_lockPixels() failed ! error=%d", ret); + return nullptr; + } + + //Do Some Stuff Here + LOGI("Create ZPL Image"); + bool success = ZPLconvertImage(&info, pixels,&retValue); + + //Unlock Pixels and return result + AndroidBitmap_unlockPixels(JEnv, bitmap); + jstring result = success ? JEnv->NewStringUTF(retValue) : nullptr; + if (retValue != nullptr) free(retValue); + return result; +} +/***************************************************************************************/ +jstring JNICALL JNI_createBitmapCPC(JNIEnv *JEnv, jclass JCls, jobject bitmap) +{ + AndroidBitmapInfo info; + int ret; + void *pixels; + char* retValue; + + //Get Bitmap Info + if ((ret = AndroidBitmap_getInfo(JEnv, bitmap, &info)) < 0) + { + LOGE("AndroidBitmap_getInfo() failed ! error=%d", ret); + return nullptr; + } + + if ((ret = AndroidBitmap_lockPixels(JEnv, bitmap, &pixels)) < 0) + { + LOGE("AndroidBitmap_lockPixels() failed ! error=%d", ret); + return nullptr; + } + + //Do Some Stuff Here + LOGI("Create CPCL Image"); + bool success = CPCconvertImage(&info, pixels,&retValue); + + //Unlock Pixels and return result + AndroidBitmap_unlockPixels(JEnv, bitmap); + jstring result = success ? JEnv->NewStringUTF(retValue) : nullptr; + if (retValue != nullptr) free(retValue); + return result; +} \ No newline at end of file diff --git a/PrintWrapper/src/main/java/com/zebra/printwrapper/RasterizationHelper.java b/PrintWrapper/src/main/java/com/zebra/printwrapper/RasterizationHelper.java index dc6b211..e580a18 100644 --- a/PrintWrapper/src/main/java/com/zebra/printwrapper/RasterizationHelper.java +++ b/PrintWrapper/src/main/java/com/zebra/printwrapper/RasterizationHelper.java @@ -19,6 +19,10 @@ public class RasterizationHelper { private static String TAG = RasterizationHelper.class.getName(); + public static native String getUtilsVersion(); + public static native String createBitmapZPL(Bitmap bitmap); + public static native String createBitmapCPC(Bitmap bitmap); + public static Bitmap loadFromFile(String filename) { try {//from ww w.j a va 2 s.c om File f = new File(filename); @@ -90,7 +94,7 @@ public static String getCPCFromBitmap(Bitmap bitmap, int dpi, int iWidth, int iH Log.i(TAG, "Creating CPC"); printData.append("! 0 " + dpi + " " + dpi + " " + iWidth + " 1\r\n"); printData.append("EG " + iWidth + " " + iHeight + " 0 0 "); - printData.append(BitmapCPCLConverter.createBitmapCPC(bitmap)); + printData.append(RasterizationHelper.createBitmapCPC(bitmap)); printData.append("\r\n"); printData.append("PRINT\r\n"); Log.i(TAG, "CPCL Data: \n"+ printData); @@ -173,7 +177,7 @@ public static String getZPLFromBitmap(Bitmap bitmap, int iWidth, int iHeight, in StringBuilder printData = new StringBuilder(); // By default create ZPL Data //Create ZPL - String ZPLBitmap = BitmapZPLConverter.createBitmapZPL(bitmap); + String ZPLBitmap = RasterizationHelper.createBitmapZPL(bitmap); Log.i(TAG, "Creating ZPL"); printData.append("^XA"); if(variableLengthEnabled == true) diff --git a/gradle.properties b/gradle.properties index df7b01b..1779859 100644 --- a/gradle.properties +++ b/gradle.properties @@ -16,7 +16,7 @@ org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 # https://developer.android.com/topic/libraries/support-library/androidx-rn android.useAndroidX=true # Automatically convert third-party libraries to use AndroidX -#android.enableJetifier=true +android.enableJetifier=true # Enables namespacing of each library's R class so that its R class includes only the # resources declared in the library itself and none from the library's dependencies, diff --git a/jitpack.yml b/jitpack.yml index 4fba258..9fc55cb 100644 --- a/jitpack.yml +++ b/jitpack.yml @@ -1,3 +1,44 @@ # Configure the JDK version -jdk: - - openjdk17 +#jdk: +# - openjdk17 + +# Optional: Run pre-build tasks +#before_install: +# - yes | sdkmanager --licenses +# - yes | sdkmanager --install "ndk;28.0.12674087" +# - yes | sdkmanager --install "cmake;3.22.1" + +################################################################################## + +#jdk: +# - openjdk17 + +#android: +# components: +# - tools +# - platform-tools +# - build-tools-34.0.0 +# - android-34 +# +# licenses: +# - 'android-sdk-license-.+' +# - 'android-sdk-preview-license-.+' +# - 'google-gdk-license-.+' +# +#before_install: +# - yes | sdkmanager --licenses +# - yes | sdkmanager "cmake;3.22.1" +# - yes | sdkmanager "ndk;28.0.12674087" + +#install: +# - export ANDROID_NDK_HOME=$ANDROID_HOME/ndk/28.0.12674087 +# - export PATH=$PATH:$ANDROID_HOME/cmake/3.22.1/bin +# - chmod +x gradlew + +#script: +# - ./gradlew clean build + +################################################################################################# + +before_install: + - yes | sdkmanager "cmake;3.22.1" \ No newline at end of file