-- Leo's gemini proxy
-- Connecting to g.mikf.pl:1965...
-- Connected
-- Sending request
-- Meta line: 20 text/gemini
Used a template for creating WinForms application.
Added a ComboBox in top left corner, set its anchoring to Top Left in Properties
Added a StatusStrip and a single StatusLabel to it, on the bottom of the window
Added a NumericUpDown so that it aligned to StatusStrip and left edge, anchoring Bottom Left
Added a TrackBar, set its orientation to Vertical, aligned it to ComboBox and NumericUpDown, set its anchoring to Top Bottom Left
took TrackBar width down to 101 (minimum), then aligned the widths of ComboBox and NumericUpDown to it
Added a PictureBox, aligned it with TrackBar to the left, top of the window from the top, window edge on the right, and StatusStrip on the bottom, set anchoring to Top Bottom Left Right
Set TrackBar's Maximum to 100. Minimum was already set to 0, and so was Maximum set to 100 in case of NumericUpDown.
Set ComboBox Collection Property to contain just one element, "JPG"
I switched the Properties pane to the events view and clicked twice on ValueChanged for both NumericUpDown and TrackBar to have them autoassigned
Private valueChangeSource As Object = Nothing Private Sub TrackBar1_ValueChanged(sender As Object, e As EventArgs) Handles TrackBar1.ValueChanged If valueChangeSource Is Nothing Then valueChangeSource = TrackBar1 ElseIf valueChangeSource Is TrackBar1 Then valueChangeSource = Nothing Return End If NumericUpDown1.Value = TrackBar1.Value End Sub Private Sub NumericUpDown1_ValueChanged(sender As Object, e As EventArgs) Handles NumericUpDown1.ValueChanged If valueChangeSource Is Nothing Then valueChangeSource = NumericUpDown1 ElseIf valueChangeSource Is NumericUpDown1 Then valueChangeSource = Nothing Return End If TrackBar1.Value = NumericUpDown1.Value End Sub
`Nothing` is actually a value of Nullable, don't do this.
I could also probably use the `sender` parameter to deduplicate this code more or less neatly.
This is just the code to keep them in sync.
Added an OpenFileDialog. Autoassigned a new handler for its FileOk event
Dim original As Image = New System.Drawing.Bitmap(100, 100) Private Sub OpenFileDialog1_FileOk(sender As OpenFileDialog, e As System.ComponentModel.CancelEventArgs) Handles OpenFileDialog1.FileOk original = Image.FromFile(sender.FileName) End Sub
Yes it creates a dummy bitmap first, that maybe is not needed but is neat.
It now turns out that the Image.Save method, to accept EncoderParameters so that we can pick the quality instead of the default, requires us to not use ImageFormat but ImageCodecInfo. Help came from the documentation example of EncoderParameter class usage, specifically the GetEncoder function from there, although I wrote it out differently:
Function Codec() As Imaging.ImageCodecInfo 'If ComboBox1.SelectedValue = "" Then ' ComboBox1.SelectedValue = "JPG" 'End If 'If Not ComboBox1.SelectedValue = "JPG" Then ' Throw New ArgumentException 'End If Dim format As ImageFormat = ImageFormat.Jpeg Dim codecs = Imaging.ImageCodecInfo.GetImageEncoders Dim result = (From approached In codecs Select approached Where approached.FormatID = format.Guid ).First Return result End Function
This is supposed to handle the ComboBox selection. It's so far non-functional. Would be for picking other lossy formats someday. Such as `ImageFormat.Webp` or `ImageFormat.Heif`.
If you want, remove the ComboBox and resize&anchor the TrackBar to the top of the window.
The other parameter to our `Image.Save` will be EncoderParameters:
Function Params() As EncoderParameters Dim obj = New EncoderParameters(1) Dim quality As Long = NumericUpDown1.Value Dim param = New EncoderParameter( Encoder.Quality, quality) obj.Param(0) = param Return obj End Function
Now what's left is to generate and preview the compressed image:
Dim compressed As Byte() Sub Render() Dim stream = New MemoryStream original.Save(stream, Codec, Params) compressed = stream.ToArray Dim img = Image.FromStream(stream) PictureBox1.Image = img stream.Dispose() End Sub
And add a call to `Render()` at the end of the both ValueChanged and FileOk handlers.
The `compressed` field is so far unused but this is our original compression output, as lossy compression could be non-deterministic and come out differently each time. We are to be saving it to file to achieve full functionality.
And for the last thing, we need our application to start with asking for a file:
Select Form1 in the properties editor, switch view to events, and double click the Load event to autoassign a handler for it.
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load OpenFileDialog1.ShowDialog() End Sub
I really hope I hadn't omitted anything. Many things need yet to be done, including drag move around, scaling. PictureBox image ("client controllers") can be drag-moved by making handlers to set a variable on MouseUp and MouseDown, and a MouseMove handler to add `e.x` to PictureBox.Left and so on. Scaling could be handled with MouseWheel.
Saving the byte array to a file will be trivial, can be triggered by a click to the image, or by handling window close event (and making the closing procedure be to cancel the file save dialog, for example), or by a keyboard shortcut.
Many things need to be polished, like the default filenames in file chooser, filetype filters in the chooser... But we wanted a thing quick to hack and we got it. Many optimization can be made but are not needed. TabStop of TrackBar could be set to one or a different value, but not necessarily, as it reduces the wastefulness of resources. Asynchronicity could be introduced, especially considering large images, would probably be needed for responsiveness.
And one of the most needed features that I only now remembered from the Android app JPEG Optimizer (com.mixaimaging.jpeg.optimizerfree) would be to have resizing of images as part of the compressing. Having live preview of a selection of downscaling algorithms would be so so cool.
Oh, and yeah, the StatusStrip is to be for showing the file sizes and original resolution.
EOF
-- Response ended
-- Page fetched on Tue May 21 19:03:36 2024