You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android PrintService打印作业文档质量极低,寻求技术帮助

Android PrintService 获取文档数据质量极低问题

我在使用Android PrintService时遇到技术问题:打印作业的文档数据质量极低,通过FileDescriptor获取的InputStream读取到的是低质量文件。已在网络上搜索相关解决方案但未找到有效信息,该问题已困扰我四天,恳请各位提供帮助。

public class CustomPrintService extends PrintService {

    private static final String TAG = "Praneet";
    private PrinterInfo mThermalPrinter;
    @Override
    public void onCreate() {
        super.onCreate();
        Log.e(TAG, "Custom Print Service created.");
        mThermalPrinter = new PrinterInfo.Builder(generatePrinterId("BT-582"),
                "Kebio Prints", PrinterInfo.STATUS_IDLE).build();
    }

    @Override
    protected PrinterDiscoverySession onCreatePrinterDiscoverySession() {
        return new CustomPrinterDiscoverySession();
    }

    @Override
    protected void onRequestCancelPrintJob(PrintJob printJob) {
        Log.e(TAG, "Canceling print job: " + printJob.getId());
        if (printJob.isStarted()) {
            printJob.cancel();
        }
    }

    @Override
    protected void onPrintJobQueued(PrintJob printJob) {
        if (printJob.isQueued()) {
            Log.e(TAG, "Processing queued print job: " + printJob.getId());
            processPrintJob(printJob);
        }
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.e(TAG, "Custom Print Service destroyed.");
    }

    private void processPrintJob(PrintJob printJob) {
        PrintDocument document = printJob.getDocument();
        if (document != null) {
            try (ParcelFileDescriptor descriptor = document.getData();
                 InputStream inputStream = new ParcelFileDescriptor.AutoCloseInputStream(descriptor)) {

                // Define the output PDF file path
                File outputFile = new File(getExternalFilesDir(null), "printed_document.pdf");
                try (OutputStream outputStream = new FileOutputStream(outputFile)) {

                    // Copy content from input stream to output stream (PDF generation)
                    byte[] buffer = new byte[5*1024];
                    int bytesRead;
                    while ((bytesRead = inputStream.read(buffer)) != -1) {
                        outputStream.write(buffer, 0, bytesRead);
                    }

                    Log.d("Praneet", "PDF generated at: " + outputFile.getAbsolutePath());
                    printJob.complete(); // Mark job as completed
                } catch (Exception e) {
                    Log.e("Praneet", "Error writing PDF: " + e.getMessage());
                    printJob.fail("Failed to generate PDF");
                }
            } catch (Exception e) {
                Log.e("Praneet", "Error reading print document: " + e.getMessage());
                printJob.fail("Failed to process document");
            }
        } else {
            Log.e("Praneet", "No document available");
            printJob.fail("No document to print");
        }
    }
    // Custom printer discovery session
    private class CustomPrinterDiscoverySession extends PrinterDiscoverySession {

        private final List<PrinterInfo> discoveredPrinters = new ArrayList<>();

        @Override
        public void onStartPrinterDiscovery(List<PrinterId> priorityList) {
            Log.e(TAG, "Starting printer discovery...");

            // Simulate discovering a single printer
            PrintAttributes.MediaSize customSize = new PrintAttributes.MediaSize(mThermalPrinter.getId().getLocalId(),

                    "58mm thermal Paper", 58, 100);


            PrinterCapabilitiesInfo capabilities =
                    new PrinterCapabilitiesInfo.Builder(mThermalPrinter.getId())
                            .addMediaSize(customSize, true)

                            .addResolution(new PrintAttributes.Resolution(mThermalPrinter.getId().getLocalId(), "Default", 1000, 1000), true)
                            .setColorModes(PrintAttributes.COLOR_MODE_MONOCHROME, PrintAttributes.COLOR_MODE_MONOCHROME)
                            .build();

            PrinterInfo printerInfo = new PrinterInfo.Builder(mThermalPrinter.getId(), "Kebio Prints", PrinterInfo.STATUS_IDLE)
                    .setCapabilities(capabilities)
                    .build();

            discoveredPrinters.add(printerInfo);
            addPrinters(discoveredPrinters);
            Log.e(TAG, "Printer discovered: " + printerInfo.getName());
        }

        @Override
        public void onStopPrinterDiscovery() {
            Log.e(TAG, "Stopping printer discovery...");
        }

        @Override
        public void onValidatePrinters(List<PrinterId> printerIds) {
            Log.e(TAG, "Validating printers...");
        }

        @Override
        public void onStartPrinterStateTracking(PrinterId printerId) {
            Log.e(TAG, "Starting printer state tracking for: " + printerId.getLocalId());
        }

        @Override
        public void onStopPrinterStateTracking(PrinterId printerId) {
            Log.e(TAG, "Stopping printer state tracking for: " + printerId.getLocalId());
        }

        @Override
        public void onDestroy() {
            Log.e(TAG, "Destroying discovery session...");
        }
    }
}

问题根源

Android PrintService会根据打印机能力参数对原始文档做适配处理,代码里的两个关键错误导致了文档降质:

  1. 媒体尺寸单位错误:PrintAttributes.MediaSize的尺寸参数默认单位是千分之一英寸,你直接传入58(mm),实际58mm约等于2283千分之一英寸,错误的尺寸会让系统严重压缩文档。
  2. 分辨率参数不匹配:声明的1000x1000分辨率和多数58mm热敏打印机的实际203DPI不符,系统会因参数不兼容自动降质。

修复方案

1. 修正媒体尺寸

将58mm热敏纸的尺寸换算为正确的千分之一英寸单位:

// 58mm宽度≈2283千分之一英寸,高度设为10000支持连续打印
PrintAttributes.MediaSize customSize = new PrintAttributes.MediaSize(
        new PrintAttributes.MediaSizeName("THERMAL_58MM", "58mm Thermal Paper"),
        2283, 10000);

2. 设置真实分辨率

使用热敏打印机常见的203DPI分辨率:

.addResolution(new PrintAttributes.Resolution("RES_203DPI", "203 DPI", 203, 203), true)

3. 验证文档属性

在processPrintJob中添加日志,确认文档的实际属性是否符合预期:

PrintAttributes docAttrs = printJob.getAttributes();
Log.d(TAG, "Doc resolution: " + docAttrs.getResolution());
Log.d(TAG, "Doc media size: " + docAttrs.getMediaSize());

如果日志显示的尺寸/分辨率和设置的不符,说明系统仍在调整文档,需要进一步检查打印机能力声明。

4. 优化流复制逻辑

可以使用Apache Commons IO的IOUtils.copy简化流复制,避免手动缓冲可能的问题:

// 需要添加依赖:implementation 'commons-io:commons-io:2.15.1'
IOUtils.copy(inputStream, outputStream);

额外测试建议

  • 直接打印到实际打印机,跳过PDF保存步骤,确认是否是PDF转换导致的质量损失。
  • 过滤系统日志中的PrintService标签,查看是否有文档缩放、质量调整的相关提示。

内容的提问来源于stack exchange,提问作者praneetk2

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 20:49:51