Impression de texte

Partagez votre expérience de PureBasic avec les autres utilisateurs.
fweil
Messages : 505
Inscription : dim. 16/mai/2004 17:50
Localisation : Bayonne (64)
Contact :

Impression de texte

Message par fweil »

Il y a eu plusieurs questions relatives à l'impression aussi je vous propose ceci.

J'ai essay d'aborder un code qui permet de passer en bitmaps les pages nécessaires à l'impression d'un fichier texte de longueur quelconque.

J'ai aussi mis un preview, pas très performant pour l'instant.

C'est juste pour essayer d'expliquer au mieux l'utilisation des transformations métriques entre la visualisation à l'écran (généralement 72dpi) et l'impression qui est courament en 360 ou 720 dpi.

Comme le programme récupère justement la métrique de l'imprimante choisie, l'impression peut se faire en respectant les paramètres d'impression choisi au moment du lancement de l'impression.

Code : Tout sélectionner

;
; Print text
; F.Weil : 20040726
;
; Here is a sample code to touch what is text printing using full bitmap drawing.
; It is Windows API dependant. I guess a Linux coder would easily add the required lines, maybe coding conditional compiler directives.
; This code does not apply to Rich Edit text. Only to text printing with no embedding.
; Easy to customize however.
; ====================================================
; Voici un programme permettant de mettre les doigts dans l'impression de texte passant par des bitmaps.
; Ce code est dépendant de Windows. Je pense qu'un codeur Linux devrait pouvoir ajouter le pendant des commandes appropriées, éventuellement en plaçant des directives de compilation conditionnelle
; Ce code ne s'applique pas à du texte de type Rich Edit. Seulement au texte non décoré.
; Toutefois l'amélioration en est relativement accessible.
;
Enumeration
  #Window_Preview
  #Image_Preview
  #Image_FullPrint
  #Gadget_Image_Preview
  #DrawingFont
  #Requester_OK = 6
  #Requester_NO
EndEnumeration

#MAX_STRING_LENGTH = $400000

Structure StringBytes
  Bytes.b[#MAX_STRING_LENGTH]
EndStructure

NewList Print_text_PageName.s()

;
; Set strings length at a # max value than PureBasic's default
; ========================================
; Modifie la longueur max des chaines de caractères.
;
Procedure ManipulationBufferSize(Bytes)
  PBStringBase.l = 0
  PBMemoryBase.l = 0
  !MOV eax, dword [PB_StringBase]
  !MOV [esp+4], eax
  !MOV eax, dword [PB_MemoryBase]
  !MOV [esp+8], eax
  HeapReAlloc_(PBMemoryBase, #GMEM_ZEROINIT, PBStringBase, Bytes)
  !MOV dword [PB_StringBase], eax
  Debug "ManipulationBufferSize : max length of string set to : " + Str(Bytes)
  ProcedureReturn Bytes
EndProcedure

;
; Split a full text placed in StringIn, in lines corresponding to a given drawing width. The text is returned to the caller
; =========================================================================
; Découpe un texte entier placé dans StringIn pour faire correspondre les lignes à une largeur de dessin donné. Le texte transformé est retourné à l'appelant.
;
Procedure.s FoxLinedText2D(StringIn.s, PixelWidth.l)
  LenStringIn = Len(StringIn)
  LenStringOut = LenStringIn + 3 * (Int(LenStringIn / PixelWidth) + 1)
  StringOut.s = Space(LenStringOut)
  *MyStringIn.StringBytes = @StringIn
  *MyStringOut.StringBytes = @StringOut
  j = 0
  For i = 0 To LenStringIn - 1
    Cod.b = *MyStringIn\Bytes[i]
    If Cod = 13 Or Cod = ' ' Or Cod = '.' Or Cod = ','
        LastWordBreakInPosition = i
        LastWordBreakOutPosition = j
        If Cod = 13
            LastLineBreak = j + 3
        EndIf
    EndIf
    If k > PixelWidth And i > 0 ; means the counter reached the right margin
        io = i
        jo = j
        i = LastWordBreakInPosition + 1
        j = LastWordBreakOutPosition
        k = 0
        *MyStringOut\Bytes[j] = 13
        *MyStringOut\Bytes[j + 1] = 10
        *MyStringOut\Bytes[j + 2] = *MyStringIn\Bytes[i] ; Asc(Mid(StringIn, i, 1))
        LastLineBreak = j + 2
        If i = LastBreakDone
            LastWordBreakInPosition = io - 1
            LastWordBreakOutPosition = jo
        EndIf
        LastBreakDone = i
        j + 2
      Else
        *MyStringOut\Bytes[j] = *MyStringIn\Bytes[i] ; Asc(Mid(StringIn, i, 1))
    EndIf
    k = TextLength(Mid(StringOut, LastLineBreak, j - LastLineBreak))
    j + 1
  Next
  *MyStringOut\Bytes[j] = 0
  ProcedureReturn StringOut
EndProcedure

;
; Build a preview image from the image stored in FileName, using desktop metrics
; ====================================================
; Construit une image preview à partir de l'original situé dans le fichier cité, en utilisant la métrique de l'écran
;
Procedure MakePreview(FileName.s)
  ImageID_FullSize = LoadImage(#Image_FullPrint, FileName)
  PreviewWidth = ImageWidth()
  PreviewHeight = ImageHeight()
  HRatio.f = 1.2 * PreviewWidth / GetSystemMetrics_(#SM_CXSCREEN)
  VRatio.f = 1.2 * PreviewHeight / GetSystemMetrics_(#SM_CYSCREEN)
  If HRatio => VRatio
      ImageWidth = PreviewWidth / HRatio
      ImageHeight = PreviewHeight / HRatio
      ImageID_Preview = ResizeImage(#Image_FullPrint, ImageWidth, ImageHeight)
    Else
      ImageWidth = PreviewWidth / VRatio
      ImageHeight = PreviewHeight / VRatio
      ImageID_Preview = ResizeImage(#Image_FullPrint, ImageWidth, ImageHeight)
  EndIf
  UseImage(#Image_FullPrint)
  StartDrawing(ImageOutput())
    DrawingMode(4)
    Box(0, 0, ImageWidth, ImageHeight, #Black)
  StopDrawing()
  ProcedureReturn ImageID_Preview
EndProcedure

;
; Draw the text in images build to the printer choosen inside this procedure.
; If the given printer allows both Portrait / Landscape, just select the desired parameters in the printer requester.
; This procedure does support multiple pages. Required pages are drawn in bitmaps queued in files for print / preview.
; The queued files names are stored in Print_text_PageName() linked list.
;
; CPI (characters per inch) and font name are received from the caller to make this procedure more flexible.
; All required metrics are turned to available printer parameters. When selecting a printer the metrics are updated for this printer.
;
; The preview feature is actually not fast. I will go back on this further more in some days / weeks.
; =========================================================================
; Dessine le texte dans les images nécessaires à l'impression éventuellement multi-pages.
; L'imprimante est choisie à l'intérieur de la présente procédure. Si l'imprimante choisie autorise par exemple le portrait / paysage
; les paramètres sont automatiquement recalculés en fonction du choix opéré.
; L'impression est générée dans autant de bitmaps que de pages sont nécessaires. Les bitmaps sont stockés en attente sur le disque.
; Les noms des bitmaps sont stockés dans la liste Print_text_PageName().
;
; Les paramètres CPI (nombre de caractères au pouce) et FontName (nom de la police), sont donnés pour rendre la procédure plus flexible.
; Toute la métrique nécessaire et suffisante est calculée pour correspondre à l'imprimante choisie au moment de l'impression.
;
; La fonction de prévisualisation est actuellement peu performante. Je reprendrai ce point dans quelques jours / semaines.
;
Procedure PrintText(Text.s, CPI.l, FontName.s)
  ClearList(Print_text_PageName())
  If PrintRequester()
     printer_DC.l = StartDrawing(PrinterOutput())
      If  printer_DC
          HorizontalDPI = GetDeviceCaps_(printer_DC,#LOGPIXELSX)
          VerticalDPI = GetDeviceCaps_(printer_DC,#LOGPIXELSY)
          FontSize = HorizontalDPI / CPI
          FontHeight = FontSize * 1.6
          PrinterLeftMargin = GetDeviceCaps_(printer_DC,#PHYSICALOFFSETY)
          PrinterTopMargin = GetDeviceCaps_(printer_DC,#PHYSICALOFFSETX)
          UserMargin = HorizontalDPI
          PixelWidth = GetDeviceCaps_(printer_DC,#PHYSICALWIDTH)
          PixelHeight = GetDeviceCaps_(printer_DC,#PHYSICALHEIGHT)
          PrinterRowHeight = FontHeight
          StopDrawing()
          ImageID_FullPrint = CreateImage(#Image_FullPrint, PixelWidth, PixelHeight)
          If ImageID_FullPrint
              StartDrawing(ImageOutput())
                Box(0, 0, PixelWidth, PixelHeight, #White)
                DrawingFont(LoadFont(#DrawingFont, FontName, FontSize, #PB_Font_HighQuality))
                TextOut.s = FoxLinedText2D(Text, PixelWidth - UserMargin * 2)
                BackColor(255, 255, 255)
                FrontColor(0, 0, 0)
                DrawingMode(1)
                LineNumber = 0
                While TextOut <> ""
                  LineOut.s = Mid(TextOut, 1, FindString(TextOut, Chr(13) + Chr(10), 1) - 1)
                  TextOut = Mid(TextOut, FindString(TextOut, Chr(13) + Chr(10), 1) + 2, Len(TextOut) - FindString(TextOut, Chr(13) + Chr(10), 1) - 2 + 1)
                  Locate(UserMargin, UserMargin + PrinterRowHeight * LineNumber)
                  DrawText(LineOut)
                  LineNumber + 1
                  If UserMargin + PrinterRowHeight * LineNumber => PixelHeight - UserMargin
                      AddElement(Print_text_PageName())
                      Print_text_PageName() = "Print text." + Str(ElapsedMilliseconds()) + ".jpg"
                      Debug "Adding page : " + Print_text_PageName()
                      SaveImage(#Image_FullPrint, Print_text_PageName(), #PB_ImagePlugin_JPEG)
                      StopDrawing()
                      FreeImage(#Image_FullPrint)
                      ImageID_FullPrint = CreateImage(#Image_FullPrint, PixelWidth, PixelHeight)
                      StartDrawing(ImageOutput())
                      Box(0, 0, PixelWidth, PixelHeight, #White)
                      DrawingFont(LoadFont(#DrawingFont, FontName, FontSize, #PB_Font_HighQuality))
                      BackColor(255, 255, 255)
                      FrontColor(0, 0, 0)
                      DrawingMode(1)
                      LineNumber = 0
                  EndIf
                Wend
              StopDrawing()
              AddElement(Print_text_PageName())
              Print_text_PageName() = "Print text." + Str(ElapsedMilliseconds()) + ".jpg"
              Debug "Adding page : " + Print_text_PageName()
              SaveImage(#Image_FullPrint, Print_text_PageName(), #PB_ImagePlugin_JPEG)
              FreeImage(#Image_FullPrint)
          EndIf
          Select MessageRequester("Print request", "Do you want to print (OK) / Preview (No) / Give up (Cancel)", #PB_MessageRequester_YesNoCancel)
            Case #Requester_OK
              If StartPrinting("PureBasic Test")
                  If StartDrawing(PrinterOutput())
                      ResetList(Print_text_PageName())
                      While NextElement(Print_text_PageName())
                        Debug "Printing page : " + Print_text_PageName()
                        LoadImage(#Image_FullPrint, Print_text_PageName())
                        DrawImage(ImageID(), 0, 0)
                        DeleteFile(Print_text_PageName())
                        DeleteElement(Print_text_PageName())
                        NewPrinterPage()
                      Wend
                      StopPrinting()
                      StopDrawing()
                  EndIf
              EndIf
            Case #Requester_NO
              ResetList(Print_text_PageName())
              NextElement(Print_text_PageName())
              PreviewWidth = ImageWidth()
              PreviewHeight = ImageHeight()
              HRatio.f = 1.2 * PreviewWidth / GetSystemMetrics_(#SM_CXSCREEN)
              VRatio.f = 1.2 * PreviewHeight / GetSystemMetrics_(#SM_CYSCREEN)
              If HRatio => VRatio
                  ImageWidth = PreviewWidth / HRatio
                  ImageHeight = PreviewHeight / HRatio
                Else
                  ImageWidth = PreviewWidth / VRatio
                  ImageHeight = PreviewHeight / VRatio
              EndIf
              If OpenWindow(#Window_Preview, 0, 0, ImageWidth, ImageHeight, #PB_Window_SystemMenu | #PB_Window_ScreenCentered, "Preview window")
                  AddKeyboardShortcut(#Window_Preview, #PB_Shortcut_Escape, #PB_Shortcut_Escape)
                  AddKeyboardShortcut(#Window_Preview, #PB_Shortcut_Up, #PB_Shortcut_Up)
                  AddKeyboardShortcut(#Window_Preview, #PB_Shortcut_Down, #PB_Shortcut_Down)
                  If CreateGadgetList(WindowID(#Window_Preview))
                      ImageGadget(#Gadget_Image_Preview, 0, 0, ImageWidth, ImageHeight, MakePreview(Print_text_PageName()))
                  EndIf
                  Repeat
                    Select WaitWindowEvent()
                      Case #PB_Event_CloseWindow
                        Quit = #TRUE
                      Case #PB_Event_Menu
                        Select EventMenuID()
                          Case #PB_Shortcut_Escape
                            Quit = #TRUE
                          Case #PB_Shortcut_Up
                            PreviousElement(Print_text_PageName())
                            SetGadgetState(#Gadget_Image_Preview, MakePreview(Print_text_PageName()))
                          Case #PB_Shortcut_Down
                            NextElement(Print_text_PageName())
                            SetGadgetState(#Gadget_Image_Preview, MakePreview(Print_text_PageName()))
                        EndSelect
                    EndSelect
                  Until Quit
              EndIf
          EndSelect
      EndIf
  EndIf
  While CountList(Print_text_PageName())
    LastElement(Print_text_PageName())
    DeleteFile(Print_text_PageName())
    DeleteElement(Print_text_PageName())
  Wend
EndProcedure

;
; The Main program cnotains initalization for using JPEG files and enhancing the string max length.
; Then you can just place any text in the parameter to call PrintText() with the desired font size and name.
; ===================================================================
; Le programme principal contient simplement les initialisations permettant d'utiliser les images JPEG et les chaines de longueur non standard.
; Il suffit d'appeler PrintText() avec nu texte quelconque et les paramètres de police souhaités.
;
Text.s
  ManipulationBufferSize(#MAX_STRING_LENGTH)
  UseJPEGImageDecoder()
  UseJPEGImageEncoder()

  If ReadFile(0, "Print text.pb")
      DataLength = Lof()
      *Buffer = AllocateMemory(DataLength)
      ReadData(*Buffer, DataLength)
      CloseFile(0)
      Text = PeekS(*Buffer)
      PrintText(Text, 12, "Verdana")
  EndIf
End
Mon avatar reproduit l'image de 4x1.8m présentée au 'Salon international du meuble de Paris' en janvier 2004, dans l'exposition 'Shades' réunisant 22 créateurs autour de Matt Sindall. L'original est un stratifié en 150 dpi.