Major Surgery to support FJCore jpeg library for making actually-good jpegs. Also bugfixing.
Major Surgery to support FJCore jpeg library for making actually-good jpegs. Also bugfixing.

--- a/ScreenshotManager.cs
+++ b/ScreenshotManager.cs
@@ -25,9 +25,15 @@
 // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
+//
+// This software uses the FJCore library, © 2008 Jeffrey Powers for Fluxcapacity Open Source.  Used under license.
+//
+
+using FluxJpeg.Core;
+using FluxJpeg.Core.Encoder;
 using KSP;
 using System;
+using System.Text;
 using System.Text.RegularExpressions;
 using ToadicusTools;
 using UnityEngine;
@@ -38,6 +44,7 @@
 	#region Fields
 
 	private ApplicationLauncherButton appLauncherButton;
+	private int jpegQuality;
 	private KeyCode realScreenshotKey;
 	private ScreenShotFormat ssFormat;
 	private string ssPath;
@@ -124,15 +131,18 @@
 				break;
 		}
 
+		this.jpegQuality = this.Config.GetValue("jpegQuality", 99);
+
 		string keyCodeString = this.Config.GetValue("TAKE_SCREENSHOT", Enum.GetName(typeof(KeyCode), KeyCode.F1)).Trim();
 		this.realScreenshotKey = (KeyCode)Enum.Parse(typeof(KeyCode), keyCodeString);
 
 		this.windowPosition = this.Config.GetValue("windowPosition",
-			new Rect(Screen.width * 1f / 8f, Screen.height * 3f / 8f, 320, 10));
+			new Rect(Screen.width * 1f / 8f, Screen.height * 3f / 8f, 240, 10));
 
 		this.Config.SetValue("Format", Enum.GetName(typeof(ScreenShotFormat), this.ssFormat));
 		this.Config.SetValue("TAKE_SCREENSHOT", Enum.GetName(typeof(KeyCode), this.realScreenshotKey));
 		this.Config.SetValue("windowPosition", this.windowPosition);
+		this.Config.SetValue("jpegQuality", this.jpegQuality);
 
 		this.Config.save();
 	}
@@ -162,18 +172,31 @@
 			this.windowVisible = false;
 		}
 
+		if (this.showWindow && this.windowVisible && this.windowPosition.Contains(Input.mousePosition))
+		{
+			InputLockManager.SetControlLock(ControlTypes.KSC_FACILITIES, "SSM_KSC");
+		}
+		else if (InputLockManager.GetControlLock("SSM_KSC") != ControlTypes.None)
+		{
+			InputLockManager.RemoveControlLock("SSM_KSC");
+		}
+
 		if (GameSettings.TAKE_SCREENSHOT.primary != KeyCode.None)
 		{
 			this.realScreenshotKey = GameSettings.TAKE_SCREENSHOT.primary;
 			GameSettings.TAKE_SCREENSHOT.primary = KeyCode.None;
-		}
-		else
-		{
-			GameSettings.TAKE_SCREENSHOT.primary = this.realScreenshotKey;
+			// GameSettings.SaveSettings();
 		}
 
 		if (Input.GetKeyUp(this.realScreenshotKey))
 		{
+			ScreenShotFormat currentFormat = this.ssFormat;
+
+			if (GameSettings.MODIFIER_KEY.GetKey())
+			{
+				this.SwitchFormats();
+			}
+
 			Texture2D screenshot;
 
 			screenshot = this.RenderScreenshot(this.TexFormat);
@@ -181,6 +204,11 @@
 			if (screenshot != null)
 			{
 				this.WriteTextureToFile(screenshot);
+			}
+
+			if (this.ssFormat != currentFormat)
+			{
+				this.ssFormat = currentFormat;
 			}
 
 			Debug.Log(string.Format("[{0}]: Screenshot!", this.GetType().Name));
@@ -195,6 +223,7 @@
 		if (this.realScreenshotKey != KeyCode.None)
 		{
 			GameSettings.TAKE_SCREENSHOT.primary = this.realScreenshotKey;
+			// GameSettings.SaveSettings();
 		}
 
 		if (this.toolbarButton != null)
@@ -216,12 +245,57 @@
 
 	#region Utility Methods
 
+	private void EncodeTextureToJpegStream(Texture2D tex, ref System.IO.FileStream stream)
+	{
+		var cm = new ColorModel();
+		cm.colorspace = FluxJpeg.Core.ColorSpace.RGB;
+
+		byte[][,] raster = Image.CreateRaster(tex.width, tex.height, 3);
+
+		byte[,] r = raster[0];
+		byte[,] g = raster[1];
+		byte[,] b = raster[2];
+
+		for (int x = 0; x < tex.width; x++)
+		{
+			for (int y = 0; y < tex.height; y++)
+			{
+				UnityEngine.Color32 uC = (Color32)tex.GetPixel(x, y);
+
+				int iy = (tex.height - 1) - y;
+
+				r[x, iy] = uC.r;
+				g[x, iy] = uC.g;
+				b[x, iy] = uC.b;
+			}
+		}
+
+		Image im = new Image(cm, raster);
+
+		JpegEncoder jpeg = new JpegEncoder(im, this.jpegQuality, stream);
+
+		jpeg.Encode();
+	}
+
 	private Texture2D RenderScreenshot(TextureFormat format)
 	{
 		Texture2D screenshot = new Texture2D(this.ScreenshotRes.x, this.ScreenshotRes.y, format, false);
 		screenshot.ReadPixels(new Rect(0, 0, this._screenRes.x, this._screenRes.y), 0, 0);
 
 		return screenshot;
+	}
+
+	private void SwitchFormats()
+	{
+		switch (this.ssFormat)
+		{
+			case ScreenShotFormat.JPG:
+				this.ssFormat = ScreenShotFormat.PNG;
+				break;
+			case ScreenShotFormat.PNG:
+				this.ssFormat = ScreenShotFormat.JPG;
+				break;
+		}
 	}
 
 	private bool WriteTextureToFile(Texture2D tex)
@@ -257,21 +331,19 @@
 			fs = System.IO.File.Open(System.IO.Path.Combine(this.ssPath, filename),
 				System.IO.FileMode.CreateNew);
 
-			binWriter = new System.IO.BinaryWriter(fs);
-
 			switch (this.ssFormat)
 			{
 				case ScreenShotFormat.JPG:
-					binWriter.Write(tex.EncodeToJPG());
+					this.EncodeTextureToJpegStream(tex, ref fs);
 					break;
 				case ScreenShotFormat.PNG:
+					binWriter = new System.IO.BinaryWriter(fs);
+
 					binWriter.Write(tex.EncodeToPNG());
 					break;
 				default:
 					throw new NotImplementedException("[SSM]: Only JPG and PNG formats are implemented.");
 			}
-
-			binWriter.Close();
 		}
 		catch (Exception ex)
 		{
@@ -304,7 +376,6 @@
 			this.toolbarButton = ToolbarManager.Instance.add("ScreenshotManager", "main");
 			this.toolbarButton.TexturePath = "SSM/ToolbarIcon";
 			this.toolbarButton.Text = "SSM";
-			this.toolbarButton.TextColor = Color.Lerp(Color.cyan, Color.blue, 0.5f);
 			this.toolbarButton.Visibility = new GameScenesVisibility(GameScenes.SPACECENTER);
 			this.toolbarButton.OnClick += ((ClickEvent e) => this.ButtonClickHandler());
 		}
@@ -316,8 +387,6 @@
 		{
 			return;
 		}
-
-		Debug.Log("[SSM]: Adding AppLauncher button.");
 
 		Texture2D appIcon;
 
@@ -367,15 +436,7 @@
 		GUILayout.FlexibleSpace();
 		if (GUILayout.Button(Enum.GetName(typeof(ScreenShotFormat), this.ssFormat)))
 		{
-			switch (this.ssFormat)
-			{
-				case ScreenShotFormat.JPG:
-					this.ssFormat = ScreenShotFormat.PNG;
-					break;
-				case ScreenShotFormat.PNG:
-					this.ssFormat = ScreenShotFormat.JPG;
-					break;
-			}
+			this.SwitchFormats();
 
 			this.Config.SetValue("Format", Enum.GetName(typeof(ScreenShotFormat), this.ssFormat));
 
@@ -383,6 +444,25 @@
 		}
 		GUILayout.EndHorizontal();
 
+		GUILayout.BeginHorizontal();
+		GUILayout.Label("JPEG Quality:");
+		GUILayout.FlexibleSpace();
+		GUILayout.Label(this.jpegQuality.ToString(), GUI.skin.textField);
+		GUILayout.EndHorizontal();
+
+		GUILayout.BeginHorizontal();
+
+		int newQuality = Mathf.RoundToInt(
+			GUILayout.HorizontalScrollbar(this.jpegQuality, 1, 1, 100, GUILayout.ExpandWidth(true))
+		);
+
+		if (newQuality != this.jpegQuality)
+		{
+			this.jpegQuality = newQuality;
+			this.Config.SetValue("jpegQuality", this.jpegQuality);
+		}
+		GUILayout.EndHorizontal();
+
 		GUILayout.EndVertical();
 
 		GUI.DragWindow();
@@ -397,10 +477,12 @@
 		if (scene == GameScenes.SETTINGS && this.realScreenshotKey != KeyCode.None)
 		{
 			GameSettings.TAKE_SCREENSHOT.primary = this.realScreenshotKey;
+			// GameSettings.SaveSettings();
 		}
 		else
 		{
 			GameSettings.TAKE_SCREENSHOT.primary = KeyCode.None;
+			// GameSettings.SaveSettings();
 		}
 	}
 

--- a/ScreenshotManager.csproj
+++ b/ScreenshotManager.csproj
@@ -10,6 +10,7 @@
     <RootNamespace>ScreenshotManager</RootNamespace>
     <AssemblyName>ScreenshotManager</AssemblyName>
     <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
+    <UseMSBuildEngine>False</UseMSBuildEngine>
   </PropertyGroup>
   <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
     <DebugSymbols>true</DebugSymbols>
@@ -28,10 +29,11 @@
     <WarningLevel>4</WarningLevel>
     <CustomCommands>
       <CustomCommands>
-        <Command type="AfterBuild" command="xcopy /Y ${TargetFile} ..\..\..\Games\KSP_win\GameData\SSM\Plugins\" />
+        <Command type="AfterBuild" command="robocopy.bat ${TargetDir}\ C:\Users\andy\Games\KSP_win\GameData\SSM\ /s ${TargetName} FJCore.dll" />
       </CustomCommands>
     </CustomCommands>
     <ConsolePause>false</ConsolePause>
+    <DefineConstants>SILVERLIGHT</DefineConstants>
   </PropertyGroup>
   <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release (linux)|AnyCPU' ">
     <Optimize>true</Optimize>
@@ -72,4 +74,10 @@
       <Link>IOTools.cs</Link>
     </Compile>
   </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\FJCore\FJCore.csproj">
+      <Project>{6F58E78E-26D6-4676-B370-E9A69B8A67BC}</Project>
+      <Name>FJCore</Name>
+    </ProjectReference>
+  </ItemGroup>
 </Project>