Ubuntu18.04 CUPS安装与Andoird系统各种打印机PDF打印

一、ubuntu安装cups打印

在Ubuntu上安装CUPS(打印系统)的步骤如下:

1、打开终端。
2、更新软件包列表:

sudo apt update

3、安装CUPS:

sudo apt install cups

4、安装foomatic-filters与ghostscript:
sudo apt-get install foomatic-filters
sudo apt-get install ghostscript

sudo apt-get install cups --reinstall

sudo /etc/init.d/cups restart
5、安装完成后,配置并启动CUPS服务:
  1. 
    sudo service cups start
    
    
  2. 你可以通过以下命令检查CUPS服务的状态:通过浏览器访问CUPS的网页界面,在地址栏输入:http://localhost:631

6、以上步骤会在Ubuntu系统上安装CUPS,并启动打印服务。如果你的系统中还没有安装Web浏览器,你可以在安装CUPS之后,通过命令行使用lpinfolpadmin工具来配置打印机。
7、安装遇到的问题

Failed to connect to bus: No such file or directory

sudo /etc/init.d/dbus start

Failed to start cups.service: Launch helper exited with unknown return code 1

sudo /etc/init.d/cups restart
8、打印应用与测试:

添加打印机:

lpadmin -p epson-xxx -E -v "ipp://11.22.33.44/ipp/print" -m everywhere
lpadmin -p EPSON-L3251 -E -v ipp://11.22.33.44/ipp/print -m everywhere
lpadmin -p HP_xxx -E -v ipp://11.22.33.44/ipp/print -m everywhere

9、设置默认打印队列
如果你有一个或多个打印队列可用,但是没有设置默认,你可以使用 lpoptions 命令来设置默认打印队列。假设你有一个名为 printer1 的打印队列,你可以这样设置它为默认:

lpoptions -d epson-xxx
lpoptions -d HP_xxx
10、查看Epson打印机3250系列ppd驱动文件状态及位置
 lpinfo -m | grep 3250
foomatic-db-compressed-ppds:0/ppd/foomatic-ppd/Epson-ActionPrinter_3250-ap3250.ppd Epson ActionPrinter 3250 Foomatic/ap3250 (recommended)

~$ find / -name "Epson*" 2>/dev/null
/etc/cups/ppd/Epson_L3251_Printer.ppd
/etc/cups/ppd/Epson_L3251_Printer.ppd.O

11、开始打印:
lp xxx.pdf
lp -o media=A4 -o resolution=600dpi xxx.pdf
12、删除打印机:
lpadmin -x myprinter
13、打印机队列状态
~$ lpstat -p

二、Andoird系统各种打印机PDF打印(插件调用方式)

建议使用各打印机厂商提供的打印机插件apk程序安装,然后使用插件调用方式调用打印。

如1、Hp的com.hp.android.printservice_xxx.apk;

2、Epson的EpsoniPrint.apk;

3、Canon的Canon_PR_Biz.apk;

4、Sansung的com.sec.print.mobileprint_v4.xxx.apk等。

插件调用代码:

/**
 * pdf打印
 */
private fun sharePdf(pdfPath: String){
    val pdfFile = File(pdfPath)
    if (pdfFile.exists()) {
        val shareIntent = Intent(Intent.ACTION_SEND)
        shareIntent.setType("application/pdf")
        val pdfUri: Uri = Uri.fromFile(pdfFile)
        shareIntent.putExtra(Intent.EXTRA_STREAM, pdfUri) 
        startActivity(Intent.createChooser(shareIntent, "Pdf Report"))
    }
    else {
        Toast.makeText(this, "PDF file not found", Toast.LENGTH_SHORT).show()
    }
}

三、Android ndk交叉编译CUPS

        过程较为复杂,依赖较多,集成较为麻烦,暂不推荐。

1、下载NDK(NDK 下载  |  Android NDK  |  Android Developers
2、解压、安装NDK、配置交叉编译环境
android-ndk-r21e$ ./build/tools/make_standalone_toolchain.py --arch arm --api 24 --install-dir /home/toolchain

# vim ~/.bash_profile
export NDK=/home/xxx/tools/android-ndk-r21e
export PATH=${NDK}:${NDK}/../toolchain/bin:${PATH}
export NDK_PROJECT_PATH=${NDK}
export CXX=armv7a-linux-androideabi24-clang++
export CC=armv7a-linux-androideabi24-clang

3、下载cups、cups-filter及其依赖包

GitHub - jianglei12138/cups: cups for android (UNIX通用打印系统)

4、解压、交叉编译cups2.1.3

        4.1 替换local头文件及拷贝so库(GitHub - jianglei12138/liblocale: locale for android

下载 lcoale 支持库和库 ,然后将标头 locale.h 放在 toolchain-folder/sysroot/usr/include(override) 下,并将共享库 liblocale.so 放在 toolchain-folder/sysroot/usr/lib 下

        4.2 配置cups

./configure --host=arm-linux-androideabi --disable-dbus --prefix=/system/usr/root --with-cups-user=system --with-cups-group=system --with-system-groups=root
5、编译

#需要重新编译avahi-master,并拷贝头文件和库,以及local头文件和库,否则会出现缺头文件和库符号错误

make

make install
6、编译2.4.10
./configure --host=arm-linux-androideabi --disable-dbus --without-tls --disable-pam --prefix=/system/usr/root --with-cups-user=system --with-cups-group=system --with-system-groups=root

#打入补丁
patch -p1 < ../cups-2.4.10-android-port.patch

编译
make

make install DESTDIR=/home/xxxx/xxx


补丁:commit cf2c2e6e2140e04cbd99f33406bc5774fafa169d
Author: jianglei <jianglei@bigo.sg>
Date:   Wed Jun 19 16:32:19 2024 +0800

    port to android system

diff --git a/cups/language.c b/cups/language.c
index 6d9474e..bac54e3 100644
--- a/cups/language.c
+++ b/cups/language.c
@@ -439,6 +439,237 @@ cupsLangFree(cups_lang_t *lang)		/* I - Language to free */
 }
 
 
+/* Specification.  */
+#include <langinfo.h>
+#if REPLACE_NL_LANGINFO
+/* Override nl_langinfo with support for added nl_item values.  */
+# include <locale.h>
+# include <string.h>
+# undef nl_langinfo
+char *
+rpl_nl_langinfo (nl_item item)
+{
+  switch (item)
+    {
+# if GNULIB_defined_CODESET
+    case CODESET:
+      {
+        const char *locale;
+        static char buf[2 + 10 + 1];
+        locale = setlocale (LC_CTYPE, NULL);
+        if (locale != NULL && locale[0] != '\0')
+          {
+            /* If the locale name contains an encoding after the dot, return
+               it.  */
+            const char *dot = strchr (locale, '.');
+            if (dot != NULL)
+              {
+                const char *modifier;
+                dot++;
+                /* Look for the possible @... trailer and remove it, if any.  */
+                modifier = strchr (dot, '@');
+                if (modifier == NULL)
+                  return dot;
+                if (modifier - dot < sizeof (buf))
+                  {
+                    memcpy (buf, dot, modifier - dot);
+                    buf [modifier - dot] = '\0';
+                    return buf;
+                  }
+              }
+          }
+        return "";
+      }
+# endif
+# if GNULIB_defined_T_FMT_AMPM
+    case T_FMT_AMPM:
+      return "%I:%M:%S %p";
+# endif
+# if GNULIB_defined_ERA
+    case ERA:
+      /* The format is not standardized.  In glibc it is a sequence of strings
+         of the form "direction:offset:start_date:end_date:era_name:era_format"
+         with an empty string at the end.  */
+      return "";
+    case ERA_D_FMT:
+      /* The %Ex conversion in strftime behaves like %x if the locale does not
+         have an alternative time format.  */
+      item = D_FMT;
+      break;
+    case ERA_D_T_FMT:
+      /* The %Ec conversion in strftime behaves like %c if the locale does not
+         have an alternative time format.  */
+      item = D_T_FMT;
+      break;
+    case ERA_T_FMT:
+      /* The %EX conversion in strftime behaves like %X if the locale does not
+         have an alternative time format.  */
+      item = T_FMT;
+      break;
+    case ALT_DIGITS:
+      /* The format is not standardized.  In glibc it is a sequence of 10
+         strings, appended in memory.  */
+      return "\0\0\0\0\0\0\0\0\0\0";
+# endif
+# if GNULIB_defined_YESEXPR || !FUNC_NL_LANGINFO_YESEXPR_WORKS
+    case YESEXPR:
+      return "^[yY]";
+    case NOEXPR:
+      return "^[nN]";
+# endif
+    default:
+      break;
+    }
+  return nl_langinfo (item);
+}
+#else
+/* Provide nl_langinfo from scratch.  */
+# if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
+/* Native Windows platforms.  */
+#  define WIN32_LEAN_AND_MEAN  /* avoid including junk */
+#  include <windows.h>
+#  include <stdio.h>
+# else
+/* An old Unix platform without locales, such as Linux libc5 or BeOS.  */
+# endif
+# include <locale.h>
+char *
+nl_langinfo (nl_item item)
+{
+  switch (item)
+    {
+    /* nl_langinfo items of the LC_CTYPE category */
+    case CODESET:
+# if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
+      {
+        static char buf[2 + 10 + 1];
+        /* The Windows API has a function returning the locale's codepage as
+           a number.  */
+        sprintf (buf, "CP%u", GetACP ());
+        return buf;
+      }
+# elif defined __BEOS__
+      return "UTF-8";
+# else
+      return "ISO-8859-1";
+# endif
+    /* nl_langinfo items of the LC_NUMERIC category */
+    case RADIXCHAR:
+      return localeconv () ->decimal_point;
+    case THOUSEP:
+      return localeconv () ->thousands_sep;
+    /* nl_langinfo items of the LC_TIME category.
+       TODO: Really use the locale.  */
+    case D_T_FMT:
+    case ERA_D_T_FMT:
+      return "%a %b %e %H:%M:%S %Y";
+    case D_FMT:
+    case ERA_D_FMT:
+      return "%m/%d/%y";
+    case T_FMT:
+    case ERA_T_FMT:
+      return "%H:%M:%S";
+    case T_FMT_AMPM:
+      return "%I:%M:%S %p";
+    case AM_STR:
+      return "AM";
+    case PM_STR:
+      return "PM";
+    case DAY_1:
+      return "Sunday";
+    case DAY_2:
+      return "Monday";
+    case DAY_3:
+      return "Tuesday";
+    case DAY_4:
+      return "Wednesday";
+    case DAY_5:
+      return "Thursday";
+    case DAY_6:
+      return "Friday";
+    case DAY_7:
+      return "Saturday";
+    case ABDAY_1:
+      return "Sun";
+    case ABDAY_2:
+      return "Mon";
+    case ABDAY_3:
+      return "Tue";
+    case ABDAY_4:
+      return "Wed";
+    case ABDAY_5:
+      return "Thu";
+    case ABDAY_6:
+      return "Fri";
+    case ABDAY_7:
+      return "Sat";
+    case MON_1:
+      return "January";
+    case MON_2:
+      return "February";
+    case MON_3:
+      return "March";
+    case MON_4:
+      return "April";
+    case MON_5:
+      return "May";
+    case MON_6:
+      return "June";
+    case MON_7:
+      return "July";
+    case MON_8:
+      return "August";
+    case MON_9:
+      return "September";
+    case MON_10:
+      return "October";
+    case MON_11:
+      return "November";
+    case MON_12:
+      return "December";
+    case ABMON_1:
+      return "Jan";
+    case ABMON_2:
+      return "Feb";
+    case ABMON_3:
+      return "Mar";
+    case ABMON_4:
+      return "Apr";
+    case ABMON_5:
+      return "May";
+    case ABMON_6:
+      return "Jun";
+    case ABMON_7:
+      return "Jul";
+    case ABMON_8:
+      return "Aug";
+    case ABMON_9:
+      return "Sep";
+    case ABMON_10:
+      return "Oct";
+    case ABMON_11:
+      return "Nov";
+    case ABMON_12:
+      return "Dec";
+    case ERA:
+      return "";
+    case ALT_DIGITS:
+      return "\0\0\0\0\0\0\0\0\0\0";
+    /* nl_langinfo items of the LC_MONETARY category
+       TODO: Really use the locale. */
+    case CRNCYSTR:
+      return "-";
+    /* nl_langinfo items of the LC_MESSAGES category
+       TODO: Really use the locale. */
+    case YESEXPR:
+      return "^[yY]";
+    case NOEXPR:
+      return "^[nN]";
+    default:
+      return "";
+    }
+}
+#endif
 /*
  * 'cupsLangGet()' - Get a language.
  */
diff --git a/cups/thread.c b/cups/thread.c
index 066f8e2..af6be86 100644
--- a/cups/thread.c
+++ b/cups/thread.c
@@ -151,11 +151,11 @@ _cupsRWUnlock(_cups_rwlock_t *rwlock)	/* I - Reader/writer lock */
  * '_cupsThreadCancel()' - Cancel (kill) a thread.
  */
 
-void
-_cupsThreadCancel(_cups_thread_t thread)/* I - Thread ID */
-{
-  pthread_cancel(thread);
-}
+// void
+// _cupsThreadCancel(_cups_thread_t thread)/* I - Thread ID */
+// {
+//   pthread_cancel(thread);
+// }
 
 
 /*
diff --git a/scheduler/auth.c b/scheduler/auth.c
index d0430b4..c80fc78 100644
--- a/scheduler/auth.c
+++ b/scheduler/auth.c
@@ -60,6 +60,50 @@ typedef struct sockpeercred cupsd_ucred_t;
 #  include <snapd-glib/snapd-glib.h>
 #endif /* HAVE_LIBSNAPDGLIB */
 
+static void android_setup_pwd(struct passwd* pw) {
+       char const* result = "@TERMUX_PREFIX@/bin/login";
+       if (result == NULL || access(result, /*X_OK*/1) == -1) {
+               pw->pw_shell = "@TERMUX_PREFIX@/bin/bash";
+       } else {
+               pw->pw_shell = (char*) result;
+       }
+       pw->pw_dir = "/tmp/";
+       pw->pw_passwd = "*";
+#ifdef __LP64__
+       pw->pw_gecos = ""; /* Avoid NULL field. */
+#endif
+}
+
+static struct passwd* android_polyfill_getpwuid(uid_t t) {
+       struct passwd* pw = getpwuid(t);
+       if (pw == NULL) return NULL;
+       android_setup_pwd(pw);
+       return pw;
+}
+
+static struct passwd* android_polyfill_getpwnam(const char* name) {
+       struct passwd* pw = getpwnam(name);
+       if (pw == NULL) return NULL;
+       android_setup_pwd(pw);
+       return pw;
+}
+
+static int android_polyfill_getpwuid_r(uid_t uid,
+                                       struct passwd *pwd,
+                                       char *buffer,
+                                       size_t bufsize,
+                                       struct passwd **result) {
+       int ret = getpwuid_r(uid, pwd, buffer, bufsize, result);
+       if (ret != 0) return ret;
+       android_setup_pwd(pwd);
+       return 0;
+}
+
+#define getpwnam android_polyfill_getpwnam
+#define getpwuid android_polyfill_getpwuid
+#define getpwuid_r android_polyfill_getpwuid_r
+static void endpwent(void) { /* Do nothing. */ }
+
 
 /*
  * Local functions...
@@ -686,7 +730,7 @@ cupsdAuthorize(cupsd_client_t *con)	/* I - Client connection */
       * client...
       */
 
-      pass = crypt(password, pw->pw_passwd);
+      pass = "*"; // crypt(password, pw->pw_passwd);
 
       if (!pass || strcmp(pw->pw_passwd, pass))
       {
@@ -1133,136 +1177,7 @@ cupsdCheckGroup(
     struct passwd *user,		/* I - System user info */
     const char    *groupname)		/* I - Group name */
 {
-  int		i;			/* Looping var */
-  struct group	*group;			/* Group info */
-  gid_t		groupid;		/* ID of named group */
-#ifdef HAVE_MBR_UID_TO_UUID
-  uuid_t	useruuid,		/* UUID for username */
-		groupuuid;		/* UUID for groupname */
-  int		is_member;		/* True if user is a member of group */
-#endif /* HAVE_MBR_UID_TO_UUID */
-
-
-  cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdCheckGroup(username=\"%s\", user=%p, groupname=\"%s\")", username, (void *)user, groupname);
-
- /*
-  * Validate input...
-  */
-
-  if (!username || !groupname)
-    return (0);
-
- /*
-  * Check to see if the user is a member of the named group...
-  */
-
-  group = getgrnam(groupname);
-  endgrent();
-
-  if (group != NULL)
-  {
-   /*
-    * Group exists, check it...
-    */
-
-    groupid = group->gr_gid;
-
-    for (i = 0; group->gr_mem[i]; i ++)
-    {
-     /*
-      * User appears in the group membership...
-      */
-
-      if (!_cups_strcasecmp(username, group->gr_mem[i]))
-	return (1);
-    }
-
-#ifdef HAVE_GETGROUPLIST
-   /*
-    * If the user isn't in the group membership list, try the results from
-    * getgrouplist() which is supposed to return the full list of groups a user
-    * belongs to...
-    */
-
-    if (user)
-    {
-      int	ngroups;		/* Number of groups */
-#  ifdef __APPLE__
-      int	groups[2048];		/* Groups that user belongs to */
-#  else
-      gid_t	groups[2048];		/* Groups that user belongs to */
-#  endif /* __APPLE__ */
-
-      ngroups = (int)(sizeof(groups) / sizeof(groups[0]));
-#  ifdef __APPLE__
-      getgrouplist(username, (int)user->pw_gid, groups, &ngroups);
-#  else
-      getgrouplist(username, user->pw_gid, groups, &ngroups);
-#endif /* __APPLE__ */
-
-      for (i = 0; i < ngroups; i ++)
-        if ((int)groupid == (int)groups[i])
-	  return (1);
-    }
-#endif /* HAVE_GETGROUPLIST */
-  }
-  else
-    groupid = (gid_t)-1;
-
- /*
-  * Group doesn't exist or user not in group list, check the group ID
-  * against the user's group ID...
-  */
-
-  if (user && groupid == user->pw_gid)
     return (1);
-
-#ifdef HAVE_MBR_UID_TO_UUID
- /*
-  * Check group membership through macOS membership API...
-  */
-
-  if (user && !mbr_uid_to_uuid(user->pw_uid, useruuid))
-  {
-    if (groupid != (gid_t)-1)
-    {
-     /*
-      * Map group name to UUID and check membership...
-      */
-
-      if (!mbr_gid_to_uuid(groupid, groupuuid))
-        if (!mbr_check_membership(useruuid, groupuuid, &is_member))
-	  if (is_member)
-	    return (1);
-    }
-    else if (groupname[0] == '#')
-    {
-     /*
-      * Use UUID directly and check for equality (user UUID) and
-      * membership (group UUID)...
-      */
-
-      if (!uuid_parse((char *)groupname + 1, groupuuid))
-      {
-        if (!uuid_compare(useruuid, groupuuid))
-	  return (1);
-	else if (!mbr_check_membership(useruuid, groupuuid, &is_member))
-	  if (is_member)
-	    return (1);
-      }
-
-      return (0);
-    }
-  }
-  else if (groupname[0] == '#')
-    return (0);
-#endif /* HAVE_MBR_UID_TO_UUID */
-
- /*
-  * If we get this far, then the user isn't part of the named group...
-  */
-
-  return (0);
 }
 
 
diff --git a/scheduler/conf.c b/scheduler/conf.c
index 0d4bb6a..c791fd9 100644
--- a/scheduler/conf.c
+++ b/scheduler/conf.c
@@ -516,6 +516,8 @@ cupsdFreeAliases(cups_array_t *aliases)	/* I - Array of aliases */
   cupsArrayDelete(aliases);
 }
 
+static void endpwent(void) { /* Do nothing. */ }
+static void endgrent(void) { /* Do nothing. */ }
 
 /*
  * 'cupsdReadConfiguration()' - Read the cupsd.conf file.
diff --git a/scheduler/ipp.c b/scheduler/ipp.c
index 37623c5..762636f 100644
--- a/scheduler/ipp.c
+++ b/scheduler/ipp.c
@@ -29,6 +29,9 @@ extern int mbr_check_membership_by_id(uuid_t user, gid_t group, int* ismember);
 #endif /* __APPLE__ */
 
 
+static void endpwent(void) { /* Do nothing. */ }
+static void endgrent(void) { /* Do nothing. */ }
+
 /*
  * Local functions...
  */
diff --git a/scheduler/policy.c b/scheduler/policy.c
index 884e499..ab8b958 100644
--- a/scheduler/policy.c
+++ b/scheduler/policy.c
@@ -20,6 +20,8 @@
  * Local functions...
  */
 
+static void endpwent(void) { /* Do nothing. */ }
+static void endgrent(void) { /* Do nothing. */ }
 static int	compare_ops(cupsd_location_t *a, cupsd_location_t *b);
 static int	compare_policies(cupsd_policy_t *a, cupsd_policy_t *b);
 static void	free_policy(cupsd_policy_t *p);
7、编译过程错误:
Making all in cups...
Making all in filter...
Linking commandtops...
../cups/libcups.so: error: undefined reference to 'nl_langinfo'
clang90: error: linker command failed with exit code 1 (use -v to see invocation)
make[1]: *** [Makefile:254: commandtops] Error 1
make: *** [Makefile:40: all] Error 1

https://android.googlesource.com/toolchain/sed/+/refs/heads/ndk-r14-release/lib/nl_langinfo.c

将上述缺少的实现拷贝到language.c重新编译即可。 

Compiling sysman.c...
Linking cupsd...
auth.c:655: error: undefined reference to 'endpwent'
auth.c:1723: error: undefined reference to 'endpwent'
ipp.c:10875: error: undefined reference to 'endpwent'
ipp.c:3744: error: undefined reference to 'endpwent'
clang90: error: linker command failed with exit code 1 (use -v to see invocation)
make[1]: *** [Makefile:382: cupsd] Error 1
make: *** [Makefile:40: all] Error 1

增加头文件包含。 

8、部署
  1. 拷贝etc目录下内容到系统/system/etc/目录,拷贝system/usr/root目录下内容到系统/system/usr/root/目录,拷贝usr/share/目录下内容到系统/usr/share/目录,拷贝liblocal.so目录下内容到系统/system/lib/目录。
9、运行
#cupsd -f

运行错误 

 解决


chmod 777 /data/local/tmp

netstat -tulnp | grep 631
10、查看服务状态

        安装一个UC浏览器,输入http://localhost:631回车。

11、修改部署配置
busybox vi /system/usr/root/etc/cups/cupsd.conf

# Restrict access to the server...
<Location />
  Order allow,deny
  Allow all
</Location>

# Restrict access to the admin pages...
<Location /admin>
  AuthType Default
  Require user @SYSTEM
  Order allow,deny
  Allow all
</Location>

# Restrict access to configuration files...
<Location /admin/conf>
  AuthType Default
  Require user @SYSTEM
  Order allow,deny
  Allow all
</Location>

# Restrict access to log files...
<Location /admin/log>
  AuthType Default
  Require user @SYSTEM
  Order allow,deny
  Allow all
</Location>

拷贝依赖库文件:

chmod 777 /system/usr/root/var/ -R

1      cp lib/libqpdf.so      /system/lib/
2      cp lib/libcupsfilters.so      /system/lib/
3      cp lib/liblcms2.so      /system/lib/
4      cp lib/libpng16.so   /system/lib/
5      cp lib/libpoppler-cpp.so   /system/lib/
6      cp lib/libxml2.so    /system/lib/
7      cp lib/libpoppler.so     /system/lib/
8      cp lib/libiconv.so      /system/lib/
9      cp lib/libopenjp2.so      /system/lib/

启动服务:

kill cups-id

cupsd -f &

四、部署过程及打印

1、打印测试
-- 添加打印机

lpadmin -p HP_M104W -E -v ipp://11.22.33.44/ipp/print -m everywhere
lpadmin -p EPSON_L3251 -E -v ipp://11.22.33.44/ipp/print -m everywhere

-- 查看打印机状态

lpstat -p

-- 设置默认打印机

lpoptions -d EPSON_L3251

-- 执行打印

:/system/usr/root/bin # ./lp /sdcard/public/xxx.pdf
request id is EPSON_L3251-3 (1 file(s))


-- 设置默认打印机

lpoptions -d HP_M104W

-- 执行打印

lp /sdcard/public/xxx.pdf

-- 日志位置

/system/usr/root/var/log/cups/error_log

* 问题:./lp: Unsupported document-format "application/pdf".
* 问题: File \"/system/usr/root/lib/cups/backend/ipp\" has insecure permissions (0100771/uid=0/gid=0).

-- 权限设置

chmod 755 /system/usr/root/* -R


* 问题:Job 7] Backend ipp returned status -6 (crashed)

-5087-5087  libc                    pid-5087                             A  CANNOT LINK EXECUTABLE "ipp://11.22.33.44/ipp/print": library "libcups.so.2" not found
5087-5087  libc                    pid-5087                             A  Fatal signal 6 (SIGABRT), code -6 in tid 5087 (ipp)

-- 设置SO库、工具运行时环境变量

export LD_LIBRARY_PATH=/system/usr/root/lib
export PATH=/system/usr/root/bin:/system/usr/root/sbin:$PATH

* 问题:PPD creation failed: No IPP attributes.

-- 判断是否支持ipp

ipptool -tv ipp://11.22.33.44:631/ipp/print get-printer-attributes.test | grep -E "ipp-versions-supported|document-format-supported|get-printer-attributes"

--网页服务端Administration

用户名:root
密码:*

-- 嗅探所有打印机

/system/usr/root//lib/cups/backend/snmp
2、开机启动:
# init and start cupsd services
chmod 777 /data/local/tmp -R
chmod 777 /system/usr/root -R

export PATH=/system/usr/root/sbin:/system/usr/root/bin:$PATH

cupsd -f &

五、打印情况说明

1、此时只是安装了CUPS打印服务,对于PDF、png、jpeg等格式的文档和图片还是不能打印的。

2、需要交叉编译部署cups-filter解析转换文档或者图片格式后才能打印,参见另外的文章:

Android系统Cupsfilter交叉编译-优快云博客

六、参考资料

CUPS - ArchWiki

GitHub - apple/cups: Apple CUPS Sources

使用 CUPS 命令行实用程序设置和管理打印机 - Oracle Solaris 管理:常见任务

Debian -- Details of package cups-filters in trixie

Debian -- Details of source package cups-filters in trixie

GitHub - jianglei12138/cups: cups for android (UNIX通用打印系统)

https://android.googlesource.com/toolchain/sed/+/refs/heads/ndk-r14-release/lib/nl_langinfo.c

特别感谢上述开源网站和作者的帮助,致敬他们热情、友好、无私的精神和品质,相信这些都是社会能够快速进步的源泉和力量。 

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值