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