Code: Select all
Structure PointF :  X.f : Y.f : EndStructure
Structure FLEX
  pt.POINT
  Plg.POINT[4]
  Vertx.POINT[4]
  s1.f[4]
  S2.PointF[4]
EndStructure
Global __Hatch,__Rim
Global _Brush,_BrushRGB,_BrushStyle
Global _DRAWING,_Grid,_Mode
Global _MyFont10=FontID(LoadFont(-1,"Arial",10))
Global _OldBrush,_Pen,_PenRGB,_PenStyle,_ShowCornerNumbers=1,_Showflag=1
Global _X,_Xmax,_Xmin,_Y,_Ymax,_Ymin
Global Dim Color(0, 0) 
Global Dim Grid.POINT(0, 0)  
Global _Flex.FLEX
Title$ = "Image Rotate, Pull, Reverse & Stretch" 
   
UseJPEGImageDecoder() 
UseJPEGImageEncoder() 
UsePNGImageDecoder() 
UsePNGImageEncoder() 
UseTGAImageDecoder() 
UseTIFFImageDecoder() 
#DBLUE=$660000
#LBLUE=$FFFCC2
Enumeration 
  #ImGad 
  #IMG 
  #IMG2 
  #Open
  #SaveAs
  #CornerNumbers
  #Quit      
  #HorVer
  #Diag
  #Grid
  #GridIMG
EndEnumeration 
  
Macro MMx :  WindowMouseX(EventWindow()) : EndMacro
Macro MMy :  WindowMouseY(EventWindow()) : EndMacro
Macro MMK
  Abs(GetAsyncKeyState_(#VK_LBUTTON) +GetAsyncKeyState_(#VK_RBUTTON)*2+GetAsyncKeyState_(#VK_MBUTTON)*3)/$8000   
EndMacro
 
Macro MouseOverGad ;- MouseOverGad : ret GadgetID under mouse
  WindowFromPoint_(MMx|MMy<<32)
EndMacro
  
Macro LoBound(A,B) :  If A<B :A=B:EndIf : EndMacro
Macro HiBound(A,B) :  If A>B :A=B:EndIf : EndMacro
  
Procedure InMousEX(X,Y,X1,Y1)
  SetRect_(rc.RECT,X,Y,X1,Y1)
  ProcedureReturn PtInRect_(@rc,MMx|MMy<<32)
EndProcedure
  
Macro STOPDRAW  ;- StopDraw
  If _DRAWING
StopDrawing() : _DRAWING=0: EndIf 
EndMacro
  
Macro DrawIMG(IMG) ;- DrawIMG(IMG) ; #ImageOutput=2
  STOPDRAW
_DRAWING=StartDrawing(ImageOutput(IMG)) ;<
EndMacro
  
Procedure Min(A,B)
  If A<B:ProcedureReturn A:EndIf
  ProcedureReturn B
EndProcedure
  
Procedure  ClsImg(IMG,RGB=0) ;-ClsImg(IMG,RGB=0) 
  DrawIMG(IMG)
  Box(0,0,ImageWidth(IMG),ImageHeight(IMG),RGB)
EndProcedure 
  
Macro DelBrush()   ;-DelBrush()
  If _Brush :DeleteObject_(_Brush) :EndIf
  _Brush=0
  If _OldBrush : SelectObject_(_DRAWING, _OldBrush) : EndIf
  _BrushRGB=0
EndMacro 
  
Procedure  Brush(BrushRGB,style=#BS_SOLID,Hatch=0)  ;- Brush(BrushRGB,Style=#BS_SOLID,Hatch=0) #BS_HOLLOW, #BS_PATTERN
  Protected L.LOGBRUSH
  DelBrush()
  L\lbStyle=style
  L\lbColor=BrushRGB
  L\lbHatch=Hatch
  _Brush = CreateBrushIndirect_(@L) 
  _OldBrush=SelectObject_(_DRAWING,_Brush)
  _BrushRGB=BrushRGB
  _BrushStyle=style
  __Hatch=Hatch
EndProcedure  
   
Macro DelPen() ;- DelPen
  If _Pen: DeleteObject_(_Pen) :EndIf
  _Pen=0: _PenRGB=0:__Rim=0
EndMacro
  
Macro Pen(Rim=1, PenRGB=0,style=#PS_SOLID) ;-  Pen(Rim=1, PenRGB=0,style=#ps_solid)
  DelPen()
  If style=#NULL_PEN
    _Pen= SelectObject_(_DRAWING,GetStockObject_ ( #NULL_PEN ))
  Else
    _Pen=CreatePen_(style,Rim,PenRGB)   
    SelectObject_(_DRAWING,_Pen) 
  EndIf
  __Rim=Rim
  _PenRGB=PenRGB
  _PenStyle=style
EndMacro
      
Procedure CenterTXT(X,Y,Wi,He,T.S)  
  
  Protected TextWidth=TextWidth(T),TextHeight=TextHeight(T)
  Protected X1=X+Wi,Y1=Y+He
  If TextWidth>Wi :  DrawText(X,(Y+Y1)/2-TextHeight/2 , T)
  Else :  DrawText((X+X1)/2-TextWidth/2, (Y1+Y)/2-TextHeight/2 , T)
  EndIf
EndProcedure
  
Procedure  Corners() ;-  draw corners
  Protected i
  With _Flex
    DrawingFont(_MyFont10)
    FrontColor(#LBLUE):BackColor(#DBLUE)
    For i = 0 To 3 
      Circle (\Vertx[i]\X , \Vertx[i]\Y, 9,#DBLUE) 
      CenterTXT(\Vertx[i]\X-5,\Vertx[i]\Y-5,10,10,Str(i)) 
    Next 
  EndWith
EndProcedure
   
Procedure Bounding() ;- Bounding()
  Protected i
  With _Flex
    _Xmax=0 : _Xmin=$FFFFFF:_Ymax=0:_Ymin=$FFFFFF
    For i = 0 To 3   
      HiBound(_Xmin,\Vertx[i]\X)
      LoBound(_Xmax,\Vertx[i]\X)
      HiBound(_Ymin,\Vertx[i]\Y)
      LoBound(_Ymax,\Vertx[i]\Y)
    Next 
  EndWith
EndProcedure 
  
Procedure  STP(A,B,C,D,E)  ;- STP(A,B,C,D,E)  - aux de Sizes
  With _Flex
    \s1[0]   = (\S2[A]\X - \S2[B]\X) / E 
    \s1[1]   = (_Flex\Vertx[C]\X - _Flex\Vertx[D]\X) / E 
    \s1[2]   = (\S2[A]\Y    - \S2[B]\Y)   / E 
    \s1[3]   = (_Flex\Vertx[C]\Y - _Flex\Vertx[D]\Y) / E 
  EndWith
EndProcedure
   
Procedure  Sizes() 
  Protected i,j,A.f,B.f,C.f,D.f
  With _Flex
    Bounding()
    \S2[0]\X = (\Vertx[1]\X - \Vertx[0]\X)  / \pt\X ; step X HOR TOP
    \S2[0]\Y = (\Vertx[1]\Y - \Vertx[0]\Y)  / \pt\X ; step Y HOR TOP
    \S2[1]\X = (\Vertx[2]\X - \Vertx[3]\X)  / \pt\X ; step X HOR BOTTOM
    \S2[1]\Y = (\Vertx[2]\Y - \Vertx[3]\Y)  / \pt\X ; step Y HOR BOTTOM
    \S2[2]\X = (\Vertx[3]\X - \Vertx[0]\X)  / \pt\Y ; step X VER LEFT
    \S2[2]\Y = (\Vertx[3]\Y - \Vertx[0]\Y)  / \pt\Y ; step Y VER LEFT
    \S2[3]\X = (\Vertx[2]\X - \Vertx[1]\X)  / \pt\Y ; step X VER RIGHT
    \S2[3]\Y = (\Vertx[2]\Y - \Vertx[1]\Y)  / \pt\Y ; step Y VER RIGHT
    
    STP(1,0,3,0,\pt\Y)
    
    For j = 0 To \pt\Y 
      A=\S2[0]\X     +\s1[0]*j 
      B=\Vertx[0]\X  +\s1[1]*j 
      C=\S2[0]\Y     +\s1[2]*j 
      D=\Vertx[0]\Y  +\s1[3]*j 
      For i = 0 To \pt\X 
        Grid(i,j)\X=A*i+B
        Grid(i,j)\Y=C*i+D 
      Next 
    Next 
    
    STP(3,2,1,0,\pt\X)
    
    For j = 0 To \pt\X 
      A=\S2[2]\X    +\s1[0]*j 
      B=\Vertx[0]\X +\s1[1]*j 
      C=\S2[2]\Y    +\s1[2]*j 
      D=\Vertx[0]\Y +\s1[3]*j 
      For i = 1 To \pt\Y 
        Grid(j,i)\X=A*i+B
        Grid(j,i)\Y=C*i+D 
      Next 
    Next 
  EndWith
EndProcedure  
   
Procedure FastGrid(Wi,He,StpX=24,StpY=-1,RGB=-1)
  If StpY=-1:StpY=StpX:EndIf
  If RGB=-1:RGB=$555555:EndIf
  For Y=0 To He
    LineXY(0,Y,Wi,Y,RGB)
    Y+StpY
  Next
  For X=0 To Wi
    LineXY(X,0,X,He,RGB)
    X+StpX    
  Next
EndProcedure 
  
Macro InitGrid() ;- InitGrid()
  CreateImage(#GridIMG,_X,_Y)
  DrawIMG(#GridIMG)
  FastGrid(_X,_Y,30,30)
  STOPDRAW
EndMacro     
   
Procedure  FastImage() ;- Faster than ShowImage - ONLY POINTS to circumvent the Polygon drawing 
  Static i,j,STP
  With _Flex
    If _Grid
      FreeImage(#IMG)
      GrabImage(#GridIMG,#IMG,0,0,_X,_Y)
      DrawIMG(#IMG)
    Else       
      DrawIMG(#IMG)
      ClsImg(#IMG)
    EndIf  
    If _ShowCornerNumbers : Corners() : EndIf 
    STP=\pt\X/120  ; LONGER STP = QUICKER DRAWING  
    LoBound(STP,1)
    i=0
    Repeat   ; Increase Stp for slow processor
      j=0
      Repeat
        Box(Grid(i, j)\X, Grid(i, j)\Y,1,1, Color(i, j))
        j+STP
      Until j>=\pt\Y 
      i+STP
    Until i>=\pt\X 
    STOPDRAW
    SetGadgetState(#ImGad, ImageID(#IMG)) 
  EndWith
EndProcedure 
     
Procedure  Polyg( Sides,*P,RGB=-1) ;P= array of POINT struc with polyg vertices ; sides >1 
  If RGB>-1
    Pen(1,RGB):Brush(RGB)
  EndIf
  Polygon_(_DRAWING,*P,Sides)  
EndProcedure 
     
Procedure ShowImage() 
  Protected i,j,i2,j2
  With _Flex
    If _Grid
      FreeImage(#IMG)
      GrabImage(#GridIMG,#IMG,0,0,_X,_Y)
      DrawIMG(#IMG)
    Else       
      DrawIMG(#IMG)
      ClsImg(#IMG,0)
    EndIf  
    If _ShowCornerNumbers : Corners() : EndIf 
    
    For i = 0 To \pt\X
      DrawIMG(#IMG)
      
      If MMK = 1 : _Showflag=0: ProcedureReturn : EndIf ;  show interruptus
      i2=i+1 
      WindowEvent()
      
      For j = 0 To \pt\Y 
        If j < \pt\Y And i < \pt\X 
          j2=j+1 
          \Plg[0]\X = Grid(i ,j )\X ;  Polygon positions
          \Plg[0]\Y = Grid(i ,j )\Y
          \Plg[1]\X = Grid(i2,j )\X 
          \Plg[1]\Y = Grid(i2,j )\Y 
          \Plg[2]\X = Grid(i2,j2)\X 
          \Plg[2]\Y = Grid(i2,j2)\Y 
          \Plg[3]\X = Grid(i ,j2)\X 
          \Plg[3]\Y = Grid(i ,j2)\Y 
          Pen(1,Color(i,j)):Brush(Color(i,j))
          Polyg(4,\Plg[0])
        Else 
          Plot(Grid(i,j)\X, Grid(i,j)\Y, Color(i,j)) ; only 1 pixel for the last line 
        EndIf 
      Next 
      If _ShowCornerNumbers : Corners() : EndIf 
      STOPDRAW
      SetGadgetState(#ImGad,ImageID(#IMG))
    Next 
  EndWith
EndProcedure 
   
Procedure SaveImg(DefaultFile$="",Title.S="Save Image") ; Save Image 
  Protected Flag, Pattern$ = "(*.bmp)|*.bmp|"   
  Pattern$ + "(*.jpg)|*.jpg|"   
  Pattern$ + "(*.png)|*.png|"   
  File$=SaveFileRequester("Please Choose The File Name To Save", DefaultFile$, Pattern$, 0)
  If File$
    If _ShowCornerNumbers
      Flag=1
      _ShowCornerNumbers = 0 
    EndIf   
    If _Grid 
      Flag+2
      _Grid=0
    EndIf
    If Flag : ShowImage()  : EndIf
    
    Select SelectedFilePattern()
      Case 0 : SaveImage(#IMG,File$,#PB_ImagePlugin_BMP)
      Case 1 : SaveImage(#IMG,File$,#PB_ImagePlugin_JPEG,10)
      Case 2 : SaveImage(#IMG,File$,#PB_ImagePlugin_PNG)
    EndSelect
    MessageRequester("","Saved to "+File$, #PB_MessageRequester_Ok)
  Else
    MessageRequester("","File Not Saved", #PB_MessageRequester_Ok)
  EndIf   
  
  If Flag=1 Or Flag=3:_ShowCornerNumbers=1:EndIf
  If Flag=2 Or Flag=3:_Grid=1:EndIf
  If Flag:ShowImage():EndIf
EndProcedure
   
Procedure$ GetLastDir(LastDirFile.S)
  Protected Temp= ReadFile(-1,GetTemporaryDirectory()+LastDirFile)
  If Temp
    LastDir.S=ReadString(Temp)
    CloseFile(Temp)
  EndIf    
  ProcedureReturn LastDir.S
EndProcedure 
  
Procedure SetLastDir(LastDirFile.S,LastDir.S)  ;-SetLastDir - pone en TempDir
  Protected Temp
  DeleteFile(GetTemporaryDirectory()+LastDirFile)
  Temp=OpenFile(-1,GetTemporaryDirectory()+LastDirFile)
  If Temp
    WriteString(Temp,LastDir)
    CloseFile(Temp)
  EndIf
EndProcedure 
  
Procedure LeeImg(*P.POINT) 
  Protected StandardFile$
  Static IMG,hIMG
  If IsImage(IMG):FreeImage(IMG):EndIf
  If hIMG:DeleteDC_(hIMG):EndIf
  LastDirFile.S="EstiraLast"
  Pattern$ = "Images (*.bmp, *.jpg, *.png, *.tiff, *.tga)|*.bmp;*.jpg; *.png; *.tiff ; *.tga |All files (*.*)|*.*" 
  StandardFile$=GetLastDir(LastDirFile)
  If StandardFile$=""
    StandardFile$ = "e:\" ; put here your image directory 
  EndIf
  File$ = OpenFileRequester("Load Image", StandardFile$, Pattern$, Pattern) 
  If File$ 
    StandardFile$=GetPathPart(File$)
    SetLastDir(LastDirFile,StandardFile$)
    hIMG = CreateCompatibleDC_(GetDC_(WindowID(0))) 
    IMG = LoadImage(#PB_Any, File$,  #PB_Image_DisplayFormat) 
    If ImageWidth(IMG)>_X
      ResizeImage(IMG,_X,ImageHeight(IMG))
    EndIf
    If ImageHeight(IMG)>_Y
      ResizeImage(IMG,ImageWidth(IMG),_Y)
    EndIf
    *P\X=ImageWidth(IMG):*P\Y=ImageHeight(IMG)
    SelectObject_(hIMG, ImageID(IMG)) 
    ProcedureReturn hIMG 
  EndIf 
EndProcedure 
   
Procedure  Menu(Win=0) ;- Menu(win)
  Protected Menu= CreateMenu(-1, WindowID(Win))   
  MenuTitle("   File")
  MenuItem(#Open,"Open ") 
  MenuBar() 
  MenuItem(#SaveAs,"Save As") 
  MenuBar()
  MenuItem(#Quit,"Quit")
  MenuTitle("   Options")
  MenuItem( #CornerNumbers, "Switch Corner Numbers on/off") 
  MenuBar()
  MenuItem(#Grid,"Switch Grid on/off")
  ProcedureReturn Menu
EndProcedure 
     
Procedure NewImage() 
 Protected hIMG = LeeImg(@P.POINT) ,X,Y,CenterX,CenterYsz
  With _Flex
    If hIMG  
      \pt\X = P\X - 1 : \pt\Y = P\Y - 1 
      Global Dim Color(\pt\X, \pt\Y) 
      Global Dim Grid.POINT (\pt\X, \pt\Y ) 
      For X = 0 To \pt\X 
        For Y = 0 To \pt\Y 
          Color(X, Y) = GetPixel_(hIMG, X, Y) 
        Next 
      Next 
      CenterX=_X/2:CenterY=_Y/2
      SZ=Min(_X,_Y)/10
      \Vertx[0]\X = CenterX-SZ 
      \Vertx[0]\Y = CenterY-SZ 
      \Vertx[1]\X = CenterX+SZ 
      \Vertx[1]\Y = CenterY-SZ 
      \Vertx[2]\X = CenterX+SZ 
      \Vertx[2]\Y = CenterY+SZ 
      \Vertx[3]\X = CenterX-SZ 
      \Vertx[3]\Y = CenterY+SZ        
      Sizes() : ShowImage() 
    EndIf
  EndWith
EndProcedure 
Procedure GetDistance(A1,A2) ;- GetDistance(a1,a2) 
  ProcedureReturn Sqr(A1*A1 + A2*A2)          
EndProcedure 
Procedure Near(X,Y); X, Y, ArrSize, ARRAY P.POINT(1)) ; Return elem de Array de Points Nearest to  x,y 
  Protected A,i,min
  With _Flex
    min = $FFFFFFF 
    For i = 0 To 3 
      A = GetDistance(X - \Vertx[i]\X, Y - \Vertx[i]\Y) 
      If A < min : min = A : Near = i : EndIf 
    Next i 
    ProcedureReturn Near 
  EndWith
EndProcedure 
    ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< 
    
If  OpenWindow(0, 100, 100,600,400,Title$, #WS_OVERLAPPEDWINDOW | #WS_MAXIMIZE) 
  SetWindowColor(0,0)
  StickyWindow(0,1)
  
  _X=WindowWidth(0):_Y=WindowHeight(0)
  Menu()    
  CreateImage(#IMG, _X,_Y,32) 
  ImageGadget(#ImGad,0,0,0,0,ImageID(#IMG)) 
  SetWindowLongPtr_(GadgetID(#ImGad), -20, GetWindowLongPtr_(GadgetID(#ImGad), -20) | $2000000)
  
  InitGrid() : NewImage() 
  With _Flex
    
    Repeat 
      If GetAsyncKeyState_(#VK_ESCAPE) :  End:EndIf
      
      Ev = WaitWindowEvent(1) 
      Select Ev
        Case #PB_Event_Menu 
          Select EventMenu() ; To see which menu has been selected 
            Case #Quit  : End 
            Case #Open  :NewImage() 
            Case #SaveAs:SaveImg()
            Case #CornerNumbers ;  switch corner numbers 
              _ShowCornerNumbers = 1 -_ShowCornerNumbers  
              ShowImage()  
            Case #Grid 
              _Grid=1-_Grid
              ShowImage()     
          EndSelect 
        Case #PB_Event_SizeWindow
          _X=WindowWidth(0):_Y=WindowHeight(0)
          ShowImage()
        Default
          If Ev=#WM_MOUSEMOVE
            If MMK = 1 
              If  InMousEX(1,1,_X-4,_Y-4)
                If Sel = 0
                  Near = Near(MMx,MMy) 
                  Sel = 1 
                EndIf 
                _Showflag = 0 
                \Vertx[Near]\X = MMx 
                \Vertx[Near]\Y = MMy 
                Sizes() :  FastImage() 
              EndIf 
            EndIf    
            
          EndIf  
          If MMK=0
            If _Showflag = 0 : _Showflag = 1 : ShowImage() : EndIf 
            Sel = 0 
          EndIf     
      EndSelect
    Until Ev = #PB_Event_CloseWindow 
  EndWith
EndIf
  End