Partage
  • Partager sur Facebook
  • Partager sur Twitter

Impression la plus basique d'un fichier .txt en Qt

    11 octobre 2020 à 13:00:57

    Bonjour à tous

    je suis donc en train de réécrire un programme script bash linux en C++ Qt5, dans ce script bash j'avais une commande toute simple qui me permettait d'imprimer directement mon fichier ouvert en lecture comme ceci:

    cat $FICHIER > /dev/lp0

    J'ai examiné QPrinter et QTextDocument ,je n'ai rien trouvé d'aussi simple pour imprimer vers mon imprimante à ticket, j'entends par là, une impression directe sans dialogue de choix d'imprimante ou de configuration. En gros je m'attend à ce que quand je clique le bouton imprimer il imprime vers la bonne imprimante sans poser de questions. En l'occurrence /dev/lp0. Il s'agit d'une imprimante matricielle à ticket de caisse. Qui fonctionne d'ailleur très bien en script bash.

    Je n'ai malheureusement pas réussi  à produire un code valable sur le sujet pour jeter une base.

    Je pense à quelque chose comme ça d'après ce que je vois :

    QTextStream out(&file);
    out << textOut + "\n";

     Mais je ne sais pas comment initialiser le flux de l'imprimante c'est une imprimante POS de type Bixolon SRP-275II.

    Merci beaucoup pour votre aide.

    -
    Edité par yoritomo 11 octobre 2020 à 21:14:20

    • Partager sur Facebook
    • Partager sur Twitter
      12 octobre 2020 à 21:18:33

      Bonsoir

      Peut-être, je devrais tout simplement faire appel à un script.sh externe pour effectuer cette impression, mais je trouve ça un peu bourrin quand même, je préférerais ne pas déléguer cette tâche à un script, surtout que c'est très peu portable comme méthode.

      QString program = "sh ./chemin/vers/mon/script/print.sh";
      QStringList arguments;
      arguments << "-style" << "fusion";
      
      QProcess *myProcess = new QProcess(parent);
      myProcess->start(program, arguments);
      


      Ca c'est ce que j'ai trouvé pour le faire, mais si quelqu'un à une piste pour l'impression directe vers /dev/lp0 sans fenêtre de dialogue, je préfèrerais encore.

      Je vois des bouts de code en C# donc il doit y avoir un équivalent C++ voire même en Qt5.

      Le but serait de pouvoir initialiser un filestream sur /dev/lp0 mais je ne trouve pas grand chose de concret qui se rapproche assez. Souvent il s'agit de l'impression de PDF ou d'images qui demandent évidemment bien plus de lignes de code.

      Bonne soirée

      -
      Edité par yoritomo 12 octobre 2020 à 21:22:12

      • Partager sur Facebook
      • Partager sur Twitter
        13 octobre 2020 à 11:50:47

        Tu peux essayer d'ouvrir un QFile sur /dev/lp0, peut-être en écriture seule et en cas d'erreur, si QFile::open renvoie false, voir ce que renvoient QFile::error() ou errorString() après la tentative d'ouverture.

        S'il n'y a pas d'erreur, tu pourras utiliser QTextStream en choisissant l'encodage utilisé par l'imprimante pour avoir les accents et/ou le signe euro avec QTextStream::setCodec(), avec le paramètre "cp850" ou "cp858" (les 2 sont à priori équivalents côté Qt), si l'imprimante est bien configurée pour utiliser la page de code "cp858".

        -
        Edité par alexisdm 15 octobre 2020 à 23:12:17

        • Partager sur Facebook
        • Partager sur Twitter
          15 octobre 2020 à 21:27:33

          Bonsoir

          Merci alexisdm pour ces conseils, je ne me suis pas encore attaqué à l'encodage des caractères spéciaux parce que provisoirement je les convertis , mais j'ai bien progressé, voici le code que j'ai produit :

          bool MainWindow::printFile(QString fileName){    
                  
              std::ifstream dFile (fileName);
              if (dFile.is_open())
              {
                  std::string line;
                  char const * const PrinterName = "/dev/lp0"; // Identifie le port d'imprimante.
                  std::ofstream printer(PrinterName); // Ouvre le flux vers l'imprimante.
                  if(!printer) // S'assure que le flux d'impression est vraiment créé.
                  {
                     printf("Rien n'est fait !");
                     return 0;
                  }
                  while(getline(dFile, line))
                  {
                      printer << line << "\n";            
                  }
          
                  printer << "\n\x1Bi"; // Coupure partielle du ticket pour imprimante POS.
                  printer << endl << flush;
                  printer.close(); // Terminer le flux de données par la fermeture du fichier.
                  dFile.close();
          
                  return 1;
              }
          
          }
          

          Ca fonctionne assez bien mais l'ennui par cette méthode, c'est que tout s'enchaîne à l'impression sur le ticket, pas de sauts de ligne, pourtant j'envoie le texte ligne par ligne, même les "\n" ne sont pas pris en compte, simplement ils sont imprimés.

          -
          Edité par yoritomo 15 octobre 2020 à 21:36:31

          • Partager sur Facebook
          • Partager sur Twitter
            16 octobre 2020 à 1:17:46

            L'impression fonctionnait avec le même fichier envoyé par la commande cat dans le script ? 

            Parce que si c'est le cas, d'après le manuel (chapitre 8 hexadecimal dumping), l'imprimante a un mode de débogage dans lequel elle va imprimer tous les caractères qu'elle reçoit sous forme hexadécimale, ça devrait te permettre de voir s'il y a une différence entre les 2 méthodes.

            • Partager sur Facebook
            • Partager sur Twitter
              16 octobre 2020 à 22:48:38

              Bonjour

              Maintenant les sauts de ligne fonctionnent , je me suis aperçu du problème en relisant le post sur le forum, je l'ai corrigé mais il y avait une slash au lieu d'un back slash dans le \n.

              Pour les caractères spéciaux en shell dans la console linux, c'est pareil , si je fais cat "J'ai essayé ça" > /dev/lp0 , les accents ne passent pas non plus, bien qu'en suivant la documentation de l'imprimante, j'ai configuré les DIP Switchs (commutateurs mécaniques sous l'appareil) pour régler en émulation Epson, en suivant cette configuration j'ai basculé les switchs pour mettre en french charset.

              Autre chose, la commande de coupure de papier ne fonctionne pas, pourtant la doc dit ça , il faut envoyer ESC + i


              35-  ESC i Partial cut (one point left uncut)"

              J'ai essayé  ceci mais ça ne fonctionne pas :

              std::string cutCommand = Convert.ToString((char)27) + Convert.ToString((char)105) ;
              printer << cutCommand ;

              J'ai aussi essayé ça :

              QString commandString = "";
                      commandString.append(27);// code de la commande ESC
                      commandString.append(105);// caractère 'i'
                      commandString.toStdString();
                      printer << commandString.toStdString();
              

              Sans plus de succès

              Il y a sûrement quelque chose que je ne saisis pas

              Bonne soirée

              -
              Edité par yoritomo 17 octobre 2020 à 22:31:09

              • Partager sur Facebook
              • Partager sur Twitter
                18 octobre 2020 à 23:01:20

                Bonsoir

                Aujourd'hui , j'ai essayé de suivre votre conseil avec le setCodec sur cp850, mais ça ne fonctionne pas avec std::ofstream qui n'a pas de membre équivalent, je suis un peu perdu pour réécrire ma fonction d'impression avec un QFileStream pour tenter ça.

                Merci et bonne soirée

                • Partager sur Facebook
                • Partager sur Twitter
                  19 octobre 2020 à 4:00:27

                  les flux de la stl n'ont pas la notion de charset, surtout sur linux où ils ne font vraiment aucune transformation à l'écriture.

                  Les accents s'affichent comment ? Et à quoi correspond french charset ? Parce qu'habituellement sur linux, les fichiers sont en utf-8 et si french charset correspond à cp850, ce n'est pas du tout la même, il faudra faire une conversion.

                  • Partager sur Facebook
                  • Partager sur Twitter
                    19 octobre 2020 à 13:49:28

                    Bonjour

                    Merci pour votre réponse, il faudrait donc convertir en Latin1 ? Comment savoir quel est l'encodage de caractère qui sort de mon flux ?

                    Bonne journée

                    • Partager sur Facebook
                    • Partager sur Twitter
                      19 octobre 2020 à 16:58:33

                      L'encodage des chaînes littérales dépend surtout de l'encodage de la configuration de ton IDE ou de ton éditeur de texte, si tu ne spécifies pas de conversions explicites dans le code. 

                      Pour la commande de partial cut "ESC + i", toutes les méthodes que tu as essayées devraient produire le même résultat, la plus simple étant ce que tu avais mis au début "\x1Bi". Pour cette séquence en particulier, ça ne pose pas de problème de l'envoyer dans un QString, mais pour les codes supérieurs à 0x80, qui indiqueraient en utf-8 un caractère codé sur plusieurs octets, les conversions successives peuvent altérer la valeur du paramètre.

                      Par exemple pour demander à l'imprimante de souligner un texte, la séquence est "ESC + ! + n" ou n vaut justement 0x80, si tu passes par QString ou par QByteArray (ou n'importe quelle autre une chaîne 8 bit comme std::string), tu auras 2 résultats différents:

                      // La chaîne QString va contenir la conversion unicode de la chaîne littérale qui est supposée être en utf8
                      QString underlineModeStr = "\x1B!\x80";
                      QByteArray underlineMode = "\x1B!\x80";
                      // définit le codec utilisé par toLocal8bit()
                      QTextCodec::setCodecForLocale(QTextCodec::codecForName("cp850"));
                      qDebug() << "QString" << underlineModeStr.toLocal8Bit().toHex();
                      qDebug() << "QByteArray" << underlineMode.toHex();

                      qui va renvoyer:

                      QString "1b213f"
                      QByteArray "1b2180"

                      Le paramètre de la commande passe donc de 0x80 (souligné) à 0x3F (font B, gras, double hauteur, double largeur).

                      Et pour l'équivalent de ton code avec QFile et QTextStream, ça devrait donner ça (j'ai juste vérifié que ça compilait et que "cp858"):

                      #include <QFile>
                      #include <QTextStream>
                      #include <QDebug>
                      
                      
                      bool MainWindow::printFile(QString fileName){
                      
                          QFile dFile(fileName); //std::ifstream dFile (fileName);
                          if(!dFile.open(QIODevice::ReadOnly)) {
                              qDebug() << "Error opening file: "<< dFile.errorString();
                              return false;
                          }
                          QTextStream input(&dFile);
                          input.setCodec("utf8");
                      
                          QFile printer("/dev/lp0");
                          if(!printer.open(QIODevice::WriteOnly)) {
                              qDebug() << "Error opening printer: "<< printer.errorString();
                              return false;
                          }
                          QTextStream output(&printer);
                          output.setCodec("cp850");
                      
                          QString line;
                      
                          while(input.readLineInto(&line)) {
                              output << line << "\n";
                          }
                      
                          output.flush();
                      
                          QByteArray partialCut = "\x1Bi";
                          printer.write(partialCut);
                      
                          return true;
                      }
                      



                      • Partager sur Facebook
                      • Partager sur Twitter
                        19 octobre 2020 à 22:32:23

                        Bonsoir,

                        Un grand merci pour cette réponse détaillée a dû vous demander du temps à recoder ça.

                        Je ne suis qu'un développeur occasionnel pour mes propres besoins, c'est pour ça que j'avais utilisé du std:: .

                        Alors j'ai essayé ce code qui a affiché sans modifications directement tous les accents, mais pas le signe "€" qui lui par contre est remplacé par un "?", je n'ai aucune idée de l'année de production de cette imprimante, ça pourrait expliquer ce manque ?

                        Le papier ne se coupe pas, je vois dans le manuel de commande de l'imprimante qu'il y à Esc + m  qui devrait faire la même chose, mais ça ne donne rien non plus.

                        J'ai donc pu désactiver toutes les conversions de caractères spéciaux, c'est déjà un pas de géant grâce à votre aide. Je cherche toujours des code snippets et les exemples sur le sujet mais ça tourne toujours autour de ce que j'avais déjà essayé. Je ferais bien sans la coupure de papier mais c'est quand même bien pratique.

                        Le cutter fonctionne parce que si je bascule le DIP switch en mode "autocut", à chaque allumage de l'imprimante il coupe le ticket, mais ça n'a aucun sens ...

                        Un petit rectificatif, après vérification sur l'étiquette signalétique, l'imprimante est une Bixolon SRP-275CG et non pas SRP-275II, mais pour les commandes je crois que ça ne change rien. Je n'ai pas réussi à lui trouver une mise à jour du firmware.

                        Il y à quand même des options qui attirent ma curiosité dans les commandes, comme Esc + R +S "Stores international character set to NV memory " serait il possible de remettre à jour la banque de caractères de l'imprimante par ce bief ?

                        Un grand merci et bonne soirée

                        -
                        Edité par yoritomo 19 octobre 2020 à 23:13:31

                        • Partager sur Facebook
                        • Partager sur Twitter
                          20 octobre 2020 à 13:32:22

                          En fait, le "?" vient de Qt, pas d'un problème avec l'imprimante. Il faut remplacer 

                          output.setCodec("cp850");

                          par 

                          output.setCodec("cp858");

                          dans le code de mon message précédent. Apparemment cp850 et cp858 ne sont pas directement gérés par Qt, mais par des bibliothèques tierces installées sur l'OS (ICU ou iconv). Quand j'ai fait le test pour les séquences ESC, j'étais sous Windows et codecForName("cp858") renvoyait un pointeur nul, alors que sous linux, ce codec est bien reconnu et le signe "€" a le bon code "0xD5" attendu par l'imprimante.

                          Si ça affiche autre chose que "€", c'est que l'imprimante n'est pas configurée pour le cp858, ce qui semble se faire soit avec les MSW ou memory switches (dans l'utilitaire de configuration, ou avec la commande "set memory switch" "ESC GS # ..." mais ça a l'air compliqué par ce biais), ou encore avec la commande "Select character code table" "ESC t 19", et là ça n'est pas stocké en mémoire donc il faut relancer la commande à chaque redémarrage.

                          Pour l'autocutter, le manuel indique bien qu'il faut que le DIP switch correspondant soit activé pour que la commande ESC+i fonctionne, dans le cas contraire, une led s'allume pour indiquer un problème lors de l'exécution de la commande. 

                          Peut-être qu'il y a autre chose dans la configuration de l'imprimante qui provoque le déclenchement du cutter au démarrage.

                          yoritomo a écrit:

                          Il y à quand même des options qui attirent ma curiosité dans les commandes, comme Esc + R +S "Stores international character set to NV memory " serait il possible de remettre à jour la banque de caractères de l'imprimante par ce bief ?

                          Cette commande sert à choisir un jeu de caractères déjà présent en ROM, et à sauvegarder le choix en mémoire non volatile. Par contre, il y a une commande pour remplacer un caractère en mémoire non volatile: "Define user-defined character set" "ESC &".



                          -
                          Edité par alexisdm 20 octobre 2020 à 13:33:58

                          • Partager sur Facebook
                          • Partager sur Twitter
                            21 octobre 2020 à 21:42:43

                            Bonsoir

                            J'ai fait pas mal de tests mais , même avec le dip switch l'auto-cutter activé (1-3) rien ne se passe, que se soit avec Esc + i ou Esc + m, ils sont soit disant équivalents selon la doc, je n'avais pas vu qu'il y avait une description détaillée de ces commandes qui précisait que l'auto cutter devait être actif. Par contre en ce qui concerne le témoin rouge c'est seulement si la commande de cutter est reçue mais si l'imprimante n'est pas équipée du cutter alors elle se affiche une erreur. La mienne en est bien équipée.

                            Je ne comprend pas la procédure avec le ESC & pour définir un caractère, mais si c'est en mémoire non volatile le changement devrait être permanent ?

                            Avec le cp850 l'€ s'affiche "?" avec cp858 il s'affiche "1", je ne sais plus trop quoi en penser , c'est quelque chose que je ne connaissais pas ces code cp , après tout si c'est trop compliqué, le "E" majuscule remplacera bien l'euro ... si il n'y a pas d'autre solution.

                            Bonne soirée.

                            • Partager sur Facebook
                            • Partager sur Twitter
                              21 octobre 2020 à 22:25:19

                              cp850 et cp858 sont des encodages (code page 85x), une manière d'associer des bytes à un caractère. Tu peux trouver les tables de correspondance sur wikipédia: https://en.wikipedia.org/wiki/Code_page_850 et https://en.wikipedia.org/wiki/Code_page_858 (850 n'a pas de €).

                              Après, tout va dépendre de comment tu écris les données, à quoi ressemble le code actuellement ? Il faut savoir qu'avec Qt et selon certaines options, les fonctions prenant un char* s'attendent à recevoir des caractères ascii (donc 7 bits et € n'y est pas) et dans le cas contraire, cela peut-être remplacé par un "replacement characters" (généralement ? ou autre caractère dédié si l'encodage le permet), ce qui peut expliquer la transformation de en ?.

                              Tu peux comparer directement le résultat qui doit être envoyé en l'écrivant dans un fichier normal à la place de /dev/lp0 puis en utilisant la commande linux hexdump lefichier. Normalement, si tu veux un €, le fichier doit contenir la valeur D5 (représentation hexadécimal), dans le cas contraire, il y a un problème dans les conversions.

                              -
                              Edité par jo_link_noir 21 octobre 2020 à 22:26:35

                              • Partager sur Facebook
                              • Partager sur Twitter
                                22 octobre 2020 à 2:03:23

                                yoritomo a écrit:

                                Je ne comprend pas la procédure avec le ESC & pour définir un caractère, mais si c'est en mémoire non volatile le changement devrait être permanent ?

                                Oui, mais tu peux désactiver les caractères redéfinis pour utiliser ceux en ROM. D'après ce que je comprend, un reset complet les effacerait également.

                                Avec le cp850 l'€ s'affiche "?" avec cp858 il s'affiche "1", je ne sais plus trop quoi en penser , c'est quelque chose que je ne connaissais pas ces code cp , après tout si c'est trop compliqué, le "E" majuscule remplacera bien l'euro ... si il n'y a pas d'autre solution.

                                "€" correspond au caractère 0xD5 en cp858, mais en cp850, 0xD5 est un "i" sans point. Ce qui signifie que l'imprimante est configurée en mode cp850.

                                Comme je l'ai écrit plus haut, tu peux changer la configuration de l'imprimante de plusieurs façons, dont envoyer la séquence "ESC t 19" ou "\x1Bt\x13" au début de l'impression. Cette méthode ne stocke pas la page de code en mémoire non volatile, il faudra le refaire à chaque réinitialisation de l'imprimante:

                                ...
                                // Select character code table cp858
                                printer.write("\x1Bt\x13);
                                
                                QTextStream output(&printer);
                                output.setCodec("cp858");
                                ...
                                

                                Pour le cutter, apparemment, le mode d'émulation (dip switch 1-1 et 1-2) influe également sur les commandes disponibles, d'après la doc du modèle SRP-275 (ici). Le partial cut est

                                • "ESC i"/"ESC m" en mode EPSON et EPSON-KP (BXL/POS et BXL/POS-KP dans le manuel de la SRP-275II), 
                                • "ESC d" en mode STAR SP500, 
                                • "ESC P 0"/"ESC P 1" en mode Citizen. 

                                De même, la sélection de la table de caractères est "ESC GS t" en mode STAR au lieu de "ESC t" pour les autres modes. 

                                J'espère que tu n'es pas déjà en mode epson, parce que je ne vois pas ce que ça pourrait être d'autre.

                                • Partager sur Facebook
                                • Partager sur Twitter
                                  22 octobre 2020 à 21:35:20

                                  jo_link_noir a écrit:

                                  cp850 et cp858 sont des encodages (code page 85x), une manière d'associer des bytes à un caractère. Tu peux trouver les tables de correspondance sur wikipédia: https://en.wikipedia.org/wiki/Code_page_850 et https://en.wikipedia.org/wiki/Code_page_858 (850 n'a pas de €).

                                  Merci c'est très intéressant ces tableaux, ça m'en apprend un peu plus surce fameux codage, en cp850 il n'y a donc pas d'€ ?

                                  alexisdm a écrit:

                                  Pour le cutter, apparemment, le mode d'émulation (dip switch 1-1 et 1-2) influe également sur les commandes disponibles, d'après la doc du modèle SRP-275 (ici). Le partial cut est

                                  • "ESC i"/"ESC m" en mode EPSON et EPSON-KP (BXL/POS et BXL/POS-KP dans le manuel de la SRP-275II), 
                                  • "ESC d" en mode STAR SP500, 
                                  • "ESC P 0"/"ESC P 1" en mode Citizen. 

                                  De même, la sélection de la table de caractères est "ESC GS t" en mode STAR au lieu de "ESC t" pour les autres modes. 

                                  J'espère que tu n'es pas déjà en mode epson, parce que je ne vois pas ce que ça pourrait être d'autre.

                                  Oui c'était ça pour le cutter ! Maintenant ça fonctionne, il était en mode star

                                  Je vais essayer la commande de changement de jeux de caractère, et je vous dis quoi après.


                                  Edit: Après avoir entré votre nouvelle ligne de commande (il y avait un guillemet manquant), l'€ apparaissait enfin dans mon total ainsi que dans la description de l'article mais  pas à chaque prix en fin de ligne, j'ai cherché pourquoi et j'ai trouvé ! Ce n'est pourtant pas très logique :

                                  Ma ligne d'origine pour noter l'article et le prix sur le ticket était celle ci :

                                  out << linePrint << "€\n";

                                  Celle ligne n'affichait pas l'€ mais une série de 3 caractères inappropriés.

                                  Par contre en modifiant comme ceci, le problème était résolu :

                                  out << linePrint + "€\n";

                                  Je tiens vraiment à vous remercier pour cette aide précieuse et pleine de recherche qui m'a permis finalement de résoudre les derniers accrocs que j'avais encore dans mon programme, j'aurai sans doute encore des améliorations à faire par après mais il est déjà pleinement fonctionnel.

                                  Un tout grand merci et bonne soirée.


                                  -
                                  Edité par yoritomo 22 octobre 2020 à 23:53:11

                                  • Partager sur Facebook
                                  • Partager sur Twitter
                                    24 octobre 2020 à 22:40:08

                                    Y a t'il une section dédiée sur le site ou sur le forum pour partager du logiciel open source ? Comme ça je pourrais en faire profiter d'autres de ce petit programme qui ne paye pas de mine mais qui rendra sûrement de bon services à ceux qui ont une imprimante POS sous linux , utilisable par quelques adaptations pour d'autres modèles bien sûr...
                                    • Partager sur Facebook
                                    • Partager sur Twitter
                                      25 octobre 2020 à 0:12:35

                                      Il existe des forges plus appropriées pour le partage de projet. Les plus connues étant github et gitlab.

                                      • Partager sur Facebook
                                      • Partager sur Twitter
                                        25 octobre 2020 à 17:11:49

                                        Merci,

                                        J'ai déposé des logiciels sur sourceforges , mais je pensais qu'il y avait peut-être un partage local sur ce site.

                                        Bon dimanche à tous

                                        • Partager sur Facebook
                                        • Partager sur Twitter

                                        Impression la plus basique d'un fichier .txt en Qt

                                        × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                                        × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
                                        • Editeur
                                        • Markdown