WPF: Allow user to resize images in RichTextBox - wpf

Is there a method within the RichTextBox control in WPF to allow for the user to resize inserted images, or do you have to devise your own method for this.
What I'm trying to achieve is shown below, a screenshot of a WordPad doing what I want:
Notes:
Reading the RTF file as plain text I find that the control tags related to image size is \picscalex100 and \picscaley100 (where 100 denotes scaled to 100%).
So yeah, is there a proper way or trick to this? Any advice on how to go about programming it? Or am I looking at the wrong control altogether?

Turns out you need to wrap your image in a ResizingAdorner.
A beautiful and simple implementation of this code can be found at http://msdn.microsoft.com/en-us/library/ms771714%28loband%29.aspx by Marco Zhou (second post).
The code for this ResizingAdorner is available as an MSDN sample at http://msdn.microsoft.com/en-us/library/ms771714%28loband%29.aspx
Here's a VB.net equivalent of the code I am now using
Dim img As Image
Sub AddImg() Handles btnAddImage.Click
Dim dlg As New Microsoft.Win32.OpenFileDialog
dlg.Filter = "Image Files(*.*) | *.*"
If dlg.ShowDialog Then
img = New Image
AddHandler img.Loaded, AddressOf imgloaded
img.Source = New BitmapImage(New Uri(dlg.FileName, UriKind.Absolute)) With {.CacheOption = BitmapCacheOption.OnLoad}
Dim container As New BlockUIContainer(img)
rtb.Document.Blocks.Add(container)
End If
End Sub
Private Sub imgloaded(ByVal sender As Object, ByVal e As Windows.RoutedEventArgs)
Dim al As AdornerLayer = AdornerLayer.GetAdornerLayer(img)
If Not (al Is Nothing) Then
al.Add(New SDKSample.ResizingAdorner(img))
End If
End Sub
The ResizingAdorner sample will require some great hacking to meet my needs, but what a great start.
Hope someone else finds this useful!

Maybe copy image to Paint and resize accordingly and then post to the RichTextBox in VB6. Images posted directly to VB6 tend to get distorted. Any image copied from Paint to VB6 is pasted as it was in Paint. I found this out when copying from a PDF image to a RichTextBox.

Related

How do you load every PictureBox on a form into an array?

I'm currently trying to find a way to change every PictureBox on my form to have the same image.
I have achieved this, but its messy, and I was wondering if there is a 'cleaner' way to do this (As I will need to dynamically fill the PictureBox array later on in my project).
Dim pbxCollection() As PictureBox = {PictureBox1, PictureBox2, PictureBox3, PictureBox4, PictureBox5, PictureBox6, PictureBox7, PictureBox8, PictureBox9} 'collection of all pictureboxes
For Each pbx In pbxCollection 'iterates through the PictureBox array and changes each value
pbx.Image = My.Resources.<image file name here>
Next
The above code does what I want, but as you can see, I have 9 PictureBoxes. In future I will need to have any number of PictureBoxes up to 50, so this solution will no longer work then.
If there is a way to fill an array with every PictureBox on a form, I will be extremely grateful.
Thanks.
Don't use an array, use an IEnumerable:
Dim pbxCollection = MyForm.Controls.OfType(Of PictureBox)()
Of course this is not recursive, so if there's a panel or group box you want to account for use that instead of MyForm. Also, make sure you run it after the InitializeComponent() method.
From the comments:
I'm using a tableLayoutPanel
So assuming a name of tableLayoutPanel1, it might look something like this:
Dim pbxCollection = tableLayoutPanel1.Controls.OfType(Of PictureBox)()

Direct2D With GDI+ Render Target Blending Transparent as Black

Reproduce the problem in this project:
https://github.com/adrotter/GDIDirect2DDualRenderer
I am trying to make Direct2D work with our current rendering engine, which is GDI+. I did this by abstracting all the calls to GDI+, and making a concrete class for GDI+ and for Direct2D. One issue that a lot of people seem to have is when you call Clear on the render target with a transparent color, you get completely opaque black background.
How do I clear a Direct2D render target to fully transparent
How to create a transparent bitmap in Direct2D
The answers from the above stack overflow posts suggest I need a WS_EX_LAYERED window, or using DirectComposition, but I am not sure if doing that would work well in WinForms. Besides, they are only talking about making the window transparent and not pixels on a bitmap. The solution I came up with that partially works is if there is a call to Graphics.Clear, and I have yet to start drawing using the render target, then I call Clear on the Drawing.Graphics object, and then start drawing. This will make the background completely transparent if I use Graphics.Clear(Color.Transparent) (fixes the problem people had with the black background).
Here is how that looks like with 100% opacity:
The color ramp on the left is Direct2D rendering, and the color ramp on the right is GDI+. They look similar, but the Direct2D looks darker. It gets worse.
Here's 50% opacity
1% opacity
Now this is why my solution partially works: 0% opacity works great. See here.
Now I don't actually think that the target blending black with transparent is a result of me calling Clear first with the System.Drawing.Graphics object first, because I tested the partial transparency without using my trick (I made no calls to GDI+ graphics at all). I would still get the same results as above for opacities 50 and 1. It seems like calling DrawBitmap using a bitmap with partial transparencies will always blend the partial transparent color with black.
For reference here is how my render target is being made:
Dim targetProperties As New RenderTargetProperties
targetProperties.Type = RenderTargetType.Default
targetProperties.PixelFormat = New Direct2D1.PixelFormat(Format.B8G8R8A8_UNorm, SharpDX.Direct2D1.AlphaMode.Premultiplied)
targetProperties.Usage = RenderTargetUsage.GdiCompatible
Dim factory = New Direct2D1.Factory()
_target = New DeviceContextRenderTarget(factory, targetProperties)
_target.BindDeviceContext(_graphics.GetHdc(), rec)
Also for reference here is how I turn a System.Drawing.Bitmap into a Direct2D1Bitmap:
Private Function GetDirect2DBitmap(bmp As System.Drawing.Bitmap) As SharpDX.Direct2D1.Bitmap
Dim bmpData As System.Drawing.Imaging.BitmapData = bmp.LockBits(
New System.Drawing.Rectangle(0, 0, bmp.Width, bmp.Height),
System.Drawing.Imaging.ImageLockMode.ReadOnly,
System.Drawing.Imaging.PixelFormat.Format32bppPArgb)
Dim stream As New SharpDX.DataStream(bmpData.Scan0, bmpData.Stride * bmpData.Height, True, False)
Dim pFormat As New SharpDX.Direct2D1.PixelFormat(SharpDX.DXGI.Format.B8G8R8A8_UNorm, Direct2D1.AlphaMode.Premultiplied)
Dim bmpProps As New SharpDX.Direct2D1.BitmapProperties(pFormat)
Dim result As New SharpDX.Direct2D1.Bitmap(
_targets(_selectedTargetIdx),
New SharpDX.Size2(bmp.Width, bmp.Height),
stream,
bmpData.Stride,
bmpProps)
bmp.UnlockBits(bmpData)
stream.Dispose()
Return result
End Function
And here is a simplification of getting my semi transparent bitmaps:
//using C# style comments so this looks prettier
//Make empty bitmap to draw on
dim canvasBMP = new System.Drawing.Bitmap(100,100)
//Make the bitmap that has partial transparent pixels
dim partialTransparentBMP as System.Drawing.Bitmap = GetSemiTransparentBMP(100,100)
Using g as System.Drawing.Graphics = Graphics.FromImage(canvasBMP)
g.Clear(Color.White)
dim d2dTarget = MakeRenderTarget(g, g.VisibleClipBounds)
d2dTarget.BeginDraw()
d2dTarget.DrawBitmap(GetDirect2DBitmap(partialTransparentBMP), GetDirect2DRect(...), 1.0F, BitmapInterpolationMode.Linear)
d2dTarget.EndDraw()
End Using
How do I get a white blended partial transparent pixel and not a black one using a GDI+ render target?

WPF Visual to XPS document method creates only one page

I have a WPF Window that I want to save to an XPS file (or really, any type of file that would store the window image). This window contains a lengthy DataGrid. So far I am able to write to an XPS file, but the resulting document contains only one page, so most of the DataGrid rows are missing. How can I get the XPSDocumentWriter to use as many pages as necessary?
Here is what I've got so far (I've turned off the grid scroll bar and autosized the window to make sure it is full-sized before writing to XPS file):
Dim visual = CType(Me.Content, Media.Visual)
Me.LogGrid.VerticalScrollBarVisibility = ScrollBarVisibility.Hidden
Me.SizeToContent = Windows.SizeToContent.WidthAndHeight
Dim xd As New System.Windows.Xps.Packaging.XpsDocument(file, IO.FileAccess.ReadWrite)
Dim xw = System.Windows.Xps.Packaging.XpsDocument.CreateXpsDocumentWriter(xd)
xw.Write(visual)
xd.Close()
I think Will's comment is probably the right answer.

How to interchange D3DImage between a WPF application and Windows (for Copy/Paste)?

I'm being working in making copy and paste operations on my diagramming application.
Therefore, I need to...
Convert a WPF Bitmap to a D3DImage (for later implement "Copy"), and
Convert a D3DImage to a WPF Bitmap (for later implement "Paste").
Notice that this requieres "Interop" between the WPF Application and the native Win-32.
How to do this, as short as possible (two functions, ideally)?
You probably found your answer in the past half year but here is how to convert a D3DImage in WPF to BitmapSource (I used vb.net in this case):
Public Function GetCurrentImage() As BitmapSource
Dim width As Integer = D3DImage.PixelWidth
Dim height As Integer = D3DImage.PixelHeight
Dim dv As New DrawingVisual()
Using dc As DrawingContext = dv.RenderOpen()
dc.DrawImage(D3DImage, New Rect(0, 0, width, height))
End Using
Dim rtb As New RenderTargetBitmap(width, height, 96, 96, PixelFormats.Pbgra32)
rtb.Render(dv)
Return BitmapFrame.Create(rtb)
End Function
You can find it in C# in the WPFMediaKit.
What do you mean by D3DImage?
There is a 'Control'/Surface in WPF that is named D3DImage but it feels as if you are referring to a bitmap format. Are you trying to put the data on the clipboard? If so you won't need interop. Just use the Clipboard API to put the image on the clipboard and read it from the clipboard.

Drag image within it's parent border?

I have created image viewer control, that provide zoom in/out the image, and when the image zoomed and be larger than it's viewer (you can't see all the image) I provided the ability to drag the image (like Windows Photo Viewer) using "TranslateTransform" but I wanna the image to stop dragging when it's border (left or right or left or down) is appeared, I have done some calculations of the width and height of the fourth sides and it's work fine but when you speedy drag the image it stop after it's border pass it's container border, and the distance increased by greater drag speed. For example: open an image in "Windows Photo Viewer" and zoomed it then drag it it's stop exactly when you reach it's border".
So I wanna the image to stop exactly when it's border appeared regardless of drag speed?
Appreciated your Helps,
Best Regards.
This looks like problem with your code. Can you just apply range check when you compute parameters for translate transform to avoid moving picture outside the region?
This is my code I have Image(name: imgView), insode grid(name: grdImage), I wanna the image(zoomed image) to move with mouse move in inside the Grid, and when it's borders reach the border of grid to stop, exactly like "Windows Photo Viewer". FYI: Im zoomed the image using the scaleTransform:
Private Sub imgView_MouseLeftButtonDown(ByVal sender As Object, ByVal e As MouseButtonEventArgs)
_IsMouseCapture = True
imgView.CaptureMouse()
Dim tt = DirectCast(DirectCast(imgView.RenderTransform, TransformGroup).Children.First(Function(tr) TypeOf tr Is TranslateTransform), TranslateTransform)
start = e.GetPosition(grdImage)
origin = New Point(tt.X, tt.Y)
End Sub
Private Sub imgView_MouseLeftButtonUp(ByVal sender As Object, ByVal e As MouseButtonEventArgs)
_IsMouseCapture = False
imgView.ReleaseMouseCapture()
End Sub
Private Sub imgView_MouseMove(ByVal sender As Object, ByVal e As MouseEventArgs)
If (Not _IsMouseCapture) Then
Return
End If
Dim tt = DirectCast(DirectCast(imgView.RenderTransform, TransformGroup).Children.First(Function(tr) TypeOf tr Is TranslateTransform), TranslateTransform)
Dim vx As Double = start.X - e.GetSafePosition(grdImage).X
Dim vy As Double = start.Y - e.GetSafePosition(grdImage).Y
tt.Y = origin.Y - vy
tt.X = origin.X - vx
End Sub`

Resources