问题记录- 国产操作系统适配问题记录

Posted One To One

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了问题记录- 国产操作系统适配问题记录相关的知识,希望对你有一定的参考价值。

一、起因

 由于国产化系统逐步的推广应用,需要将在window系统中实现的功能;迁移到国产系统(UOS(统信OS)、麒麟操作系统等)中运行。

 在windows环境中主要采用Framework4.0开发的后台运行程序。主体思路采用将Windows程序功能迁移成Linux系统后台服务运行。

 特记录在适配过程中相关问题记录

二、问题记录

 1、System.Draw.Common包使用问题:

  由于后台服务需要生成pdf报告功能;需要用到gdi相关类型:如Font、Pen、Image、Bitmap等类型;在跨平台的处理中微软提供了:System.Draw.Common包在跨平台中使用。

  注意点:

  a)System.Draw.Common在linux环境中依赖gdip包;需要在环境中安装gdip包:

//安装libgdiplus:
apt-get install -y libgdiplus

  b)在.NET6以后System.Draw.Common被归为 Windows 特定的库。 在为非 Windows 操作系统编译时,平台分析器会在编译时发出警告;运行时会出现以下异常:

System.TypeInitializationException : The type initializer for \'Gdip\' threw an exception.
      ---- System.PlatformNotSupportedException : System.Drawing.Common is not supported on non-Windows platforms. See https://aka.ms/systemdrawingnonwindows for more information.

  更改原因:

由于 System.Drawing.Common 被设计为 Windows 技术的精简包装器,因此其跨平台实现欠佳。

libgdiplus 是本机端 System.Drawing.Common 跨平台实现的主要提供程序。 libgdiplus 实际上是对 System.Drawing.Common 所依赖的 Windows 部分的重新实现。 该实现使 libgdiplus 成为一个重要的组件。 它大约有 30,000 行 C 代码,大部分未经测试,而且缺少很多功能。 libgdiplus 还具有许多用于图像处理和文本呈现的外部依赖项,例如 cairopango 和其他本机库。 这些依赖项使得维护和交付组件更具挑战性。 自从包含 Mono 跨平台实现以来,我们已将许多从未得到修复的问题重定向到 libgdiplus。 相比之下,我们采用的其他外部依赖项,例如 icu 或 openssl,都是高质量的库。 使 libgdiplus 的功能集和质量与 .NET 堆栈的其余部分相媲美是不可行的。

通过对 NuGet 包的分析,我们观察到 System.Drawing.Common 主要用于跨平台的图像处理,例如 QR 代码生成器和文本呈现。 由于我们的跨平台图形支持不完整,我们还没有注意到大量的图形使用。 System.Drawing.Common 在非 Windows 环境中的使用通常得到 SkiaSharp 和 ImageSharp 的良好支持。

System.Drawing.Common 将仅在 Windows 窗体和 GDI+ 的上下文中继续演变。 

   解决办法:可通过将 runtimeconfig.json 文件中的 System.Drawing.EnableUnixSupportSystem.Drawing.EnableUnixSupport设置为 true 来启用对 .NET 6 中非 Windows 平台的支持


   "configProperties": 
      "System.Drawing.EnableUnixSupport": true
   

    可以在项目中添加:runtimeconfig.template.json 设置以上内容;编译时会自动添加到对于配置文件中。   

 2、打印机信息获取:

  在国产系统中打印机管理主要使用CUPS管理打印机:

  a)安装CUPS:(如果未安装改服务)

sudo apt-get update && sudo apt-get install cups cups-client lpr

  b) 获取打印机列表:安装后可以使用以下命令获取打印机列表

//输出打印机信息
lpstat -p
//输出信息:
打印机 HP-Color-LaserJet-MFP-M281fdw 目前空闲。从 2022年03月15日 星期二 17时49分10秒 开始启用
打印机 PDF 目前空闲。从 2022年03月17日 星期四 19时09分47秒 开始启用

  c)获取打印机基本信息:如纸张信息、纸张来源、双面打印等

//打印机相关信息
lpoptions -p HP-Color-LaserJet-MFP-M281fdw -l 
//输出信息

//纸张信息
PageSize/Media Size: *Letter Legal Executive FanFoldGermanLegal 4x6 5x8 A4 A5 A6 B5 B6 102x152mm Oficio 195x270mm 184x260mm 7.75x10.75 Postcard DoublePostcardRotated Env10 EnvMonarch EnvISOB5 EnvC5 EnvDL Custom.WIDTHxHEIGHT
//双面打印
Collate/Collate: True False
//双面打印设置
Duplex/Two-Sided: *None DuplexNoTumble DuplexTumble
//纸张来源
InputSlot/Paper Feed: *Auto Tray1 Tray2 ManualFeed
HPOption_Duplexer/Duplex Unit: True *False
MediaType/Media Type: *Unspecified Plain HPEcoFFICIENT HPLaserJet90 HPColorLaserMatte105 HPPremiumChoiceMatte120 HPBrochureMatte150 HPCoverMatte200 HPMattePhoto200 HPPremiumPresentationGlossy120 HPBrochureGlossy150 HPTrifoldBrochureGlossy150 HPBrochureGlossy200 Light6074 Intermediate8595 MidWeight96110 Heavy111130 ExtraHeavy131175 HeavyGlossy111130 ExtraHeavyGlossy131175 CardGlossy176220 ColorLaserTransparency Labels Letterhead Envelope HeavyEnvelope Preprinted Prepunched Colored Bond Recycled Rough HeavyRough OpaqueFilm
HPPJLColorAsGray/Print Color as Gray: True *False
HPRGBEmulation/RGB Color: *DefaultSRGB PhotoSRGB Adobe VividSRGB HPRGBEmulationNone
HPEdgeControl/Edge Control: HPEdgeControlOff Light *Normal Max
HPGeneralHalftone/Halftone: *Smooth Detail
HPTextNeutralGrays/Text Neutral Grays: *Black ProcessBlack
HPGraphicsNeutralGrays/Graphics Neutral Grays: *Black ProcessBlack
HPPhotoNeutralGrays/Photo Neutral Grays: Black *ProcessBlack

  有了前面的命令就可以封装获取打印机名称及打印机信息的方法了:

//命令执行帮助类
public static class ShellHelper

    public static string RunCommand(string? command, string? args)
    
        if (string.IsNullOrWhiteSpace(command))
            return string.Empty;
        var process = new Process()
        
            StartInfo = new ProcessStartInfo
            
                FileName = command,
                Arguments = args,
                RedirectStandardOutput = true,
                RedirectStandardError = true,
                UseShellExecute = false,
                CreateNoWindow = true,
            
        ;
        process.Start();
        string output = process.StandardOutput.ReadToEnd();
        string error = process.StandardError.ReadToEnd();
        process.WaitForExit();
        if (string.IsNullOrEmpty(error))  return output; 
        else  return error; 
    

  获取打印机名称:

public static object GetAllPrinterNames(ILogger? logger = null)

    object result = null;
    if (printerCache.TryGetValue(PrinterName, out result)
                && (result is PrinterSettings.StringCollection
                && (result as PrinterSettings.StringCollection).Count == PrinterSettings.InstalledPrinters.Count))
    
        result = printerCache[PrinterName];
    
    else
    
        if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
        
            string cmdResult = ShellHelper.RunCommand("lpstat", "-p");
            string[] strArray = cmdResult.Split(\'\\n\');
            List<string> strList = new List<string>();
            int index1, index2;
            for (int i = 0; i < strArray.Length; i++)
            
                index1 = strArray[i].IndexOf(\' \');
                if (index1 <= 0) continue;

                index2 = strArray[i].IndexOf(\' \', index1 + 1);
                if (index2 <= 0) continue;

                strList.Add(strArray[i].Substring(index1 + 1, index2 - index1 - 1));
            
            //获取打印机信息
            result = strList;
        
        else
        
            result = PrinterSettings.InstalledPrinters;
        
        printerCache[PrinterName] = result;
    
    return result;
   

  获取打印机信息:需注意不同打印机获取出来的设置信息不同,需要获取通用的打印机信息:纸张来源、纸张、双面打印等

public static List<PrinterInfo> GetAllPrinters(ILogger? logger = null)

    List<PrinterInfo> result = null;
    if (printerCache.TryGetValue(PrinterInfo, out object objresult)
                    && (objresult is List<PrinterInfo>
                    && (objresult as List<PrinterInfo>).Count == PrinterSettings.InstalledPrinters.Count))
    
        result = objresult as List<PrinterInfo>;
    
    else
    
        var resultPrinterInfos = new List<PrinterInfo>();
        if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
        
            string cmdResult = ShellHelper.RunCommand("lpstat", "-p");
            string[] strArray = cmdResult.Split(\'\\n\');
            List<string> strList = new List<string>();
            int index1, index2;
            for (int i = 0; i < strArray.Length; i++)
            
                index1 = strArray[i].IndexOf(\' \');
                if (index1 <= 0) continue;

                index2 = strArray[i].IndexOf(\' \', index1 + 1);
                if (index2 <= 0) continue;

                strList.Add(strArray[i].Substring(index1 + 1, index2 - index1 - 1));
            
            //获取打印机信息
            foreach (var item in strList)
            
                cmdResult = ShellHelper.RunCommand("lpoptions", $"-p \\"item\\" -l");
                string[] strArray2 = cmdResult.Split(new string[]  "\\n" , StringSplitOptions.RemoveEmptyEntries);
                /*
                    PageSize/Media Size: *Letter Legal Executive FanFoldGermanLegal 4x6 5x8 A4 A5 A6 B5 B6 102x152mm Oficio 195x270mm 184x260mm 7.75x10.75 Postcard DoublePostcardRotated Env10 EnvMonarch EnvISOB5 EnvC5 EnvDL Custom.WIDTHxHEIGHT
                    Collate/Collate: True False
                    Duplex/Two-Sided: *None DuplexNoTumble DuplexTumble
                    InputSlot/Paper Feed: *Auto Tray1 Tray2 ManualFeed
                    HPOption_Duplexer/Duplex Unit: True *False
                    MediaType/Media Type: *Unspecified Plain HPEcoFFICIENT HPLaserJet90 HPColorLaserMatte105 HPPremiumChoiceMatte120 HPBrochureMatte150 HPCoverMatte200 HPMattePhoto200 HPPremiumPresentationGlossy120 HPBrochureGlossy150 HPTrifoldBrochureGlossy150 HPBrochureGlossy200 Light6074 Intermediate8595 MidWeight96110 Heavy111130 ExtraHeavy131175 HeavyGlossy111130 ExtraHeavyGlossy131175 CardGlossy176220 ColorLaserTransparency Labels Letterhead Envelope HeavyEnvelope Preprinted Prepunched Colored Bond Recycled Rough HeavyRough OpaqueFilm
                    HPPJLColorAsGray/Print Color as Gray: True *False
                    HPRGBEmulation/RGB Color: *DefaultSRGB PhotoSRGB Adobe VividSRGB HPRGBEmulationNone
                    HPEdgeControl/Edge Control: HPEdgeControlOff Light *Normal Max
                    HPGeneralHalftone/Halftone: *Smooth Detail
                    HPTextNeutralGrays/Text Neutral Grays: *Black ProcessBlack
                    HPGraphicsNeutralGrays/Graphics Neutral Grays: *Black ProcessBlack
                    HPPhotoNeutralGrays/Photo Neutral Grays: Black *ProcessBlack
                */
                PrinterInfo pinfo = new PrinterInfo();
                pinfo.name = item;
                pinfo.color = true;
                pinfo.isvalid = true;
                foreach (var opItem in strArray2)
                
                    string[] kvArr = opItem.Split(":".ToArray(), StringSplitOptions.RemoveEmptyEntries);
                    if (kvArr.Length == 2)
                    
                        string key = kvArr.First();
                        string[] values = kvArr.Last().Split(" ".ToArray(), StringSplitOptions.RemoveEmptyEntries);
                        int nIndex = key.IndexOf(\'/\');
                        if (nIndex > 0) key = key.Substring(0, nIndex);//todo:判断规则可能只取/前面的部分
                        switch (key)
                        
                            //纸张
                            case "PageSize": // /Media Size  /Page Size 
                                List<PaperSize> psList = new List<PaperSize>();
                                foreach (var ps in values)
                                
                                    PaperSize paperSize = new PaperSize();
                                    paperSize.PaperName = ps.Trim(\'*\');
                                    psList.Add(paperSize);
                                
                                pinfo.paper = new PaperSizeCollection(psList.ToArray());
                                break;
                            //纸张来源
                            case "InputSlot": // /Paper Feed  /Media Source
                                List<PaperSource> psourceList = new List<PaperSource>();
                                for (int i = 0; i < values.Length; i++)
                                
                                    string ps = values[i];
                                    PaperSource pSource = new PaperSource();
                                    pSource.SourceName = ps.Trim(\'*\');
                                    pSource.RawKind = i;
                                    psourceList.Add(pSource);
                                
                                pinfo.papersource = new PaperSourceCollection(psourceList.ToArray());
                                break;
                            //双面打印
                            //Duplex/Two-Sided: *None DuplexNoTumble DuplexTumble
                            case "Duplex": // /Two-Sided   /Double-Sided Printing
                                for (int i = 0; i < values.Length; i++)
                                
                                    string ps = values[i];
                                    if (ps.Contains("*"))
                                    
                                        pinfo.duplex = i;
                                        break;
                                    
                                
                                pinfo.canduplex = values.Length > 1;
                                break;
                        
                    
                
                if (pinfo.paper == null)
                
                    pinfo.paper = new PaperSizeCollection(new PaperSize[0]);
                
                if (pinfo.papersource == null)
                
                    pinfo.papersource = new PaperSourceCollection(new PaperSource[0]);
                
                resultPrinterInfos.Add(pinfo);
            
        
        else
        
            var printerNames = PrinterSettings.InstalledPrinters;
            if (printerNames.Count > 0)
            
                foreach (string printName in printerNames)
                
                    try
                    
                        PrinterSettings ps = new PrinterSettings();
                        ps.PrinterName = printName;
                        if (ps.IsValid)
                        
                            PrinterSettings.PaperSourceCollection psSources = ps.PaperSources;
                            resultPrinterInfos.Add(new PrinterInfo(
                                printName,
                                ps.PaperSources,
                                ps.PaperSizes,
                                ps.SupportsColor,
                                (int)ps.Duplex,
                                ps.IsDefaultPrinter,
                                ps.IsValid,
                                ps.CanDuplex
                            ));
                        
                    
                    catch (Exception ex)
                    
                        logger?.LogError(ex, $"获取打印机【printName】信息失败-请检查打印机是否正常访问");
                    
                
            
        
        result = resultPrinterInfos;
        printerCache[PrinterInfo] = result;
    
    return result;

 3、打印文件:

  前面解决获取打印相关信息,接下来需要解决打印文档的问题:

/// <summary>
/// 打印内容
/// </summary>
/// <param name="pdfBytes">打印内容byte数组</param>
/// <param name="psi"></param>
public static void Print(byte[] pdfBytes, PrintSettings psi)

    string tmpFileName = Path.GetTempFileName();
    try
    
        File.WriteAllBytes(tmpFileName, pdfBytes);
        ShellHelper.RunCommand("lp", BuildLpArgs(tmpFileName, psi));
    
    finally
    
        try
        
            File.Delete(tmpFileName);
        
        catch  
    

/// <summary>
/// 构建打印参数
/// </summary>
/// <param name="filePath"></param>
/// <param name="psi"></param>
/// <returns></returns>
private static string BuildLpArgs(string filePath, PrintSettings psi)

    StringBuilder str = new StringBuilder();
    if (psi != null && psi.PrinterSetting != null)
    
        //打印机名称
        if (!string.IsNullOrWhiteSpace(psi.PrinterSetting.PrinterName))
        
            str.Append($"-d psi.PrinterSetting.PrinterName ");
        
        //双面打印
        if (psi.PrinterSetting.Duplex != Duplex.Default)
        
            switch (psi.PrinterSetting.Duplex)
            
                case Duplex.Simplex:
                case Duplex.Vertical:
                    str.Append($"-o sides=two-sided-long-edge ");
                    break;
                case Duplex.Horizontal:
                    str.Append($"-o sides=two-sided-short-edge ");
                    break;
            
        
        //打印份数
        if (psi.PrinterSetting.Copies > 1)
        
            str.Append($"-n psi.PrinterSetting.Copies ");
        
    

    if (psi != null && psi.PaperSetting != null)
    //纸张名称
        if (!string.IsNullOrWhiteSpace(psi.PaperSetting.PaperName))
        
            str.Append($"-o media=psi.PaperSetting.PaperName ");
            /*
            全部模板及尺寸如下:
            Letter- US Letter (8.5×11 inches, or 216x279mm)
            Legal- US Legal (8.5×14 inches, or 216x356mm)
            A4- ISO A4 (8.27×11.69 inches, or 210x297mm)
            COM10- US #10 Envelope (9.5×4.125 inches, or 241x105mm)
            DL- ISO DL Envelope (8.66×4.33 inches, or 220x110mm)
            Transparency- Transparency media type or source
            Upper- Upper paper tray
            Lower- Lower paper tray
            MultiPurpose- Multi-purpose paper tray
            LargeCapacity- Large capacity paper tray
            也可以自定义尺寸,比如想输出照片6寸(15.2cmx10.2cm) 只需要输入指令lp -o media=Custom.15.2×10.2cm filename
                */
        
        //是否横行
        if (psi.PaperSetting.Landscape == 1)
        
            str.Append($"-o landscape ");
        
    

    str.Append(filePath);
    return str.ToString();

三、参考

 仅在 Windows 上支持 System.Drawing.Common

 lp操作命令说明

以上是关于问题记录- 国产操作系统适配问题记录的主要内容,如果未能解决你的问题,请参考以下文章

android12适配记录

iOS12适配及问题记录

华汇数据信创终端适配平台国产化解决方案

破记录!国产数据库KunDB 单节点TPC-C事务性能超180万tpmC

Mysql迁移达梦数据库踩坑历险记

批量查找 mongoDB 记录(使用 mongoid ruby​​ 适配器)