No announcement yet.


  • Filter
  • Time
  • Show
Clear All
new posts

  • PrintME

    Drawing from my old gbPrint code, here's a function that prints the dialog, resized to fit on the paper.

    When there are lighter letters on a darker background, my local B&W printer turns the background into black and the letters into white.

    The problem with that is that it uses up printer ink/toner really quickly. I'd like the option to reverse the colors when I know I'm printing something that will use up a lot of toner.

    I can write code that changes the color of each pixel based on some trigger point (Graphic Get Bits, work on the string, Graphic Set Bits), using an algorithm such as this ....

      Pixel = RGB((r + 128) Mod 256, (g + 128) Mod 256, (b + 128) Mod 256)
    ...but I would think there ought to be an "inverse" color API of some kind. I did find the InvertRect API and it does a pretty good job, although I've tried it only on a few color combinations.

    Print dialog example:
    'Compilable Example:
    #Compiler PBWin 10
    #Compile Exe
    #Dim All
    %Unicode = 1
    #Include ""
    Enum Equates Singular
       IDC_Button = 500
       LandScape  = 2
       Portrait   = 1
       UseDefault = 0
       ChoosePrinter  = 0
       DefaultPrinter = 1
       SizeToFit   = 0
       NaturalSize = 1
       UseXYInchCoordinates = 0
       CenterOnPage = 1
    End Enum
    Global hDlg,hFont As Dword
    Function PBMain() As Long
       Font New "Tahoma", 48,1 To hFont
       Dialog New Pixels, 0, "PrintME",300,300,250,200, %WS_OverlappedWindow To hDlg
       Control Add Button, hDlg, %IDC_Button,"Push", 50,10,100,20
       Control Add Graphic, hDlg, %IDC_Graphic,"", 0,40,250,160
       Graphic Set Font hFont
       Graphic Color %Yellow, %Blue
       Graphic Clear
       Graphic Set Pos(100,40) : Graphic Print "X"
       Dialog Show Modal hDlg Call DlgProc
    End Function
    CallBack Function DlgProc() As Long
       Select Case Cb.Msg
          Case %WM_Command
             Select Case Cb.Ctl
                Case %IDC_Button
                   PrintScreenImageB hDlg, %DefaultPrinter, %LandScape, %SizeToFit, %CenterOnPage, 0, 0
             End Select
       End Select
    End Function
    Sub PrintScreenImageB(hWindow As Dword, PrinterSelection As Long, PrinterOrientation As Long, RenderSize As Long, _
                Location As Long, x0 As Single, y0 As Single)
       Local x,y,wNew,hNew,wImg,hImg,wCont,hCont As Long
       Local hDC_Window, hDC_Printer, deskDC As Dword
       Local gXppi, gyPPI, pXppi, pYppi As Long, rc As Rect
       If RenderSize = %SizeToFit Then Location = %CenterOnPage
       'Select Printer
       Select Case PrinterSelection
          Case %DefaultPrinter : XPrint Attach Default
          Case %ChoosePrinter : XPrint Attach Choose
       End Select
       If Len(XPrint$)=0 Then Exit Sub
       'Set Printer Orientation
       Select Case PrinterOrientation
          Case %Landscape : XPrint Set Orientation 2
          Case %Portrait  : XPrint Set Orientation 1
          Case %UseDefault 'no action. use whatever printer dialog was set for
       End Select
       'Get Printer Properties
       XPrint Get Client To wCont, hCont
       XPrint Get PPI To pXppi, pYppi
       XPrint Get DC To hDC_Printer
       'Get Screen PPI
       deskDC = GetDC(%HWND_Desktop)
       gXppi = GetDeviceCaps(deskDC, %LogPixelsX)
       gYppi = GetDeviceCaps(deskDC, %LogPixelsX)
       ReleaseDC %HWND_Desktop, deskDC
       'Calculate Print Size
       'Dialog Get Size hWindow To wImg,hImg
       GetWindowRect hWindow, rc
       wImg = rc.nRight - rc.nLeft
       hImg = rc.nBottom - rc.nTop
       'ShowBarMessage_WithSleep "Window Size: " + Str$(wImg) + Str$(hImg)
       'Clipboard Reset
       'Clipboard Set Text "Window Size: " + Str$(wImg) + Str$(hImg)
       hDC_Window = GetWindowDC (hWindow)
       Select Case RenderSize
          Case %NaturalSize
             wNew = wImg * pXppi/gXppi
             hNew = hImg * pYppi/gYppi
          Case %SizeToFit
             'wCont,hCont = container size : hImg,wImg = original image size : wNew,hNew = image size to fit in container
             wNew = wImg / Max(wImg / wCont, hImg / hCont)
             hNew = hImg / Max(wImg / wCont, hImg / hCont)
       End Select
       'Calculate Upper/Left Corner
       Select Case Location
          Case %CenterOnPage
             x = (wCont-wNew)/2 : y = (hCont-hNew)/2 'upper/left position so resized image is centered
          Case %UseXYInchCoordinates
             x = x0 * pXppi : y = y0 * pYppi
       End Select
       XPrint Get Orientation To PrinterOrientation
       Select Case PrinterOrientation
          Case %Landscape
             ReDim Pt(0 To 2) As PointAPI
             Pt(0).x = y        :  Pt(0).y = x + wNew -1
             Pt(1).x = y        :  Pt(1).y = x
             Pt(2).x = y+hNew-1 :  Pt(2).y = x + wNew -1
             PlgBlt(hDC_Printer, Pt(0), hDC_Window, 0, 0, wImg, hImg, 0, 0, 0)  ' Draw rotated image
          Case %Portrait
             StretchBlt hDC_Printer,x,y,wNew,hNew, hDC_Window,0,0,wImg,hImg,%SRCCopy
       End Select
       ReleaseDC hWindow, hDC_Window
       XPrint Close
    End Sub

  • #2
    Can you do anything with XPRINT SET MIX? Never tried it myself on images. Documentation seems a little vague. Or downright misleading.
    "To every unsung hero in the universe
    To those who roam the skies and those who roam the earth
    To all good men of reason may they never thirst " - from "Heaven Help the Devil" by G. Lightfoot


    • #3

      Color image to negative

      Converting a color image into negative is very simple. All we have to do is repeat 3 simple steps for each pixels of the image.
      1. Get the RGB value of the pixel.
      2. Calculate the new RGB value as shown below.

        R = 255 – R
        G = 255 – G
        B = 255 – B
      3. Save the new RGB value in the pixel.

      The world is strange and wonderful.*
      I reserve the right to be horrifically wrong.
      Please maintain a safe following distance.
      *wonderful sold separately.


      • #4
        Simple negative example.
        #COMPILE EXE
        #DIM ALL
        ENUM controls SINGULAR
            negative = 500
        END ENUM
            LOCAL hWnd AS DWORD, hfont AS LONG
            FONT NEW "Times New Roman", 20, 0, 1, 0 TO hfont
            DIALOG NEW PIXELS, 0, "Negative", , , 600, 100, %WS_CAPTION OR %WS_POPUP OR %WS_SYSMENU, 0 TO hWnd
            CONTROL ADD GRAPHIC, hWnd, %grafix, "", 100, 0, 500, 200
            CONTROL ADD BUTTON, hWnd, %negative, "Negative", 0, 0, 100, 100
            GRAPHIC ATTACH hWnd, %grafix
            GRAPHIC CLEAR
            GRAPHIC SET POS (50, 30)
            GRAPHIC SET FONT hfont
            GRAPHIC PRINT "White Text On Black Background"
           DIALOG SHOW MODAL hWnd, CALL dlgproc()
            SELECT CASE CB.MSG
                CASE %WM_COMMAND
                    SELECT CASE CB.CTL
                        CASE %negative
                            IF CB.CTLMSG = %BN_CLICKED THEN
                                LOCAL bitstring AS STRING, PTR_bs AS BYTE POINTER, x AS LONG
                                GRAPHIC ATTACH CB.HNDL, %grafix, REDRAW
                                GRAPHIC GET BITS TO bitstring
                                PTR_bs = STRPTR(bitstring) + 8
                                FOR x = 0 TO LEN(bitstring)-1
                                    @PTR_bs[x] = 255-@PTR_bs[x]
                                GRAPHIC SET BITS bitstring
                                GRAPHIC REDRAW
                            END IF
                    END SELECT
            END SELECT
        The world is strange and wonderful.*
        I reserve the right to be horrifically wrong.
        Please maintain a safe following distance.
        *wonderful sold separately.


        • #5
          Hey Kurt!
          Thanks!. That's a great example of how the bitstring can be used to modify colors with a minimum of code. The hard part is understanding what code change to make to get the desired visual change!

          The use of the InvertRect seems to give the same visual effect, doesn't it? I wasn't sure what the algorithm is that InvertRect uses, but it seems to give a similar result.

          The result I was looking for was to convert to a pair of binary colors. The code I posted below converts each pixel to grayscale, then turns it black or white depending on the grayscale value. I can control the binary pair that is displayed.

          Click image for larger version

Name:	pb_2097.jpg
Views:	21
Size:	42.4 KB
ID:	777807

          #Compile Exe
          #Dim All
          #Debug Display
          Enum controls Singular
              negative = 500
          End Enum
          Function PBMain () As Long
              Local hWnd As Dword, hfont As Long, hBmp As Dword
              Font New "Times New Roman", 20, 0, 1, 0 To hfont
              Dialog New Pixels, 0, "Negative", , , 600, 100, %WS_Caption Or %WS_Popup Or %WS_SysMenu, 0 To hWnd
              Control Add Graphic, hWnd, %grafix, "", 100, 0, 500, 200
              Control Add Button, hWnd, %negative, "Negative", 0, 0, 100, 100
              Graphic Attach hWnd, %grafix
              Graphic Color %Yellow, %Blue
              Graphic Clear
              Graphic Set Pos (100, 30)
              Graphic Set Font hfont
              Graphic Bitmap Load "cowgirl.bmp", 0,0 To hBMP
              Graphic Print "White Text On Black Background"
              Graphic Copy hBMP, 0
             Dialog Show Modal hWnd, Call dlgproc()
          End Function
          CallBack Function dlgproc() As Long
              Select Case Cb.Msg
                  Case %WM_Command
                      Select Case Cb.Ctl
                          Case %negative
                              If Cb.CtlMsg = %BN_Clicked Then ConvertToBW(128)
                      End Select
              End Select
          End Function
          Sub ConvertToBW(BWTrigger As Long)
             Local w,h,i,iColor,R,G,B As Long, p As Long Ptr, bmp$
             Graphic Get Bits To bmp$
             'get width/height of image
             w = Cvl(bmp$,1)
             h = Cvl(bmp$,5)
             p = StrPtr(bmp$)+8    'position of starting position for bits in string
             'get string position of coordinates and modify the string at that position
             For i = 1 To w*h
                iColor = @p                           'result is a BGR color value 0-R-G-B
                B = iColor Mod 256                    'or this: iColor AND &HFF&
                G = (iColor\256) Mod 256              'or this: (iColor AND &HFF00&) \ &H100
                R = (iColor\256\256) Mod 256          'or this: (iColor AND &HFF0000&) \ &H10000&
                iColor = 0.299*R + 0.587*G + 0.114*B  'or this: iColor = (R+G+B)/3
                If iColor <= BWTrigger Then @p = Bgr(%White) Else @p = Bgr(%Black)
                Incr p
             Next i
             Graphic Set Bits bmp$
             Graphic ReDraw
          End Sub


          • #6
            Yep, our code and InvertRect API appear to give the same results.

            Here's the code for using InvertRect ...

                                      Local rc As Rect
                                      rc.nTop = 0 : rc.nTop = 0 : rc.nRight = 500 : rc.nBottom = 100
                                      InvertRect hDC, rc
                                      Graphic ReDraw
            Actually, now that I see it, I seem to recall there's an API to get the window rectangle. That would have shortened it some. .

            Click image for larger version  Name:	pb_2098.jpg Views:	1 Size:	28.3 KB ID:	777809
            Last edited by Gary Beene; 7 Jan 2019, 12:40 PM.