2014-04-11 4 views
2

사용자가 사용자 지정 "스탬프"를 만들어 PDF에 배치 할 수있는 양식이 있습니다. 이 양식은 pdf 첫 페이지 이미지로 표시되며 기본적으로 사용자는 자신의 도장을 원하는 화면을 클릭하여 모양이 어떻게 보이는지 미리 볼 수 있습니다. PDF 파일에 대해 걱정하지 마십시오.회전 된 텍스트의 좌표 계산 및 테두리 경계

멋진 이미지를 만들기 위해 이미지의 사본이 두 개 있습니다. 정상적인 이미지와 밝기가 감소한 이미지입니다. 저휘도 이미지를 표시하고 사용자가 마우스를 움직이면 원본 이미지의 덩어리가 표시되거나 강조 표시됩니다. 그런 다음 해당 영역에 사용자가 PDF에 넣을 텍스트를 표시합니다.

사용자는 마우스 휠을 사용하여 스크롤하려는 텍스트의 각도를 변경할 수 있습니다 (-45도에서 +45도까지).

여기 내 문제가 있습니다. 적절한 직사각형/좌표를 계산할 수 없습니다. 때로는 모든 것이 멋지게 보이고 다른 때는 (글꼴 크기가 변함에 따라) 아주 적합하지 않습니다.

는 어떻게 X를 계산합니까와 y 좌표 : 회전 된 텍스트 의 위치와 경계의 구형 패딩 10px

작품 아래의 코드와 폭에서 텍스트와 높이, 내가 크랭크 시작까지 글꼴 크기를 늘리면 모든 것이 왜곡되지 않습니다.

처음 두 개의 이미지는 작은 글꼴에 텍스트 + 경계 사각형을 표시합니다. 그것은 좋아 보인다 :

enter image description here enter image description here

다음 이미지는 텍스트 크기가 커질수록, 내 픽셀 주위의 모든 이동 오프 다진됩니다 보여줍니다. 더 큰 텍스트에서도 너비/높이가 끝납니다.

enter image description here enter image description here

죄송 예제 이미지는 많은 세부 사항을 표시하지 않습니다. 공유 할 수없는 실제 데이터가 있습니다.

 Private Sub PanelMouseMove(ByVal sender As Object, ByVal e As MouseEventArgs) '// handles the mouse move (handler added elsehwere) 

     With CType(sender, PictureBox) 

      .Image.Dispose() '// get rid of old image 

      Dim b As Bitmap = _curGray.Clone '// the low brightness image as the base image 

      '// stamp font and text values are initiated from another form 
      Using g As Graphics = Graphics.FromImage(b), 
       f As New Font(DefaultFont.FontFamily, CSng(_stmpTools.StampTextSize), If(_stmpTools.StampBold, FontStyle.Bold, FontStyle.Regular)) 

       Const borderWidth As Integer = 10 
       Const borderPadding As Integer = 5 

       '// measure the string 
       Dim szx As SizeF = g.MeasureString(_stmpTools.StampText, f, Integer.MaxValue, StringFormat.GenericDefault) 
       Dim strLength As Single = szx.Width 
       Dim strHeight As Single = szx.Height 

       Dim x As Single = e.X - borderWidth - borderPadding, 
        y As Single = e.Y 

       Dim w As Double, h As Double 

       If Math.Abs(_angle) > Double.Epsilon Then 
        h = CDbl(strLength) * Math.Sin(CDbl(Math.Abs(_angle)) * Math.PI/180.0F) 
        w = Math.Sqrt(CDbl(strLength) * CDbl(strLength) - h * h) 
       Else 
        '// its zero. so use calculated values 
        h = strHeight 
        w = strLength 
       End If 

       '// add space for the 10px border plus 5px of padding 
       Dim r As New Rectangle(0, 0, w, h) 
       r.Inflate(borderWidth + borderPadding, borderWidth + borderPadding) 

       h = r.Height 
       w = r.Width 

       '// keep box from moving off the left 
       If x < .Location.X Then 
        x = .Location.X 
       End If 

       '// keep box from moving off the right 
       If x > .Location.X + .Width - w Then 
        x = .Location.X + .Width - w 
       End If 

       '// I don't know, but these values work for most smaller fonts, but 
       '// it has got to be a fluke 
       If _angle > 0 Then 
        y = y - h + borderWidth + borderWidth 
       Else 
        y = y - borderWidth 
       End If 

       '// can't go off the top 
       If y < .Location.Y Then 
        y = .Location.Y 
       End If 

       '// can't go off the bottom 
       If y > .Location.Y + .Height - h Then 
        y = .Location.Y + .Height - h 
       End If 

       Dim rect As New Rectangle(x, y, w, h) 
       g.DrawImage(_curImg, rect, rect, GraphicsUnit.Pixel) 

       Using br As New SolidBrush(_stmpTools.StampTextColor) 
        RotateString(_stmpTools.StampText, _angle, e.X, e.Y, f, g, br) 
       End Using 

       '//draw bounding rectangle 
       Using p As New Pen(Color.Black, borderWidth) 
        g.DrawRectangle(p, rect) 
       End Using 

      End Using 
      '// set the picture box to show the new image 
      .Image = b 
     End With 

    End Sub 

    Private Sub RotateString(ByVal Text As String, ByVal angle As Integer, _ 
         ByVal x As Integer, ByVal y As Integer, myfont As Font, mydrawing As Graphics, myColor As Brush) 
     Dim myMatrix As New Matrix 
     myMatrix.RotateAt(angle * -1, New Point(x, y)) 'Rotate drawing 
     mydrawing.Transform = myMatrix 
     mydrawing.DrawString(Text, myFont, myColor, x, y) 'Draw the text string 
     myMatrix.RotateAt(angle, New Point(x, y)) 'Rotate back 
     mydrawing.Transform = myMatrix 
    End Sub 

나는 그리기에 관해서 최고가 아니다. 그래서 도움이 될 것입니다.

아래의 솔루션을 @LarsTech에서 사용하십시오. g.FillRectangle을 다음으로 대체했습니다.

g.DrawImage(_curImg, r, r, GraphicsUnit.Pixel) 

_curImg는 밝기를 조정 한 원본 이미지의 복사본입니다. 내가 아래에서 코드를 변경하면 결국 :

enter image description here 두 줄을 유의하십시오. 그들은 그들이 배경 이미지로 행동하고 제안 당

을 회전되지 않은한다하더라도, 스탬프와 함께 회전, 나는 다음에 @LarsTech에서 DrawStamp을 변경 : 그러나

 Private Sub DrawStamp(g As Graphics, text As String, 
        f As Font, center As Point, angle As Integer, backImg As Image) 

     Dim s As Size = g.MeasureString(text, f).ToSize 
     Dim r As New Rectangle(center.X - (s.Width/2) - 16, 
           center.Y - (s.Height/2) - 16, 
           s.Width + 32, 
           s.Height + 32) 

     g.DrawImage(backImg, r, r, GraphicsUnit.Pixel) 

     Using m As New Matrix 
      m.RotateAt(angle, center) 
      g.Transform = m 

      Using p As New Pen(Color.Black, 6) 
       g.DrawRectangle(p, r) 
      End Using 
      Using sf As New StringFormat 
       sf.LineAlignment = StringAlignment.Center 
       sf.Alignment = StringAlignment.Center 
       g.DrawString(text, f, Brushes.Black, r, sf) 
      End Using 
      g.ResetTransform() 
     End Using 
    End Sub 

, 지금 남아 있어요 enter image description here

배경을 그린 다음 회전하여 우표를 그렸습니다. 그것은 거의 작동합니다. 이 예제에서 직선은 의도 된 동작을 보여줍니다 ...그러나 나는 전체 스탬프를 배경으로 채우기를 원합니다. 옆면의 여분의 흰색은 우표의 배경으로 회전 된 것이었을 것입니다. 나는 '회색'부분이 이미지의 일부를 잘라내는 것으로 의심하기 때문에 혼란 스럽지만, 그렇지 않습니다. (불행히도 여기에 게시 할 수없는 다른 영역 위로 이동하면) 통지가 없습니다. 직사각형의 측면이 그 자체로 페인트한다는 사실을 제외하고는 비뚤어졌습니다.

잘하면 좀 더 많은 정보를 원하시면 여기

또 다른 편집 잘하면 내가 뭘하려고 오전의 더 나은 explaination입니다. 타사 PDF 뷰어를 사용하며 사용자가 이미지를 PDF에 추가 할 수 있어야합니다. 뷰어는 사용자의 마우스 클릭을 잡기 위해, 그래서 내가 다음을 수행, 내가 그것을 클릭 이벤트를 발생시킬 수 없습니다 :

  1. 은 PDF 뷰어를 숨기기
  2. 형태의 화면 잡아보세요
  3. 양식에 PictureBox 컨트롤을 추가하여 PDF 뷰어가 있던 영역을 바꿉니다.
  4. 내 화면을 잡으면 밝기를 줄여 이미지 복사본을 만듭니다.
  5. 이미지의 회색조 복사본을 표시하고 바로 그립니다. Picturebox의 이벤트에 마우스를 올려 놓은 이미지
  6. 나는 그림 상자에 도장을 그렸지만 그 배경을 원본 (비 조정 밝기 이미지)으로하고 싶다. 그러나 영역이 회전을 사용하여 변형 될 수 있으므로 배경 이미지를 가져올 수 없습니다. 각도를 지정하지 않으면 소스 사각형이 일치합니다. 그러나 그것의 회전, 나는 소스 이미지에서 동일한 회전 사각형을 잡을 수 없습니다.

버튼을 클릭 이벤트 : 나는 두 개의 이미지와 끝까지 그 코드 후

Dim bds As Rectangle = AxDPVActiveX1.Bounds 
    Dim pt As Point = AxDPVActiveX1.PointToScreen(bds.Location) 

    Using bit As Bitmap = New Bitmap(bds.Width, bds.Height) 
     Using g As Graphics = Graphics.FromImage(bit) 
      g.CopyFromScreen(New Point(pt.X - AxDPVActiveX1.Location.X, pt.Y - AxDPVActiveX1.Location.Y), Point.Empty, bds.Size) 
     End Using 

     _angle = 0 

     _curImg = bit.Clone 
     _curGray = Utils.CopyImageAndAdjustBrightness(bit, -100) 

End Using 

    Dim p As New PictureBox 

     Utils.SetControlDoubleBuffered(p) 

     p.Dock = DockStyle.Fill 
     p.BackColor = Color.Transparent 
     AxDPVActiveX1.Visible = False 
     p.Image = _curImg.Clone 

     AddHandler p.MouseClick, AddressOf PanelDownMouse 
     AddHandler p.MouseMove, AddressOf PanelMouseMove 
     AddHandler p.MouseWheel, Sub(s As Object, ee As MouseEventArgs) 
            _angle = Math.Max(Math.Min(_angle + (ee.Delta/30), 45), -45) 
            PanelMouseMove(s, ee) 
           End Sub 
     AddHandler p.MouseEnter, Sub(s As Object, ee As EventArgs) 
            CType(s, Control).Focus() 
           End Sub 


     AxDPVActiveX1.Parent.Controls.Add(p) 

. _curgray는 밝기가 조정 된 이미지이고 _curImg는 원래의 스크린 잡기입니다.

_curGray : enter image description here _curImg : enter image description here

mouseMove 이동 이벤트가 나의 새로운 그림 상자에 적용됩니다. 여기서 질문의 앞부분에 나오는 모든 코드가 작동합니다.

위의 코드를 사용하면 my mouseMove 이벤트가 내 그림 상자에 새로운 imageto 표시를 계속 생성합니다. 회전이 없다면, 내가 원하는 것을 거의 얻을 수 있습니다. 아래 이미지에서 스탬프의 배경이 모든 것보다 더 밝아지는 것을 확인하십시오. 파란 사각형 위에있는 부분은 약간 가볍습니다. 나는이 방법으로 시청자들의 눈을 끌기 위해이 영역을 사용하고 있습니다. 여기에 회전을 적용 할 때

enter image description here

그러나, 나는 원래 이미지에서 복사 할 수없는 것. 다음 이미지를 보아라, 배경은 그것과 함께 회전하지 않는다. 나는 원본 이미지에서 회전 된 사각형을 움켜 잡을 필요가있다.

enter image description here

http://msdn.microsoft.com/en-us/library/ms142040(v=vs.110).aspxGraphics.DrawImage()

은 받아 내가 (이 경우 _curImg에) 내 소스 이미지에서이 소스 사각형을 복사 지정하고 내 새 도면에 배치 할 수 있습니다

Public Sub DrawImage (_ 
    image As Image, _ 
    destRect As Rectangle, _ 
    srcRect As Rectangle, _ 
    srcUnit As GraphicsUnit _ 
) 

. 원본 사각형에 변형을 적용 할 수 없습니다. 기본적으로 (@larstech에서 변환을 기반으로) 회전 된 사각형에 해당하는 영역을 내 원본 이미지에서 복사하려고합니다.

이 개념을 더 명확하게 표현하는 방법을 모르겠습니다. 그래도 여전히 이해가되지 않는다면 나는 LarsTech의 대답을 최고의 대답으로 받아 들일 것이고, 나의 생각을 고칠 것이다.

+0

당신은 사각형의 점을 변환 할 수 있습니다. 새로운 사각형 (회전 된 텍스트 주변)은 모든 X의 x = min, 모든 Y의 y = min, width = maxX-minX 및 height = maxY-minY –

답변

1

나는 사각형과 함께 텍스트를 그리기 시도 할 것이다 :

Private Sub DrawStamp(g As Graphics, text As String, 
         f As Font, center As Point, angle As Integer) 
    Using m As New Matrix 
    g.SmoothingMode = SmoothingMode.AntiAlias 
    g.TextRenderingHint = TextRenderingHint.AntiAlias 
    m.RotateAt(angle, center) 
    g.Transform = m 
    Dim s As Size = g.MeasureString(text, f).ToSize 
    Dim r As New Rectangle(center.X - (s.Width/2) - 16, 
          center.Y - (s.Height/2) - 16, 
          s.Width + 32, 
          s.Height + 32) 
    g.FillRectangle(Brushes.White, r) 
    Using p As New Pen(Color.Black, 6) 
     g.DrawRectangle(p, r) 
    End Using 
    Using sf As New StringFormat 
     sf.LineAlignment = StringAlignment.Center 
     sf.Alignment = StringAlignment.Center 
     g.DrawString(text, f, Brushes.Black, r, sf) 
    End Using 
    g.ResetTransform() 
    End Using 
End Sub 

페인트 예 :

Protected Overrides Sub OnPaint(e As PaintEventArgs) 
    MyBase.OnPaint(e) 
    e.Graphics.Clear(Color.LightGray) 
    Using f As New Font("Calibri", 16, FontStyle.Bold) 
    DrawStamp(e.Graphics, 
       "Reviewed By Doctor Papa", 
       f, 
       New Point(Me.ClientSize.Width/2, Me.ClientSize.Height/2), 
       -25) 
    End Using 
End Sub 

결과 : 나는에 코드를 업데이트 여기

enter image description here

회전 된 사각형을 "클립"하여 t에서 같은 영역을 복사 할 수 있습니다. 텍스트 및 테두리를 적용하기 전에 그는 원본 이미지 :

Private Sub DrawStamp(g As Graphics, text As String, 
         f As Font, center As Point, angle As Integer) 

    Dim s As Size = g.MeasureString(text, f).ToSize 
    Dim r As New Rectangle(center.X - (s.Width/2) - 16, 
         center.Y - (s.Height/2) - 16, 
         s.Width + 32, 
         s.Height + 32) 

    Using bmp As New Bitmap(_curImg.Width, _curImg.Height) 
    Using gx As Graphics = Graphics.FromImage(bmp) 
     Using m As New Matrix 
     m.RotateAt(angle, center) 
     gx.Transform = m 
     gx.SetClip(r) 
     gx.ResetTransform() 
     End Using 
     gx.DrawImage(_curImg, Point.Empty) 
    End Using 
    g.DrawImage(bmp, Point.Empty) 
    End Using 

    Using m As New Matrix 
    g.SmoothingMode = SmoothingMode.AntiAlias 
    g.TextRenderingHint = TextRenderingHint.AntiAlias 
    m.RotateAt(angle, center) 
    g.Transform = m  
    Using p As New Pen(Color.Black, 6) 
     g.DrawRectangle(p, r) 
    End Using 
    Using sf As New StringFormat 
     sf.LineAlignment = StringAlignment.Center 
     sf.Alignment = StringAlignment.Center 
     g.DrawString(text, f, Brushes.Black, r, sf) 
    End Using 
    g.ResetTransform() 
    End Using 
End Sub 

새로운 결과 :

enter image description here

+0

입니다. 왜 내가 그런 생각을하지 않았는지 모르겠다. 그것을 시도하고 그것을 작동하는 방법을 볼 것이다 – pinkfloydx33

+0

사각형이 회전되고 ... 다른 이미지를 소스로 사용하여 회전 된 사각형을 소스 사각형으로 사용하여 g.DrawImage (...)를 호출하려고합니다. 내가 어떻게 할 수 있니? – pinkfloydx33

+0

@ pinkfloydx33 그 점을 잘 모르겠습니다. 내 예제에서는 양식의 페인트 이벤트에서 그래픽을 사용하고 있습니다. 그 그래픽 객체는 이미지의 그래픽 객체로 대체 될 수 있습니다. – LarsTech

1

그냥 삼각법의 :

enter image description here

원래 텍스트가 얼마나 넓은 알고 있기 때문에 당신은 c을 알고, 당신은 텍스트의 높이를 알고 있기 때문에 당신은 h을 알고있다. 또한 알파를 알아야합니다. 텍스트를 회전 한 각도입니다.

이제 수학의 힘을 사용해야합니다. 먼저 작은 사각형을 가져옵니다. 왼쪽 하단에서 x의 오른쪽이 실제로 180 ° -90 ° -alpha 또는 90 ° -alpha임을 알 수 있습니다. 따라서 알파는 반대 위치에서도 발견됩니다. 그래서 당신은 X 찾을 수 있습니다 : 같은 Y 간다

x = h * sin(alpha)

을하지만, 그건 하나의 죄 (90 ° - 알파), 또는 COS (알파)

y = h * cos(alpha)

다음을 수행해야 a와 b를 찾아 직사각형을 완성하십시오.

NewWidth = a + x
NewHeight = b + y

당신이 일 수 그런 식 : 큰 삼각형은

b = w * sin(alpha)

그럼 그냥 함께 부품을 추가하면

a = w * cos(alpha)

을 제공합니다 e 경계 상자의 크기. 좌표는 회전 된 텍스트를 인쇄 할 때 실제로 정의 된 점에 따라 다릅니다.