mirror of
https://github.com/riegera2412/UVtools.git
synced 2026-07-08 17:42:31 +02:00
v3.9.0
- **File formats:** - (Add) File extension: .gktwo.ctb to `ChituboxFile` to be able to convert files for UniFormation GKtwo under special CTB format - (Add) UniFormation GKtwo compatibility under CTB format, if exporting JXS rename to CTB before open - (Fix) CTB, CBDDLP, PHOTON, FDG, PHZ: Read and write files larger then 4GB (#608) - **PCB Exposure:** - (Add) Offset X/Y to offset the PCB from it origin - (Add) Allow to toggle between "Show preview image cropped by it bounds" and "Show full preview image (The final result)" - (Improvement) Use rectangle instead of line for center line primitive (#607) - (Fix) Implement rotation to polygon and center line primitives (#607) - (Fix) Macros in a single line was not being parsed (#607) - (Fix) Invert color per file was not affecting primitives - **Network printers:** - (Add) Socket requests with TCP and UDP - (Add) AnyCubic printer preset (However it can't upload a file) - (Add) Scripts in request path to allow a first request to fetch data to the final request: - A script starts with **<\?** and ends with **?>** - First parameter is the first request to get response content from - Second parameter is the regex pattern to match content with - Third parameter is the final request that supports a parameter from regex matching group, eg: **{#1}** is match Group[1] value - **Example:** <\? getfiles > {0}\/(\d+\.[\da-zA-Z]+), > printfile,{#1} ?> - (Change) Allow to print a filename without send it when upload request path is empty - (Fix) Do not show printers with empty requests - (Change) Default layer compression to Lz4 instead of Png - (Improvement) Application is now culture aware but set part of `NumberFormat` to the `InvariantCulture.NumberFormat` - (Improvement) Material cost now show with the current culture currency symbol due previous change - (Improvement) Better submit of bug reports using sections and forms - (Improvement) Linux: AppImage now have a help manual with possible arguments and parameters - (Improvement) macOS: Codesign app on auto-installer and auto-upgrade to bypass arm64 run restriction (#431) - (Improvement) macOS: Rebuilt arm64 libcvextern.dylib to run with less dependencies (#431) - (Improvement) macOS: Try to show missing dependencies from openCV (if any) on the error message - (Fix) UI: layers sorted lexicographically instead of numerically in the issues list view (#611) - (Fix) PrusaSlicer printer parameters: UniFormation GKtwo
This commit is contained in:
@@ -1,5 +1,40 @@
|
||||
# Changelog
|
||||
|
||||
## 01/12/2022 - v3.9.0
|
||||
|
||||
- **File formats:**
|
||||
- (Add) File extension: .gktwo.ctb to `ChituboxFile` to be able to convert files for UniFormation GKtwo under special CTB format
|
||||
- (Add) UniFormation GKtwo compatibility under CTB format, if exporting JXS rename to CTB before open
|
||||
- (Fix) CTB, CBDDLP, PHOTON, FDG, PHZ: Read and write files larger then 4GB (#608)
|
||||
- **PCB Exposure:**
|
||||
- (Add) Offset X/Y to offset the PCB from it origin
|
||||
- (Add) Allow to toggle between "Show preview image cropped by it bounds" and "Show full preview image (The final result)"
|
||||
- (Improvement) Use rectangle instead of line for center line primitive (#607)
|
||||
- (Fix) Implement rotation to polygon and center line primitives (#607)
|
||||
- (Fix) Macros in a single line was not being parsed (#607)
|
||||
- (Fix) Invert color per file was not affecting primitives
|
||||
- **Network printers:**
|
||||
- (Add) Socket requests with TCP and UDP
|
||||
- (Add) AnyCubic printer preset (However it can't upload a file)
|
||||
- (Add) Scripts in request path to allow a first request to fetch data to the final request:
|
||||
- A script starts with **<\?** and ends with **?>**
|
||||
- First parameter is the first request to get response content from
|
||||
- Second parameter is the regex pattern to match content with
|
||||
- Third parameter is the final request that supports a parameter from regex matching group, eg: **{#1}** is match Group[1] value
|
||||
- **Example:** <\? getfiles > {0}\/(\d+\.[\da-zA-Z]+), > printfile,{#1} ?>
|
||||
- (Change) Allow to print a filename without send it when upload request path is empty
|
||||
- (Fix) Do not show printers with empty requests
|
||||
- (Change) Default layer compression to Lz4 instead of Png
|
||||
- (Improvement) Application is now culture aware but set part of `NumberFormat` to the `InvariantCulture.NumberFormat`
|
||||
- (Improvement) Material cost now show with the current culture currency symbol due previous change
|
||||
- (Improvement) Better submit of bug reports using sections and forms
|
||||
- (Improvement) Linux: AppImage now have a help manual with possible arguments and parameters
|
||||
- (Improvement) macOS: Codesign app on auto-installer and auto-upgrade to bypass arm64 run restriction (#431)
|
||||
- (Improvement) macOS: Rebuilt arm64 libcvextern.dylib to run with less dependencies (#431)
|
||||
- (Improvement) macOS: Try to show missing dependencies from openCV (if any) on the error message
|
||||
- (Fix) UI: layers sorted lexicographically instead of numerically in the issues list view (#611)
|
||||
- (Fix) PrusaSlicer printer parameters: UniFormation GKtwo
|
||||
|
||||
## 10/11/2022 - v3.8.3
|
||||
|
||||
- **UVtoolsCmd:**
|
||||
|
||||
+2
-1
@@ -74,4 +74,5 @@
|
||||
- Patrick Hofmann
|
||||
- Ajilus
|
||||
- James F Hammond
|
||||
- Steven Woodward
|
||||
- Steven Woodward
|
||||
- Piotr Czerkasow
|
||||
+32
-18
@@ -1,19 +1,33 @@
|
||||
- **UVtoolsCmd:**
|
||||
- **print-properties:**
|
||||
- (Change) `-b`, `--base` option to `-a`, `-all` to indicate all properties and sub-properties, now defaults to only show base properties
|
||||
- (Add) `-r`, `--range` option to prints only the matching layer(s) index(es) in a range
|
||||
- (Add) `-i`, `--indexes` option to prints only the matching layer(s) index(es)
|
||||
- (Add) Command: `set-properties <input-file> <property=value> Set properties in a file or to it layers with new values`
|
||||
- (Add) Command: `print-issues <input-file> Detect and print issues in a file`
|
||||
- (Add) New option to the `run` command: `-p, --property <property=value> Set a property with a new value (Compatible with operations only)`
|
||||
- (Remove) Command: `print-layers` as it has been moved to `print-properties`, use `-r :` to obtain same result as default on `print-layers`
|
||||
- **Issues:**
|
||||
- (Fix) Issues groups with only one issue was displaying the wrong area value
|
||||
- (Fix) Volume incorrectly calculated, resulting in a high value for group of issues
|
||||
- (Fix) Incorrect calculation of the bounding rectangle for a group of issues
|
||||
- **Repair layers:**
|
||||
- (Add) Switch to opt between "Re-detect the selected issues before repair" and "Use and repair the previous detected issues" (Default)
|
||||
- (Improvement) Do not allow to run the tool if there are no detected issues when the option "Use and repair the previous detected issues" is selected
|
||||
- (Improvement) Linux: Recompile libcvextern.so on a older system to be able to run on both older and newest system (#603)
|
||||
- (Upgrade) .NET from 6.0.10 to 6.0.11
|
||||
- **File formats:**
|
||||
- (Add) File extension: .gktwo.ctb to `ChituboxFile` to be able to convert files for UniFormation GKtwo under special CTB format
|
||||
- (Add) UniFormation GKtwo compatibility under CTB format, if exporting JXS rename to CTB before open
|
||||
- (Fix) CTB, CBDDLP, PHOTON, FDG, PHZ: Read and write files larger then 4GB (#608)
|
||||
- **PCB Exposure:**
|
||||
- (Add) Offset X/Y to offset the PCB from it origin
|
||||
- (Add) Allow to toggle between "Show preview image cropped by it bounds" and "Show full preview image (The final result)"
|
||||
- (Improvement) Use rectangle instead of line for center line primitive (#607)
|
||||
- (Fix) Implement rotation to polygon and center line primitives (#607)
|
||||
- (Fix) Macros in a single line was not being parsed (#607)
|
||||
- (Fix) Invert color per file was not affecting primitives
|
||||
- **Network printers:**
|
||||
- (Add) Socket requests with TCP and UDP
|
||||
- (Add) AnyCubic printer preset (However it can't upload a file)
|
||||
- (Add) Scripts in request path to allow a first request to fetch data to the final request:
|
||||
- A script starts with **<\?** and ends with **?>**
|
||||
- First parameter is the first request to get response content from
|
||||
- Second parameter is the regex pattern to match content with
|
||||
- Third parameter is the final request that supports a parameter from regex matching group, eg: **{#1}** is match Group[1] value
|
||||
- **Example:** <\? getfiles > {0}\/(\d+\.[\da-zA-Z]+), > printfile,{#1} ?>
|
||||
- (Change) Allow to print a filename without send it when upload request path is empty
|
||||
- (Fix) Do not show printers with empty requests
|
||||
- (Change) Default layer compression to Lz4 instead of Png
|
||||
- (Improvement) Application is now culture aware but set part of `NumberFormat` to the `InvariantCulture.NumberFormat`
|
||||
- (Improvement) Material cost now show with the current culture currency symbol due previous change
|
||||
- (Improvement) Better submit of bug reports using sections and forms
|
||||
- (Improvement) Linux: AppImage now have a help manual with possible arguments and parameters
|
||||
- (Improvement) macOS: Codesign app on auto-installer and auto-upgrade to bypass arm64 run restriction (#431)
|
||||
- (Improvement) macOS: Rebuilt arm64 libcvextern.dylib to run with less dependencies (#431)
|
||||
- (Improvement) macOS: Try to show missing dependencies from openCV (if any) on the error message
|
||||
- (Fix) UI: layers sorted lexicographically instead of numerically in the issues list view (#611)
|
||||
- (Fix) PrusaSlicer printer parameters: UniFormation GKtwo
|
||||
|
||||
|
||||
@@ -163,7 +163,7 @@ struct LAYER_DATA {
|
||||
float LightOffSeconds <fgcolor=cBlack, bgcolor=cRed>;
|
||||
uint DataAddress <fgcolor=cBlack, bgcolor=cRed>;
|
||||
uint DataSize <fgcolor=cBlack, bgcolor=cRed>;
|
||||
uint Unknown1 <fgcolor=cBlack, bgcolor=cRed>;
|
||||
uint PageNumber <fgcolor=cBlack, bgcolor=cRed>;
|
||||
uint TableSize <fgcolor=cBlack, bgcolor=cRed>;
|
||||
uint Unknown3 <fgcolor=cBlack, bgcolor=cRed>;
|
||||
uint Unknown4 <fgcolor=cBlack, bgcolor=cRed>;
|
||||
@@ -205,11 +205,11 @@ struct LAYERS {
|
||||
|
||||
if(header.Version >= 3)
|
||||
{
|
||||
FSeek(layerData.DataAddress - 84);
|
||||
FSeek(layerData.PageNumber * 4294967296 + layerData.DataAddress - 84);
|
||||
LAYER_DATAEX layerDataEx;
|
||||
}
|
||||
|
||||
FSeek(layerData.DataAddress);
|
||||
FSeek(layerData.PageNumber * 4294967296 + layerData.DataAddress);
|
||||
LAYER_RLE layerRLE(layerData.DataSize);
|
||||
FSeek(currentPos);
|
||||
}
|
||||
|
||||
@@ -126,7 +126,7 @@ FSeek(decryptedHeader.LayerTableOffset);
|
||||
|
||||
struct LAYER_POINTER {
|
||||
uint Offset;
|
||||
uint Padding1;
|
||||
uint PageNumber;
|
||||
uint LayerTableSize;
|
||||
uint Padding2;
|
||||
} layerPointers[decryptedHeader.LayerCount];
|
||||
@@ -137,7 +137,7 @@ struct LAYER_HEADER{
|
||||
float ExposureTime;
|
||||
float LightOffDelay;
|
||||
uint LayerDataOffset;
|
||||
uint unknown2;
|
||||
uint PageNumber;
|
||||
uint LayerDataLength;
|
||||
uint unknown3;
|
||||
uint EncryptedDataOffset;
|
||||
@@ -158,7 +158,7 @@ struct LAYER_HEADER{
|
||||
|
||||
struct LAYER {
|
||||
LAYER_HEADER layerHeader;
|
||||
FSeek(layerHeader.LayerDataOffset);
|
||||
FSeek(layerHeader.PageNumber * 4294967296 + layerHeader.LayerDataOffset);
|
||||
|
||||
/* do we have encrypted data? */
|
||||
if (layerHeader.EncryptedDataLength > 0) {
|
||||
@@ -180,7 +180,7 @@ struct LAYER {
|
||||
struct LAYERS {
|
||||
local uint x;
|
||||
for(x = 0; x < decryptedHeader.LayerCount; x++) {
|
||||
FSeek(layerPointers[x].Offset);
|
||||
FSeek(layerPointers[x].PageNumber * 4294967296 + layerPointers[x].Offset);
|
||||
LAYER layer;
|
||||
}
|
||||
} layers;
|
||||
|
||||
@@ -70,7 +70,7 @@ FSeek(curOffset);
|
||||
|
||||
struct LAYER_POINTER {
|
||||
uint Offset <format=hex>;
|
||||
uint Padding1;
|
||||
uint PageNumber;
|
||||
uint LayerTableSize;
|
||||
uint Padding2;
|
||||
} layerPointers[layerCount];
|
||||
@@ -81,9 +81,9 @@ struct LAYER_HEADER{
|
||||
float ExposureTime;
|
||||
float LightOffDelay;
|
||||
uint LayerDataOffset;
|
||||
uint unknown2;
|
||||
uint PageNumber;
|
||||
uint LayerDataLength;
|
||||
ubyte unknown3[4];
|
||||
uint Unknown;
|
||||
uint EncryptedDataOffset;
|
||||
uint EncryptedDataLength;
|
||||
float LiftHeight;
|
||||
@@ -102,7 +102,7 @@ struct LAYER_HEADER{
|
||||
|
||||
struct LAYER {
|
||||
LAYER_HEADER layerHeader;
|
||||
FSeek(layerHeader.LayerDataOffset);
|
||||
FSeek(layerHeader.PageNumber * 4294967296 + layerHeader.LayerDataOffset);
|
||||
|
||||
/* do we have encrypted data? */
|
||||
if (layerHeader.EncryptedDataLength > 0) {
|
||||
@@ -124,7 +124,7 @@ struct LAYER {
|
||||
struct LAYERS {
|
||||
local uint x;
|
||||
for(x = 0; x < layerCount; x++) {
|
||||
FSeek(layerPointers[x].Offset);
|
||||
FSeek(layerPointers[x].PageNumber * 4294967296 + layerPointers[x].Offset);
|
||||
LAYER layer;
|
||||
}
|
||||
} layers;
|
||||
|
||||
@@ -101,7 +101,7 @@ struct LAYER_DATA {
|
||||
float LightOffSeconds <fgcolor=cBlack, bgcolor=cRed>;
|
||||
uint DataAddress <fgcolor=cBlack, bgcolor=cRed>;
|
||||
uint DataSize <fgcolor=cBlack, bgcolor=cRed>;
|
||||
uint Unknown <fgcolor=cBlack, bgcolor=cRed>;
|
||||
uint PageNumber <fgcolor=cBlack, bgcolor=cRed>;
|
||||
uint Unknown <fgcolor=cBlack, bgcolor=cRed>;
|
||||
uint Unknown <fgcolor=cBlack, bgcolor=cRed>;
|
||||
uint Unknown <fgcolor=cBlack, bgcolor=cRed>;
|
||||
@@ -119,7 +119,7 @@ struct LAYERS {
|
||||
for( i = 0; i < header.LayerCount; i++ ){
|
||||
LAYER_DATA layerData <fgcolor=cBlack, bgcolor=cYellow>;
|
||||
currentPos = FTell();
|
||||
FSeek(layerData.DataAddress);
|
||||
FSeek(layerData.PageNumber * 4294967296 + layerData.DataAddress);
|
||||
LAYER_RLE layerRLE(layerData.DataSize);
|
||||
FSeek(currentPos);
|
||||
}
|
||||
|
||||
@@ -101,7 +101,7 @@ struct LAYER_DATA {
|
||||
float LightOffSeconds <fgcolor=cBlack, bgcolor=cRed>;
|
||||
uint DataAddress <fgcolor=cBlack, bgcolor=cRed>;
|
||||
uint DataSize <fgcolor=cBlack, bgcolor=cRed>;
|
||||
uint Unknown <fgcolor=cBlack, bgcolor=cRed>;
|
||||
uint PageNumber <fgcolor=cBlack, bgcolor=cRed>;
|
||||
uint Unknown <fgcolor=cBlack, bgcolor=cRed>;
|
||||
uint Unknown <fgcolor=cBlack, bgcolor=cRed>;
|
||||
uint Unknown <fgcolor=cBlack, bgcolor=cRed>;
|
||||
@@ -119,7 +119,7 @@ struct LAYERS {
|
||||
for( i = 0; i < header.LayerCount; i++ ){
|
||||
LAYER_DATA layerData <fgcolor=cBlack, bgcolor=cYellow>;
|
||||
currentPos = FTell();
|
||||
FSeek(layerData.DataAddress);
|
||||
FSeek(layerData.PageNumber * 4294967296 + layerData.DataAddress);
|
||||
LAYER_RLE layerRLE(layerData.DataSize);
|
||||
FSeek(currentPos);
|
||||
}
|
||||
|
||||
+10
-10
@@ -14,6 +14,11 @@ api_url="https://api.github.com/repos/sn4k3/UVtools/releases/latest"
|
||||
dependencies_url="https://raw.githubusercontent.com/sn4k3/UVtools/master/Scripts/install-dependencies.sh"
|
||||
macOS_least_version='10.15'
|
||||
|
||||
if [ "$arch" != "x86_64" -a "$arch" != "arm64" ]; then
|
||||
echo "Error: Unsupported host arch $arch"
|
||||
exit -1
|
||||
fi
|
||||
|
||||
version() { echo "$@" | awk -F. '{ printf("%d%03d%03d%03d\n", $1,$2,$3,$4); }'; }
|
||||
testcmd() { command -v "$1" &> /dev/null; }
|
||||
get_filesize() {
|
||||
@@ -29,19 +34,19 @@ get_filesize() {
|
||||
}
|
||||
downloaduvtools(){
|
||||
if [ -z "$1" ]; then
|
||||
echo "Download url was not specified"
|
||||
echo 'Error: Download url was not specified!'
|
||||
exit -1
|
||||
fi
|
||||
|
||||
filename="$(basename "${download_url}")"
|
||||
tmpfile="$(mktemp "${TMPDIR:-/tmp}"/UVtoolsUpdate.XXXXXXXX)"
|
||||
|
||||
echo "Downloading: $download_url"
|
||||
echo "- Downloading: $download_url"
|
||||
curl -L --retry 4 $download_url -o "$tmpfile"
|
||||
|
||||
download_size="$(curl -sLI $download_url | grep -i Content-Length | awk 'END{print $2}' | tr -d '\r')"
|
||||
if [ -n "$download_size" ]; then
|
||||
echo "- Validating file"
|
||||
echo '- Validating file'
|
||||
local filesize="$(get_filesize "$tmpfile")"
|
||||
if [ "$download_size" -ne "$filesize" ]; then
|
||||
echo "Error: File verification failed, expecting $download_size bytes but downloaded $filesize bytes. Please re-run the script."
|
||||
@@ -50,17 +55,12 @@ downloaduvtools(){
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "- Kill instances"
|
||||
echo '- Kill instances'
|
||||
killall UVtools 2> /dev/null
|
||||
ps -ef | grep '.*dotnet.*UVtools.dll' | grep -v grep | awk '{print $2}' | xargs kill 2> /dev/null
|
||||
sleep 0.5
|
||||
}
|
||||
|
||||
if [ "$arch" != "x86_64" -a "$arch" != "arm64" ]; then
|
||||
echo "Error: Unsupported host arch $arch"
|
||||
exit -1
|
||||
fi
|
||||
|
||||
echo ' _ ___ ___ _ '
|
||||
echo ' | | | \ \ / / |_ ___ ___ | |___ '
|
||||
echo ' | | | |\ \ / /| __/ _ \ / _ \| / __|'
|
||||
@@ -91,7 +91,7 @@ if [ -z "$osVariant" ]; then
|
||||
exit -1
|
||||
fi
|
||||
|
||||
echo "- Detected: $osVariant $arch"
|
||||
echo "- $osVariant $arch"
|
||||
|
||||
if [ "$osVariant" == "osx" ]; then
|
||||
#############
|
||||
|
||||
@@ -33,7 +33,8 @@ internal class Program
|
||||
|
||||
public static async Task<int> Main(params string[] args)
|
||||
{
|
||||
Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture;
|
||||
|
||||
Thread.CurrentThread.CurrentCulture = CoreSettings.OptimalCultureInfo;
|
||||
Args = args;
|
||||
|
||||
var rootCommand = new RootCommand("MSLA/DLP, file analysis, repair, conversion and manipulation")
|
||||
|
||||
@@ -1,42 +1,42 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<AssemblyName>UVtoolsCmd</AssemblyName>
|
||||
<ApplicationIcon>UVtools.ico</ApplicationIcon>
|
||||
<Version>1.0.5</Version>
|
||||
<Authors>Tiago Conceição, sn4k3</Authors>
|
||||
<Company>PTRTECH</Company>
|
||||
<PackageLicenseFile>LICENSE</PackageLicenseFile>
|
||||
<RepositoryUrl>https://github.com/sn4k3/UVtools</RepositoryUrl>
|
||||
<PackageIcon>UVtools.png</PackageIcon>
|
||||
<PackageProjectUrl>https://github.com/sn4k3/UVtools</PackageProjectUrl>
|
||||
<Description>MSLA/DLP, file analysis, repair, conversion and manipulation</Description>
|
||||
<Copyright>Copyright © 2020 PTRTECH</Copyright>
|
||||
<RepositoryType>Git</RepositoryType>
|
||||
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
|
||||
<Platforms>AnyCPU;x64</Platforms>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<AssemblyName>UVtoolsCmd</AssemblyName>
|
||||
<ApplicationIcon>UVtools.ico</ApplicationIcon>
|
||||
<Version>1.0.5</Version>
|
||||
<Authors>Tiago Conceição, sn4k3</Authors>
|
||||
<Company>PTRTECH</Company>
|
||||
<PackageLicenseFile>LICENSE</PackageLicenseFile>
|
||||
<RepositoryUrl>https://github.com/sn4k3/UVtools</RepositoryUrl>
|
||||
<PackageIcon>UVtools.png</PackageIcon>
|
||||
<PackageProjectUrl>https://github.com/sn4k3/UVtools</PackageProjectUrl>
|
||||
<Description>MSLA/DLP, file analysis, repair, conversion and manipulation</Description>
|
||||
<Copyright>Copyright © 2020 PTRTECH</Copyright>
|
||||
<RepositoryType>Git</RepositoryType>
|
||||
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
|
||||
<Platforms>AnyCPU;x64</Platforms>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="System.CommandLine" Version="2.0.0-beta4.22272.1" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="System.CommandLine" Version="2.0.0-beta4.22272.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\UVtools.Core\UVtools.Core.csproj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\UVtools.Core\UVtools.Core.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="..\LICENSE">
|
||||
<Pack>True</Pack>
|
||||
<PackagePath></PackagePath>
|
||||
</None>
|
||||
<None Include="..\UVtools.GUI\UVtools.png">
|
||||
<Pack>True</Pack>
|
||||
<PackagePath></PackagePath>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="..\LICENSE">
|
||||
<Pack>True</Pack>
|
||||
<PackagePath></PackagePath>
|
||||
</None>
|
||||
<None Include="..\UVtools.GUI\UVtools.png">
|
||||
<Pack>True</Pack>
|
||||
<PackagePath></PackagePath>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
using Emgu.CV.Cuda;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
@@ -26,6 +27,21 @@ public static class CoreSettings
|
||||
|
||||
#region Properties
|
||||
|
||||
public static CultureInfo OptimalCultureInfo
|
||||
{
|
||||
get
|
||||
{
|
||||
var cultureInfo = (CultureInfo)CultureInfo.CurrentCulture.Clone();
|
||||
cultureInfo.NumberFormat.CurrencyDecimalSeparator = CultureInfo.InvariantCulture.NumberFormat.CurrencyDecimalSeparator;
|
||||
cultureInfo.NumberFormat.CurrencyGroupSeparator = CultureInfo.InvariantCulture.NumberFormat.CurrencyGroupSeparator;
|
||||
cultureInfo.NumberFormat.NumberDecimalSeparator = CultureInfo.InvariantCulture.NumberFormat.NumberDecimalSeparator;
|
||||
cultureInfo.NumberFormat.NumberGroupSeparator = CultureInfo.InvariantCulture.NumberFormat.NumberGroupSeparator;
|
||||
cultureInfo.NumberFormat.PercentDecimalSeparator = CultureInfo.InvariantCulture.NumberFormat.PercentDecimalSeparator;
|
||||
cultureInfo.NumberFormat.PercentGroupSeparator = CultureInfo.InvariantCulture.NumberFormat.PercentGroupSeparator;
|
||||
return cultureInfo;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the maximum number of concurrent tasks enabled by this ParallelOptions instance.
|
||||
/// Less or equal to 0 will set to auto number
|
||||
@@ -77,7 +93,7 @@ public static class CoreSettings
|
||||
/// <summary>
|
||||
/// Gets or sets the default compression type for layers
|
||||
/// </summary>
|
||||
public static LayerCompressionCodec DefaultLayerCompressionCodec { get; set; } = LayerCompressionCodec.Png;
|
||||
public static LayerCompressionCodec DefaultLayerCompressionCodec { get; set; } = LayerCompressionCodec.Lz4;
|
||||
|
||||
/// <summary>
|
||||
/// <para>The average resin 1000ml bottle cost, to use when bottle cost is not available.</para>
|
||||
|
||||
@@ -1074,6 +1074,12 @@ public static class EmguExtensions
|
||||
/// <param name="lineType"></param>
|
||||
public static void DrawRotatedRectangle(this Mat src, Size size, Point center, MCvScalar color, int angle = 0, int thickness = -1, LineType lineType = LineType.EightConnected)
|
||||
{
|
||||
if (angle == 0)
|
||||
{
|
||||
src.DrawCenteredRectangle(size, center, color, thickness, lineType);
|
||||
return;
|
||||
}
|
||||
|
||||
var rect = new RotatedRect(center, size, angle);
|
||||
var vertices = rect.GetVertices();
|
||||
var points = new Point[vertices.Length];
|
||||
@@ -1097,6 +1103,32 @@ public static class EmguExtensions
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Draw a square around a center point
|
||||
/// </summary>
|
||||
/// <param name="src"></param>
|
||||
/// <param name="size"></param>
|
||||
/// <param name="center"></param>
|
||||
/// <param name="color"></param>
|
||||
/// <param name="thickness"></param>
|
||||
/// <param name="lineType"></param>
|
||||
public static void DrawCenteredSquare(this Mat src, int size, Point center, MCvScalar color, int thickness = -1, LineType lineType = LineType.EightConnected)
|
||||
=> src.DrawCenteredRectangle(new Size(size, size), center, color, thickness, lineType);
|
||||
|
||||
/// <summary>
|
||||
/// Draw a rectangle around a center point
|
||||
/// </summary>
|
||||
/// <param name="src"></param>
|
||||
/// <param name="size"></param>
|
||||
/// <param name="center"></param>
|
||||
/// <param name="color"></param>
|
||||
/// <param name="thickness"></param>
|
||||
/// <param name="lineType"></param>
|
||||
public static void DrawCenteredRectangle(this Mat src, Size size, Point center, MCvScalar color, int thickness = -1, LineType lineType = LineType.EightConnected)
|
||||
{
|
||||
CvInvoke.Rectangle(src, new Rectangle(center.OffsetBy(size.Width / -2, size.Height / -2), size), color, thickness, lineType);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Draw a polygon given number of sides and length
|
||||
/// </summary>
|
||||
@@ -1113,8 +1145,8 @@ public static class EmguExtensions
|
||||
{
|
||||
if (sides == 1)
|
||||
{
|
||||
var point1 = new Point(center.X - radius, center.Y);
|
||||
var point2 = new Point(center.X + radius, center.Y);
|
||||
var point1 = center with {X = center.X - radius};
|
||||
var point2 = center with {X = center.X + radius};
|
||||
point1 = point1.Rotate(startingAngle, center);
|
||||
point2 = point2.Rotate(startingAngle, center);
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ public static class ReflectionExtensions
|
||||
{
|
||||
if (Enum.TryParse(attribute.PropertyType, value, true, out var enumValue))
|
||||
{
|
||||
attribute.SetValue(obj, Enum.Parse(attribute.PropertyType, enumValue?.ToString() ?? string.Empty));
|
||||
attribute.SetValue(obj, enumValue);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -95,25 +95,25 @@ public static class ReflectionExtensions
|
||||
|
||||
if (attribute.PropertyType == typeof(Half))
|
||||
{
|
||||
attribute.SetValue(obj, Half.Parse(value, CultureInfo.InvariantCulture.NumberFormat));
|
||||
attribute.SetValue(obj, Half.Parse(value, CultureInfo.InvariantCulture));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (attribute.PropertyType == typeof(float))
|
||||
{
|
||||
attribute.SetValue(obj, float.Parse(value, CultureInfo.InvariantCulture.NumberFormat));
|
||||
attribute.SetValue(obj, float.Parse(value, CultureInfo.InvariantCulture));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (attribute.PropertyType == typeof(double))
|
||||
{
|
||||
attribute.SetValue(obj, double.Parse(value, CultureInfo.InvariantCulture.NumberFormat));
|
||||
attribute.SetValue(obj, double.Parse(value, CultureInfo.InvariantCulture));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (attribute.PropertyType == typeof(decimal))
|
||||
{
|
||||
attribute.SetValue(obj, decimal.Parse(value, CultureInfo.InvariantCulture.NumberFormat));
|
||||
attribute.SetValue(obj, decimal.Parse(value, CultureInfo.InvariantCulture));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Printing;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
@@ -176,22 +177,23 @@ public class CTBEncryptedFile : FileFormat
|
||||
public class LayerPointer
|
||||
{
|
||||
[FieldOrder(0)] public uint LayerOffset { get; set; }
|
||||
[FieldOrder(1)] public uint Padding1 { get; set; } // 0
|
||||
[FieldOrder(1)] public uint PageNumber { get; set; }
|
||||
[FieldOrder(2)] public uint LayerTableSize { get; set; } = LayerDef.TABLE_SIZE; // always 0x58
|
||||
[FieldOrder(3)] public uint Padding2 { get; set; } // 0
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{nameof(LayerOffset)}: {LayerOffset}, {nameof(Padding1)}: {Padding1}, {nameof(LayerTableSize)}: {LayerTableSize}, {nameof(Padding2)}: {Padding2}";
|
||||
return $"{nameof(LayerOffset)}: {LayerOffset}, {nameof(PageNumber)}: {PageNumber}, {nameof(LayerTableSize)}: {LayerTableSize}, {nameof(Padding2)}: {Padding2}";
|
||||
}
|
||||
|
||||
public LayerPointer()
|
||||
{
|
||||
}
|
||||
|
||||
public LayerPointer(uint layerOffset)
|
||||
public LayerPointer(long layerOffset)
|
||||
{
|
||||
LayerOffset = layerOffset;
|
||||
PageNumber = (uint)(layerOffset / ChituboxFile.PageSize);
|
||||
LayerOffset = (uint)(layerOffset - ChituboxFile.PageSize * PageNumber);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -203,8 +205,8 @@ public class CTBEncryptedFile : FileFormat
|
||||
[FieldOrder(1)] public float PositionZ { get; set; }
|
||||
[FieldOrder(2)] public float ExposureTime { get; set; }
|
||||
[FieldOrder(3)] public float LightOffDelay { get; set; }
|
||||
[FieldOrder(4)] public uint LayerDefOffset { get; set; }
|
||||
[FieldOrder(5)] public uint Unknown2 { get; set; }
|
||||
[FieldOrder(4)] public uint LayerDataOffset { get; set; }
|
||||
[FieldOrder(5)] public uint PageNumber { get; set; }
|
||||
[FieldOrder(6)] public uint DataLength { get; set; }
|
||||
[FieldOrder(7)] public uint Unknown3 { get; set; }
|
||||
[FieldOrder(8)] public uint EncryptedDataOffset { get; set; }
|
||||
@@ -440,7 +442,7 @@ public class CTBEncryptedFile : FileFormat
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{nameof(TableSize)}: {TableSize}, {nameof(PositionZ)}: {PositionZ}, {nameof(ExposureTime)}: {ExposureTime}, {nameof(LightOffDelay)}: {LightOffDelay}, {nameof(LayerDefOffset)}: {LayerDefOffset}, {nameof(Unknown2)}: {Unknown2}, {nameof(DataLength)}: {DataLength}, {nameof(Unknown3)}: {Unknown3}, {nameof(EncryptedDataOffset)}: {EncryptedDataOffset}, {nameof(EncryptedDataLength)}: {EncryptedDataLength}, {nameof(LiftHeight)}: {LiftHeight}, {nameof(LiftSpeed)}: {LiftSpeed}, {nameof(LiftHeight2)}: {LiftHeight2}, {nameof(LiftSpeed2)}: {LiftSpeed2}, {nameof(RetractSpeed)}: {RetractSpeed}, {nameof(RetractHeight2)}: {RetractHeight2}, {nameof(RetractSpeed2)}: {RetractSpeed2}, {nameof(RestTimeBeforeLift)}: {RestTimeBeforeLift}, {nameof(RestTimeAfterLift)}: {RestTimeAfterLift}, {nameof(RestTimeAfterRetract)}: {RestTimeAfterRetract}, {nameof(LightPWM)}: {LightPWM}, {nameof(Unknown6)}: {Unknown6}, {nameof(RLEData)}: {RLEData?.Length}";
|
||||
return $"{nameof(TableSize)}: {TableSize}, {nameof(PositionZ)}: {PositionZ}, {nameof(ExposureTime)}: {ExposureTime}, {nameof(LightOffDelay)}: {LightOffDelay}, {nameof(LayerDataOffset)}: {LayerDataOffset}, {nameof(PageNumber)}: {PageNumber}, {nameof(DataLength)}: {DataLength}, {nameof(Unknown3)}: {Unknown3}, {nameof(EncryptedDataOffset)}: {EncryptedDataOffset}, {nameof(EncryptedDataLength)}: {EncryptedDataLength}, {nameof(LiftHeight)}: {LiftHeight}, {nameof(LiftSpeed)}: {LiftSpeed}, {nameof(LiftHeight2)}: {LiftHeight2}, {nameof(LiftSpeed2)}: {LiftSpeed2}, {nameof(RetractSpeed)}: {RetractSpeed}, {nameof(RetractHeight2)}: {RetractHeight2}, {nameof(RetractSpeed2)}: {RetractSpeed2}, {nameof(RestTimeBeforeLift)}: {RestTimeBeforeLift}, {nameof(RestTimeAfterLift)}: {RestTimeAfterLift}, {nameof(RestTimeAfterRetract)}: {RestTimeAfterRetract}, {nameof(LightPWM)}: {LightPWM}, {nameof(Unknown6)}: {Unknown6}, {nameof(RLEData)}: {RLEData?.Length}";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1188,7 +1190,7 @@ public class CTBEncryptedFile : FileFormat
|
||||
{
|
||||
progress.ThrowIfCancellationRequested();
|
||||
|
||||
inputFile.Seek(LayersPointer[layerIndex].LayerOffset, SeekOrigin.Begin);
|
||||
inputFile.Seek(LayersPointer[layerIndex].PageNumber * ChituboxFile.PageSize + LayersPointer[layerIndex].LayerOffset, SeekOrigin.Begin);
|
||||
LayersDefinition[layerIndex] = Helpers.Deserialize<LayerDef>(inputFile);
|
||||
LayersDefinition[layerIndex].Parent = this;
|
||||
if (DecodeType == FileDecodeType.Full) LayersDefinition[layerIndex].RLEData = inputFile.ReadBytes(LayersDefinition[layerIndex].DataLength);
|
||||
@@ -1207,13 +1209,10 @@ public class CTBEncryptedFile : FileFormat
|
||||
/* Decrypt RLE data here */
|
||||
|
||||
var byteBuffer = new byte[layerDef.EncryptedDataLength];
|
||||
Array.Copy(layerDef.RLEData!, (int)layerDef.EncryptedDataOffset, byteBuffer, 0,
|
||||
(int)layerDef.EncryptedDataLength);
|
||||
Array.Copy(layerDef.RLEData!, (int)layerDef.EncryptedDataOffset, byteBuffer, 0, (int)layerDef.EncryptedDataLength);
|
||||
|
||||
byteBuffer = CryptExtensions.AesCryptBytes(byteBuffer, Bigfoot, CipherMode.CBC,
|
||||
PaddingMode.None, false, CookieMonster);
|
||||
Array.Copy(byteBuffer, 0, layerDef.RLEData!, layerDef.EncryptedDataOffset,
|
||||
layerDef.EncryptedDataLength);
|
||||
byteBuffer = CryptExtensions.AesCryptBytes(byteBuffer, Bigfoot, CipherMode.CBC, PaddingMode.None, false, CookieMonster);
|
||||
Array.Copy(byteBuffer, 0, layerDef.RLEData!, layerDef.EncryptedDataOffset, layerDef.EncryptedDataLength);
|
||||
}
|
||||
|
||||
bool isBugged = false;
|
||||
@@ -1243,7 +1242,7 @@ public class CTBEncryptedFile : FileFormat
|
||||
if (buggyLayers.Count == LayerCount)
|
||||
{
|
||||
throw new FileLoadException("Unable to load this file due to Chitubox bug affecting every layer." +
|
||||
"Please increase the portion of the plate in use and reslice the file.");
|
||||
"Please increase the portion of the plate in use and re-slice the file.");
|
||||
}
|
||||
|
||||
for (uint layerIndex = 0; layerIndex < LayerCount; layerIndex++)
|
||||
@@ -1376,9 +1375,11 @@ public class CTBEncryptedFile : FileFormat
|
||||
{
|
||||
progress.ThrowIfCancellationRequested();
|
||||
var layerDef = LayersDefinition[layerIndex];
|
||||
LayersPointer[layerIndex] = new LayerPointer((uint)outputFile.Position);
|
||||
LayersPointer[layerIndex] = new LayerPointer(outputFile.Position);
|
||||
|
||||
layerDef.LayerDefOffset = LayersPointer[layerIndex].LayerOffset + LayerDef.TABLE_SIZE;
|
||||
long layerDataOffset = outputFile.Position + LayerDef.TABLE_SIZE;
|
||||
layerDef.PageNumber = (uint)(layerDataOffset / ChituboxFile.PageSize);
|
||||
layerDef.LayerDataOffset = (uint)(layerDataOffset - ChituboxFile.PageSize * layerDef.PageNumber);
|
||||
outputFile.WriteSerialize(layerDef);
|
||||
outputFile.WriteBytes(layerDef.RLEData!);
|
||||
progress++;
|
||||
@@ -1425,7 +1426,7 @@ public class CTBEncryptedFile : FileFormat
|
||||
for (uint layerIndex = 0; layerIndex < LayersPointer!.Length; layerIndex++)
|
||||
{
|
||||
LayersDefinition![layerIndex].SetFrom(this[layerIndex]);
|
||||
outputFile.Seek(LayersPointer[layerIndex].LayerOffset, SeekOrigin.Begin);
|
||||
outputFile.Seek(LayersPointer[layerIndex].PageNumber * ChituboxFile.PageSize + LayersPointer[layerIndex].LayerOffset, SeekOrigin.Begin);
|
||||
outputFile.WriteSerialize(LayersDefinition[layerIndex]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -489,7 +489,7 @@ public class CXDLPFile : FileFormat
|
||||
|
||||
public override float DisplayWidth
|
||||
{
|
||||
get => float.Parse(Encoding.ASCII.GetString(SlicerInfoSettings.DisplayWidthBytes.Where(b => b != 0).ToArray()));
|
||||
get => float.Parse(Encoding.ASCII.GetString(SlicerInfoSettings.DisplayWidthBytes.Where(b => b != 0).ToArray()), CultureInfo.InvariantCulture);
|
||||
set
|
||||
{
|
||||
var str = Math.Round(value, 2).ToString(CultureInfo.InvariantCulture);
|
||||
@@ -508,7 +508,7 @@ public class CXDLPFile : FileFormat
|
||||
|
||||
public override float DisplayHeight
|
||||
{
|
||||
get => float.Parse(Encoding.ASCII.GetString(SlicerInfoSettings.DisplayHeightBytes.Where(b => b != 0).ToArray()));
|
||||
get => float.Parse(Encoding.ASCII.GetString(SlicerInfoSettings.DisplayHeightBytes.Where(b => b != 0).ToArray()), CultureInfo.InvariantCulture);
|
||||
set
|
||||
{
|
||||
string str = Math.Round(value, 2).ToString(CultureInfo.InvariantCulture);
|
||||
@@ -527,7 +527,7 @@ public class CXDLPFile : FileFormat
|
||||
|
||||
public override float LayerHeight
|
||||
{
|
||||
get => float.Parse(Encoding.ASCII.GetString(SlicerInfoSettings.LayerHeightBytes.Where(b => b != 0).ToArray()));
|
||||
get => float.Parse(Encoding.ASCII.GetString(SlicerInfoSettings.LayerHeightBytes.Where(b => b != 0).ToArray()), CultureInfo.InvariantCulture);
|
||||
set
|
||||
{
|
||||
string str = Layer.RoundHeight(value).ToString(CultureInfo.InvariantCulture);
|
||||
|
||||
@@ -362,7 +362,7 @@ public class CXDLPv1File : FileFormat
|
||||
|
||||
public override float DisplayWidth
|
||||
{
|
||||
get => float.Parse(Encoding.ASCII.GetString(SlicerInfoSettings.DisplayWidthBytes.Where(b => b != 0).ToArray()));
|
||||
get => float.Parse(Encoding.ASCII.GetString(SlicerInfoSettings.DisplayWidthBytes.Where(b => b != 0).ToArray()), CultureInfo.InvariantCulture);
|
||||
set
|
||||
{
|
||||
string str = Math.Round(value, 2).ToString(CultureInfo.InvariantCulture);
|
||||
@@ -380,7 +380,7 @@ public class CXDLPv1File : FileFormat
|
||||
|
||||
public override float DisplayHeight
|
||||
{
|
||||
get => float.Parse(Encoding.ASCII.GetString(SlicerInfoSettings.DisplayHeightBytes.Where(b => b != 0).ToArray()));
|
||||
get => float.Parse(Encoding.ASCII.GetString(SlicerInfoSettings.DisplayHeightBytes.Where(b => b != 0).ToArray()), CultureInfo.InvariantCulture);
|
||||
set
|
||||
{
|
||||
string str = Math.Round(value, 2).ToString(CultureInfo.InvariantCulture);
|
||||
@@ -398,7 +398,7 @@ public class CXDLPv1File : FileFormat
|
||||
|
||||
public override float LayerHeight
|
||||
{
|
||||
get => float.Parse(Encoding.ASCII.GetString(SlicerInfoSettings.LayerHeightBytes.Where(b => b != 0).ToArray()));
|
||||
get => float.Parse(Encoding.ASCII.GetString(SlicerInfoSettings.LayerHeightBytes.Where(b => b != 0).ToArray()), CultureInfo.InvariantCulture);
|
||||
set
|
||||
{
|
||||
string str = Layer.RoundHeight(value).ToString(CultureInfo.InvariantCulture);
|
||||
|
||||
@@ -34,6 +34,7 @@ public class ChituboxFile : FileFormat
|
||||
public const uint MAGIC_CBDDLP = 0x12FD0019; // 318570521
|
||||
public const uint MAGIC_CTB = 0x12FD0086; // 318570630
|
||||
public const uint MAGIC_CTBv4 = 0x12FD0106; // 318570758
|
||||
public const uint MAGIC_CTBv4_GKtwo = 0xFF220810; // 4280420368
|
||||
public const ushort REPEATRGB15MASK = 0x20;
|
||||
|
||||
public const byte RLE8EncodingLimit = 0x7d; // 125;
|
||||
@@ -50,6 +51,8 @@ public class ChituboxFile : FileFormat
|
||||
private const ushort CTBv4_DISCLAIMER_SIZE = 320;
|
||||
private const ushort CTBv4_RESERVED_SIZE = 384;
|
||||
|
||||
public const long PageSize = 4_294_967_296L; // Page-size for layers, limited to 4GB
|
||||
|
||||
#endregion
|
||||
|
||||
#region Sub Classes
|
||||
@@ -612,7 +615,7 @@ public class ChituboxFile : FileFormat
|
||||
/// Gets the layer image length in bytes.
|
||||
/// </summary>
|
||||
[FieldOrder(4)] public uint DataSize { get; set; }
|
||||
[FieldOrder(5)] public uint Unknown1 { get; set; }
|
||||
[FieldOrder(5)] public uint PageNumber { get; set; }
|
||||
[FieldOrder(6)] public uint TableSize { get; set; } = TABLE_SIZE;
|
||||
[FieldOrder(7)] public uint Unknown3 { get; set; }
|
||||
[FieldOrder(8)] public uint Unknown4 { get; set; }
|
||||
@@ -956,7 +959,7 @@ public class ChituboxFile : FileFormat
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{nameof(PositionZ)}: {PositionZ}, {nameof(ExposureTime)}: {ExposureTime}, {nameof(LightOffSeconds)}: {LightOffSeconds}, {nameof(DataAddress)}: {DataAddress}, {nameof(DataSize)}: {DataSize}, {nameof(Unknown1)}: {Unknown1}, {nameof(TableSize)}: {TableSize}, {nameof(Unknown3)}: {Unknown3}, {nameof(Unknown4)}: {Unknown4}";
|
||||
return $"{nameof(PositionZ)}: {PositionZ}, {nameof(ExposureTime)}: {ExposureTime}, {nameof(LightOffSeconds)}: {LightOffSeconds}, {nameof(DataAddress)}: {DataAddress}, {nameof(DataSize)}: {DataSize}, {nameof(PageNumber)}: {PageNumber}, {nameof(TableSize)}: {TableSize}, {nameof(Unknown3)}: {Unknown3}, {nameof(Unknown4)}: {Unknown4}";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1073,10 +1076,10 @@ public class ChituboxFile : FileFormat
|
||||
new(typeof(ChituboxFile), "photon", "Chitubox Photon"),
|
||||
new(typeof(ChituboxFile), "cbddlp", "Chitubox CBDDLP"),
|
||||
new(typeof(ChituboxFile), "ctb", "Chitubox CTB"),
|
||||
new(typeof(ChituboxFile), "gktwo.ctb", "Chitubox CTB for UniFormation GKtwo", false),
|
||||
//new(typeof(ChituboxFile), "v2.ctb", "Chitubox CTBv2"),
|
||||
//new(typeof(ChituboxFile), "v3.ctb", "Chitubox CTBv3"),
|
||||
//new(typeof(ChituboxFile), "v4.ctb", "Chitubox CTBv4", false, false),
|
||||
//new(typeof(ChituboxFile), "encrypted.ctb", "Chitubox encrypted CTB"),
|
||||
};
|
||||
|
||||
public override PrintParameterModifier[]? PrintParameterModifiers
|
||||
@@ -1706,7 +1709,11 @@ public class ChituboxFile : FileFormat
|
||||
}
|
||||
|
||||
public bool IsCbddlpFile => HeaderSettings.Magic == MAGIC_CBDDLP;
|
||||
public bool IsCtbFile => HeaderSettings.Magic is MAGIC_CTB or MAGIC_CTBv4;
|
||||
public bool IsCtbFile => HeaderSettings.Magic is MAGIC_CTB or MAGIC_CTBv4 or MAGIC_CTBv4_GKtwo;
|
||||
|
||||
public bool IsMagicValid => IsValidKnownMagic(HeaderSettings.Magic);
|
||||
|
||||
public static bool IsValidKnownMagic(uint magic) => magic is MAGIC_CBDDLP or MAGIC_CTB or MAGIC_CTBv4 or MAGIC_CTBv4_GKtwo;
|
||||
|
||||
public bool CanHash => IsCbddlpFile && HeaderSettings.Version <= 2;
|
||||
#endregion
|
||||
@@ -1739,7 +1746,7 @@ public class ChituboxFile : FileFormat
|
||||
{
|
||||
using var fs = new BinaryReader(new FileStream(fileFullPath!, FileMode.Open, FileAccess.Read));
|
||||
var magic = fs.ReadUInt32();
|
||||
return magic is MAGIC_CBDDLP or MAGIC_CTB or MAGIC_CTBv4;
|
||||
return IsValidKnownMagic(magic);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@@ -1753,7 +1760,7 @@ public class ChituboxFile : FileFormat
|
||||
{
|
||||
if (FileEndsWith(".ctb"))
|
||||
{
|
||||
if (HeaderSettings.Magic is not MAGIC_CTB and not MAGIC_CTBv4)
|
||||
if (!IsCtbFile)
|
||||
{
|
||||
HeaderSettings.Magic = MAGIC_CTB;
|
||||
}
|
||||
@@ -1773,6 +1780,11 @@ public class ChituboxFile : FileFormat
|
||||
HeaderSettings.Magic = MAGIC_CTBv4;
|
||||
HeaderSettings.Version = 4;
|
||||
}
|
||||
else if (FileEndsWith(".gktwo.ctb"))
|
||||
{
|
||||
HeaderSettings.Magic = MAGIC_CTBv4_GKtwo;
|
||||
HeaderSettings.Version = 4;
|
||||
}
|
||||
}
|
||||
else if (FileEndsWith(".cbddlp") || FileEndsWith(".photon"))
|
||||
{
|
||||
@@ -1905,9 +1917,8 @@ public class ChituboxFile : FileFormat
|
||||
}
|
||||
|
||||
HeaderSettings.LayersDefinitionOffsetAddress = (uint)outputFile.Position;
|
||||
uint layerDefSize = (uint)Helpers.Serializer.SizeOf(new LayerDef());
|
||||
//uint layerDefCurrentOffset = HeaderSettings.LayersDefinitionOffsetAddress;
|
||||
uint layerDataCurrentOffset = HeaderSettings.LayersDefinitionOffsetAddress + layerDefSize * LayerCount * HeaderSettings.AntiAliasLevel;
|
||||
long layerDefSize = Helpers.Serializer.SizeOf(new LayerDef());
|
||||
long layerDataCurrentOffset = HeaderSettings.LayersDefinitionOffsetAddress + layerDefSize * LayerCount * HeaderSettings.AntiAliasLevel;
|
||||
|
||||
var layersHash = new Dictionary<string, LayerDef>();
|
||||
progress.Reset(OperationProgress.StatusEncodeLayers, LayerCount);
|
||||
@@ -1930,7 +1941,7 @@ public class ChituboxFile : FileFormat
|
||||
|
||||
foreach (var layerIndex in batch)
|
||||
{
|
||||
if (layerIndex == 0) layerDefSize = (uint)Helpers.Serializer.SizeOf(LayerDefinitions[0, layerIndex]);
|
||||
if (layerIndex == 0) layerDefSize = Helpers.Serializer.SizeOf(LayerDefinitions[0, layerIndex]);
|
||||
for (byte aaIndex = 0; aaIndex < HeaderSettings.AntiAliasLevel; aaIndex++)
|
||||
{
|
||||
progress.ThrowIfCancellationRequested();
|
||||
@@ -1954,14 +1965,16 @@ public class ChituboxFile : FileFormat
|
||||
|
||||
if (layerDefHash is null)
|
||||
{
|
||||
layerDef.DataAddress = layerDataCurrentOffset;
|
||||
layerDef.PageNumber = (uint)(layerDataCurrentOffset / PageSize);
|
||||
layerDef.DataAddress = (uint)(layerDataCurrentOffset - PageSize * layerDef.PageNumber);
|
||||
outputFile.Seek(layerDataCurrentOffset, SeekOrigin.Begin);
|
||||
|
||||
if (HeaderSettings.Version >= 3)
|
||||
{
|
||||
var layerDataEx = new LayerDefEx(layerDef, this[layerIndex]);
|
||||
layerDataCurrentOffset += (uint)Helpers.Serializer.SizeOf(layerDataEx);
|
||||
layerDef.DataAddress = layerDataCurrentOffset;
|
||||
layerDataCurrentOffset += Helpers.Serializer.SizeOf(layerDataEx);
|
||||
layerDef.PageNumber = (uint)(layerDataCurrentOffset / PageSize);
|
||||
layerDef.DataAddress = (uint)(layerDataCurrentOffset - PageSize * layerDef.PageNumber);
|
||||
outputFile.WriteSerialize(layerDataEx);
|
||||
}
|
||||
|
||||
@@ -2001,7 +2014,7 @@ public class ChituboxFile : FileFormat
|
||||
//HeaderSettings = Helpers.Serializer.Deserialize<Header>(InputFile.ReadBytes(Helpers.Serializer.SizeOf(typeof(Header))));
|
||||
HeaderSettings = Helpers.Deserialize<Header>(inputFile);
|
||||
|
||||
if (HeaderSettings.Magic is not MAGIC_CBDDLP and not MAGIC_CTB and not MAGIC_CTBv4)
|
||||
if (!IsMagicValid)
|
||||
{
|
||||
throw new FileLoadException($"Not a valid PHOTON nor CBDDLP nor CTB file! Magic Value: {HeaderSettings.Magic}", FileFullPath);
|
||||
}
|
||||
@@ -2112,7 +2125,7 @@ public class ChituboxFile : FileFormat
|
||||
|
||||
if (HeaderSettings.Version >= 3)
|
||||
{
|
||||
inputFile.SeekDoWorkAndRewind(layerDef.DataAddress - 84, () =>
|
||||
inputFile.SeekDoWorkAndRewind(layerDef.PageNumber * PageSize + layerDef.DataAddress - 84, () =>
|
||||
{
|
||||
layerDefinitionsEx![layerIndex] = Helpers.Deserialize<LayerDefEx>(inputFile);
|
||||
layerDefinitionsEx[layerIndex].LayerDef.Parent = this;
|
||||
@@ -2137,7 +2150,7 @@ public class ChituboxFile : FileFormat
|
||||
{
|
||||
progress.ThrowIfCancellationRequested();
|
||||
|
||||
inputFile.Seek(LayerDefinitions[aaIndex, layerIndex].DataAddress, SeekOrigin.Begin);
|
||||
inputFile.Seek(LayerDefinitions[aaIndex, layerIndex].PageNumber * PageSize + LayerDefinitions[aaIndex, layerIndex].DataAddress, SeekOrigin.Begin);
|
||||
LayerDefinitions[aaIndex, layerIndex].EncodedRle = inputFile.ReadBytes(LayerDefinitions[aaIndex, layerIndex].DataSize);
|
||||
}
|
||||
}
|
||||
@@ -2179,16 +2192,13 @@ public class ChituboxFile : FileFormat
|
||||
outputFile.WriteSerialize(SlicerInfoSettings);
|
||||
}
|
||||
|
||||
uint layerOffset = HeaderSettings.LayersDefinitionOffsetAddress;
|
||||
outputFile.Seek(HeaderSettings.LayersDefinitionOffsetAddress, SeekOrigin.Begin);
|
||||
for (byte aaIndex = 0; aaIndex < HeaderSettings.AntiAliasLevel; aaIndex++)
|
||||
{
|
||||
for (uint layerIndex = 0; layerIndex < LayerCount; layerIndex++)
|
||||
{
|
||||
var layer = this[layerIndex];
|
||||
LayerDefinitions![aaIndex, layerIndex].SetFrom(layer);
|
||||
|
||||
outputFile.Seek(layerOffset, SeekOrigin.Begin);
|
||||
layerOffset += outputFile.WriteSerialize(LayerDefinitions[aaIndex, layerIndex]);
|
||||
LayerDefinitions![aaIndex, layerIndex].SetFrom(this[layerIndex]);
|
||||
outputFile.WriteSerialize(LayerDefinitions[aaIndex, layerIndex]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2196,7 +2206,7 @@ public class ChituboxFile : FileFormat
|
||||
{
|
||||
for (uint layerIndex = 0; layerIndex < LayerCount; layerIndex++)
|
||||
{
|
||||
outputFile.Seek(LayerDefinitions![0, layerIndex].DataAddress - 84, SeekOrigin.Begin);
|
||||
outputFile.Seek(LayerDefinitions![0, layerIndex].PageNumber * PageSize + LayerDefinitions![0, layerIndex].DataAddress - 84, SeekOrigin.Begin);
|
||||
outputFile.WriteSerialize(new LayerDefEx(LayerDefinitions[0, layerIndex], this[layerIndex]));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -435,7 +435,7 @@ public class FDGFile : FileFormat
|
||||
/// Gets the layer image length in bytes.
|
||||
/// </summary>
|
||||
[FieldOrder(4)] public uint DataSize { get; set; }
|
||||
[FieldOrder(5)] public uint Unknown1 { get; set; }
|
||||
[FieldOrder(5)] public uint PageNumber { get; set; }
|
||||
[FieldOrder(6)] public uint Unknown2 { get; set; } = 84;
|
||||
[FieldOrder(7)] public uint Unknown3 { get; set; }
|
||||
[FieldOrder(8)] public uint Unknown4 { get; set; }
|
||||
@@ -611,7 +611,7 @@ public class FDGFile : FileFormat
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{nameof(LayerPositionZ)}: {LayerPositionZ}, {nameof(LayerExposure)}: {LayerExposure}, {nameof(LightOffDelay)}: {LightOffDelay}, {nameof(DataAddress)}: {DataAddress}, {nameof(DataSize)}: {DataSize}, {nameof(Unknown1)}: {Unknown1}, {nameof(Unknown2)}: {Unknown2}, {nameof(Unknown3)}: {Unknown3}, {nameof(Unknown4)}: {Unknown4}";
|
||||
return $"{nameof(LayerPositionZ)}: {LayerPositionZ}, {nameof(LayerExposure)}: {LayerExposure}, {nameof(LightOffDelay)}: {LightOffDelay}, {nameof(DataAddress)}: {DataAddress}, {nameof(DataSize)}: {DataSize}, {nameof(PageNumber)}: {PageNumber}, {nameof(Unknown2)}: {Unknown2}, {nameof(Unknown3)}: {Unknown3}, {nameof(Unknown4)}: {Unknown4}";
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
@@ -973,8 +973,8 @@ public class FDGFile : FileFormat
|
||||
var layersHash = new Dictionary<string, LayerDef>();
|
||||
LayersDefinitions = new LayerDef[HeaderSettings.LayerCount];
|
||||
HeaderSettings.LayersDefinitionOffsetAddress = (uint)outputFile.Position;
|
||||
uint layerDefCurrentOffset = HeaderSettings.LayersDefinitionOffsetAddress;
|
||||
uint layerDataCurrentOffset = HeaderSettings.LayersDefinitionOffsetAddress + (uint)Helpers.Serializer.SizeOf(new LayerDef()) * LayerCount;
|
||||
long layerDefCurrentOffset = HeaderSettings.LayersDefinitionOffsetAddress;
|
||||
long layerDataCurrentOffset = HeaderSettings.LayersDefinitionOffsetAddress + Helpers.Serializer.SizeOf(new LayerDef()) * LayerCount;
|
||||
|
||||
foreach (var batch in BatchLayersIndexes())
|
||||
{
|
||||
@@ -1011,7 +1011,8 @@ public class FDGFile : FileFormat
|
||||
|
||||
if (layerDefHash is null)
|
||||
{
|
||||
layerDef.DataAddress = layerDataCurrentOffset;
|
||||
layerDef.PageNumber = (uint)(layerDataCurrentOffset / ChituboxFile.PageSize);
|
||||
layerDef.DataAddress = (uint)(layerDataCurrentOffset - ChituboxFile.PageSize * layerDef.PageNumber);
|
||||
|
||||
outputFile.Seek(layerDataCurrentOffset, SeekOrigin.Begin);
|
||||
layerDataCurrentOffset += outputFile.WriteBytes(layerDef.EncodedRle!);
|
||||
@@ -1101,7 +1102,7 @@ public class FDGFile : FileFormat
|
||||
|
||||
if (DecodeType == FileDecodeType.Full)
|
||||
{
|
||||
inputFile.SeekDoWorkAndRewind(layerDef.DataAddress,
|
||||
inputFile.SeekDoWorkAndRewind(layerDef.PageNumber * ChituboxFile.PageSize + layerDef.DataAddress,
|
||||
() => { layerDef.EncodedRle = inputFile.ReadBytes(layerDef.DataSize); });
|
||||
}
|
||||
}
|
||||
@@ -1141,13 +1142,11 @@ public class FDGFile : FileFormat
|
||||
outputFile.Write(Encoding.ASCII.GetBytes(HeaderSettings.MachineName), 0, (int)HeaderSettings.MachineNameSize);
|
||||
}*/
|
||||
|
||||
uint layerOffset = HeaderSettings.LayersDefinitionOffsetAddress;
|
||||
outputFile.Seek(HeaderSettings.LayersDefinitionOffsetAddress, SeekOrigin.Begin);
|
||||
for (uint layerIndex = 0; layerIndex < HeaderSettings.LayerCount; layerIndex++)
|
||||
{
|
||||
LayersDefinitions[layerIndex].SetFrom(this[layerIndex]);
|
||||
outputFile.Seek(layerOffset, SeekOrigin.Begin);
|
||||
outputFile.WriteSerialize(LayersDefinitions[layerIndex]);
|
||||
layerOffset += (uint)Helpers.Serializer.SizeOf(LayersDefinitions[layerIndex]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -624,12 +624,13 @@ public abstract class FileFormat : BindableBase, IDisposable, IEquatable<FileFor
|
||||
{
|
||||
if (!targetPrintModifier.Contains(sourceModifier)) continue;
|
||||
|
||||
var fromValueStr = from.GetValueFromPrintParameterModifier(sourceModifier)?.ToString();
|
||||
var toValueStr = to.GetValueFromPrintParameterModifier(sourceModifier)?.ToString();
|
||||
var fromValueObj = from.GetValueFromPrintParameterModifier(sourceModifier);
|
||||
var toValueObj = to.GetValueFromPrintParameterModifier(sourceModifier);
|
||||
|
||||
if (fromValueStr is null || toValueStr is null) continue;
|
||||
|
||||
if (decimal.TryParse(fromValueStr, out var fromValue) && decimal.TryParse(toValueStr, out var toValue) && fromValue != toValue)
|
||||
if (fromValueObj is null || toValueObj is null) continue;
|
||||
var fromValue = System.Convert.ToDecimal(fromValueObj);
|
||||
var toValue = System.Convert.ToDecimal(toValueObj);
|
||||
if (fromValue != toValue)
|
||||
{
|
||||
to.SetValueFromPrintParameterModifier(sourceModifier, fromValue);
|
||||
count++;
|
||||
|
||||
@@ -14,6 +14,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Drawing;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
@@ -695,8 +696,8 @@ public class FlashForgeSVGXFile : FileFormat
|
||||
if (i + 1 >= spaceSplit.Length) break; // No more to see
|
||||
|
||||
|
||||
if (!float.TryParse(spaceSplit[i], out var mmX)) continue;
|
||||
if (!float.TryParse(spaceSplit[++i], out var mmY)) continue;
|
||||
if (!float.TryParse(spaceSplit[i], NumberStyles.Float, CultureInfo.InvariantCulture, out var mmX)) continue;
|
||||
if (!float.TryParse(spaceSplit[++i], NumberStyles.Float, CultureInfo.InvariantCulture, out var mmY)) continue;
|
||||
|
||||
|
||||
var mmAbsX = Math.Clamp(halfDisplay.Width + mmX, 0, DisplayWidth);
|
||||
|
||||
@@ -195,7 +195,7 @@ public class GR1File : FileFormat
|
||||
|
||||
public override float DisplayWidth
|
||||
{
|
||||
get => float.Parse(Encoding.ASCII.GetString(SlicerInfoSettings.DisplayWidthBytes.Where(b => b != 0).ToArray()));
|
||||
get => float.Parse(Encoding.ASCII.GetString(SlicerInfoSettings.DisplayWidthBytes.Where(b => b != 0).ToArray()), CultureInfo.InvariantCulture);
|
||||
set
|
||||
{
|
||||
string str = Math.Round(value, 2).ToString(CultureInfo.InvariantCulture);
|
||||
@@ -213,7 +213,7 @@ public class GR1File : FileFormat
|
||||
|
||||
public override float DisplayHeight
|
||||
{
|
||||
get => float.Parse(Encoding.ASCII.GetString(SlicerInfoSettings.DisplayHeightBytes.Where(b => b != 0).ToArray()));
|
||||
get => float.Parse(Encoding.ASCII.GetString(SlicerInfoSettings.DisplayHeightBytes.Where(b => b != 0).ToArray()), CultureInfo.InvariantCulture);
|
||||
set
|
||||
{
|
||||
string str = Math.Round(value, 2).ToString(CultureInfo.InvariantCulture);
|
||||
@@ -233,7 +233,7 @@ public class GR1File : FileFormat
|
||||
|
||||
public override float LayerHeight
|
||||
{
|
||||
get => float.Parse(Encoding.ASCII.GetString(SlicerInfoSettings.LayerHeightBytes.Where(b => b != 0).ToArray()));
|
||||
get => float.Parse(Encoding.ASCII.GetString(SlicerInfoSettings.LayerHeightBytes.Where(b => b != 0).ToArray()), CultureInfo.InvariantCulture);
|
||||
set
|
||||
{
|
||||
string str = Layer.RoundHeight(value).ToString(CultureInfo.InvariantCulture);
|
||||
|
||||
@@ -199,7 +199,7 @@ public class MDLPFile : FileFormat
|
||||
|
||||
public override float DisplayWidth
|
||||
{
|
||||
get => float.Parse(Encoding.ASCII.GetString(SlicerInfoSettings.DisplayWidthBytes.Where(b => b != 0).ToArray()));
|
||||
get => float.Parse(Encoding.ASCII.GetString(SlicerInfoSettings.DisplayWidthBytes.Where(b => b != 0).ToArray()), CultureInfo.InvariantCulture);
|
||||
set
|
||||
{
|
||||
string str = Math.Round(value, 2).ToString(CultureInfo.InvariantCulture);
|
||||
@@ -217,7 +217,7 @@ public class MDLPFile : FileFormat
|
||||
|
||||
public override float DisplayHeight
|
||||
{
|
||||
get => float.Parse(Encoding.ASCII.GetString(SlicerInfoSettings.DisplayHeightBytes.Where(b => b != 0).ToArray()));
|
||||
get => float.Parse(Encoding.ASCII.GetString(SlicerInfoSettings.DisplayHeightBytes.Where(b => b != 0).ToArray()), CultureInfo.InvariantCulture);
|
||||
set
|
||||
{
|
||||
string str = Math.Round(value, 2).ToString(CultureInfo.InvariantCulture);
|
||||
@@ -236,7 +236,7 @@ public class MDLPFile : FileFormat
|
||||
public override FlipDirection DisplayMirror { get; set; }
|
||||
public override float LayerHeight
|
||||
{
|
||||
get => float.Parse(Encoding.ASCII.GetString(SlicerInfoSettings.LayerHeightBytes.Where(b => b != 0).ToArray()));
|
||||
get => float.Parse(Encoding.ASCII.GetString(SlicerInfoSettings.LayerHeightBytes.Where(b => b != 0).ToArray()), CultureInfo.InvariantCulture);
|
||||
set
|
||||
{
|
||||
string str = Layer.RoundHeight(value).ToString(CultureInfo.InvariantCulture);
|
||||
|
||||
@@ -449,7 +449,7 @@ public class PHZFile : FileFormat
|
||||
/// Gets the layer image length in bytes.
|
||||
/// </summary>
|
||||
[FieldOrder(4)] public uint DataSize { get; set; }
|
||||
[FieldOrder(5)] public uint Unknown1 { get; set; }
|
||||
[FieldOrder(5)] public uint PageNumber { get; set; }
|
||||
[FieldOrder(6)] public uint Unknown2 { get; set; }
|
||||
[FieldOrder(7)] public uint Unknown3 { get; set; }
|
||||
[FieldOrder(8)] public uint Unknown4 { get; set; }
|
||||
@@ -625,7 +625,7 @@ public class PHZFile : FileFormat
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{nameof(PositionZ)}: {PositionZ}, {nameof(ExposureTime)}: {ExposureTime}, {nameof(LightOffDelay)}: {LightOffDelay}, {nameof(DataAddress)}: {DataAddress}, {nameof(DataSize)}: {DataSize}, {nameof(Unknown1)}: {Unknown1}, {nameof(Unknown2)}: {Unknown2}, {nameof(Unknown3)}: {Unknown3}, {nameof(Unknown4)}: {Unknown4}";
|
||||
return $"{nameof(PositionZ)}: {PositionZ}, {nameof(ExposureTime)}: {ExposureTime}, {nameof(LightOffDelay)}: {LightOffDelay}, {nameof(DataAddress)}: {DataAddress}, {nameof(DataSize)}: {DataSize}, {nameof(PageNumber)}: {PageNumber}, {nameof(Unknown2)}: {Unknown2}, {nameof(Unknown3)}: {Unknown3}, {nameof(Unknown4)}: {Unknown4}";
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
@@ -999,8 +999,8 @@ public class PHZFile : FileFormat
|
||||
var layersHash = new Dictionary<string, LayerDef>();
|
||||
LayersDefinitions = new LayerDef[HeaderSettings.LayerCount];
|
||||
HeaderSettings.LayersDefinitionOffsetAddress = (uint)outputFile.Position;
|
||||
uint layerDefCurrentOffset = HeaderSettings.LayersDefinitionOffsetAddress;
|
||||
uint layerDataCurrentOffset = HeaderSettings.LayersDefinitionOffsetAddress + (uint)Helpers.Serializer.SizeOf(new LayerDef()) * LayerCount;
|
||||
long layerDefCurrentOffset = HeaderSettings.LayersDefinitionOffsetAddress;
|
||||
long layerDataCurrentOffset = HeaderSettings.LayersDefinitionOffsetAddress + Helpers.Serializer.SizeOf(new LayerDef()) * LayerCount;
|
||||
|
||||
foreach (var batch in BatchLayersIndexes())
|
||||
{
|
||||
@@ -1037,7 +1037,8 @@ public class PHZFile : FileFormat
|
||||
|
||||
if (layerDefHash is null)
|
||||
{
|
||||
layerDef.DataAddress = layerDataCurrentOffset;
|
||||
layerDef.PageNumber = (uint)(layerDataCurrentOffset / ChituboxFile.PageSize);
|
||||
layerDef.DataAddress = (uint) (layerDataCurrentOffset - ChituboxFile.PageSize * layerDef.PageNumber);
|
||||
|
||||
outputFile.Seek(layerDataCurrentOffset, SeekOrigin.Begin);
|
||||
layerDataCurrentOffset += outputFile.WriteBytes(layerDef.EncodedRle);
|
||||
@@ -1128,7 +1129,7 @@ public class PHZFile : FileFormat
|
||||
|
||||
if (DecodeType == FileDecodeType.Full)
|
||||
{
|
||||
inputFile.SeekDoWorkAndRewind(layerDef.DataAddress,
|
||||
inputFile.SeekDoWorkAndRewind(layerDef.PageNumber * ChituboxFile.PageSize + layerDef.DataAddress,
|
||||
() => { layerDef.EncodedRle = inputFile.ReadBytes(layerDef.DataSize); });
|
||||
}
|
||||
}
|
||||
@@ -1164,13 +1165,11 @@ public class PHZFile : FileFormat
|
||||
outputFile.Write(Encoding.ASCII.GetBytes(HeaderSettings.MachineName), 0, (int)HeaderSettings.MachineNameSize);
|
||||
}*/
|
||||
|
||||
uint layerOffset = HeaderSettings.LayersDefinitionOffsetAddress;
|
||||
outputFile.Seek(HeaderSettings.LayersDefinitionOffsetAddress, SeekOrigin.Begin);
|
||||
for (uint layerIndex = 0; layerIndex < HeaderSettings.LayerCount; layerIndex++)
|
||||
{
|
||||
LayersDefinitions[layerIndex].SetFrom(this[layerIndex]);
|
||||
outputFile.Seek(layerOffset, SeekOrigin.Begin);
|
||||
outputFile.WriteSerialize(LayersDefinitions[layerIndex]);
|
||||
layerOffset += (uint)Helpers.Serializer.SizeOf(LayersDefinitions[layerIndex]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -636,7 +636,7 @@ public class GCodeBuilder : BindableBase
|
||||
|
||||
public void AppendWaitSyncDelay(string timeStr, string? comment = null)
|
||||
{
|
||||
if (!float.TryParse(timeStr, out var time)) return;
|
||||
if (!float.TryParse(timeStr, NumberStyles.Float | NumberStyles.AllowThousands, CultureInfo.InvariantCulture, out var time)) return;
|
||||
if (time < 0) return;
|
||||
AppendLineOverrideComment(CommandWaitSyncDelay, comment, timeStr);
|
||||
}
|
||||
@@ -649,7 +649,7 @@ public class GCodeBuilder : BindableBase
|
||||
|
||||
public void AppendWaitG4(string timeStr, string? comment = null)
|
||||
{
|
||||
if (!float.TryParse(timeStr, out var time)) return;
|
||||
if (!float.TryParse(timeStr, NumberStyles.Float | NumberStyles.AllowThousands, CultureInfo.InvariantCulture, out var time)) return;
|
||||
if (time < 0) return;
|
||||
AppendLineOverrideComment(CommandWaitG4, comment, timeStr);
|
||||
}
|
||||
@@ -1041,7 +1041,7 @@ public class GCodeBuilder : BindableBase
|
||||
layerBlock.WaitSyncDelayDetected = true;
|
||||
continue; // Sync movement delay, skip
|
||||
}
|
||||
var waitTime = float.Parse(match.Groups[1].Value);
|
||||
var waitTime = float.Parse(match.Groups[1].Value, CultureInfo.InvariantCulture);
|
||||
|
||||
if (layerBlock.PositionZ.HasValue &&
|
||||
//layerBlock.LiftHeight.HasValue &&
|
||||
@@ -1120,107 +1120,6 @@ public class GCodeBuilder : BindableBase
|
||||
// Propagate values of left over layer
|
||||
layerBlock.SetLayer();
|
||||
|
||||
|
||||
/*for (uint layerIndex = 0; layerIndex < slicerFile.LayerCount; layerIndex++)
|
||||
{
|
||||
var layer = slicerFile[layerIndex];
|
||||
if(layer is null) continue;
|
||||
var startStr = CommandShowImageM6054.ToStringWithoutComments(GetShowImageString(layerIndex));
|
||||
var endStr = CommandShowImageM6054.ToStringWithoutComments(GetShowImageString(layerIndex+1));
|
||||
gcode = gcode.Substring(gcode.IndexOf(startStr, StringComparison.InvariantCultureIgnoreCase) + startStr.Length + 1);
|
||||
var endStrIndex = gcode.IndexOf(endStr, StringComparison.Ordinal);
|
||||
var stripGcode = endStrIndex > 0 ? gcode[..endStrIndex] : gcode;//.Trim(' ', '\n', '\r', '\t');
|
||||
|
||||
float liftHeight = 0;// this allow read back no lifts slicerFile.GetInitialLayerValueOrNormal(layerIndex, slicerFile.BottomLiftHeight, slicerFile.LiftHeight);
|
||||
float liftSpeed = slicerFile.GetInitialLayerValueOrNormal(layerIndex, slicerFile.BottomLiftSpeed, slicerFile.LiftSpeed);
|
||||
float retractSpeed = slicerFile.RetractSpeed;
|
||||
float lightOffDelay = 0;
|
||||
byte pwm = slicerFile.GetInitialLayerValueOrNormal(layerIndex, slicerFile.BottomLightPWM, slicerFile.LightPWM);
|
||||
float exposureTime = slicerFile.GetInitialLayerValueOrNormal(layerIndex, slicerFile.BottomExposureTime, slicerFile.ExposureTime);
|
||||
var moveG0Regex = Regex.Matches(stripGcode, CommandMoveG0.ToStringWithoutComments(@"([+-]?([0-9]*[.])?[0-9]+)", @"(\d+)"), RegexOptions.IgnoreCase);
|
||||
var moveG1Regex = Regex.Matches(stripGcode, CommandMoveG1.ToStringWithoutComments(@"([+-]?([0-9]*[.])?[0-9]+)", @"(\d+)"), RegexOptions.IgnoreCase);
|
||||
var waitG4Regex = Regex.Matches(stripGcode, CommandWaitG4.ToStringWithoutComments(@"(\d+)"), RegexOptions.IgnoreCase);
|
||||
var pwmM106Regex = Regex.Match(stripGcode, CommandTurnLEDM106.ToStringWithoutComments(@"(\d+)"), RegexOptions.IgnoreCase);
|
||||
var moveRegex = moveG0Regex.Count > 0 ? moveG0Regex : moveG1Regex;
|
||||
|
||||
if (moveRegex.Count >= 1 && moveRegex[0].Success)
|
||||
{
|
||||
float liftPosTemp = float.Parse(moveRegex[0].Groups[1].Value, CultureInfo.InvariantCulture);
|
||||
float liftSpeedTemp = ConvertToMillimetersPerMinute(float.Parse(moveRegex[0].Groups[3].Value, CultureInfo.InvariantCulture));
|
||||
|
||||
if (moveRegex.Count >= 2 && moveRegex[1].Success)
|
||||
{
|
||||
float retractPos = float.Parse(moveRegex[1].Groups[1].Value, CultureInfo.InvariantCulture);
|
||||
retractSpeed = ConvertToMillimetersPerMinute(float.Parse(moveRegex[1].Groups[3].Value, CultureInfo.InvariantCulture));
|
||||
liftSpeed = liftSpeedTemp;
|
||||
|
||||
switch (positionType)
|
||||
{
|
||||
case GCodePositioningTypes.Absolute:
|
||||
liftHeight = Layer.RoundHeight(liftPosTemp - retractPos);
|
||||
positionZ = retractPos;
|
||||
break;
|
||||
case GCodePositioningTypes.Partial:
|
||||
liftHeight = liftPosTemp;
|
||||
positionZ = Layer.RoundHeight(positionZ + liftPosTemp + retractPos);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (liftPosTemp - positionZ <= FileFormat.MaximumLayerHeight)
|
||||
{
|
||||
switch (positionType)
|
||||
{
|
||||
case GCodePositioningTypes.Absolute:
|
||||
positionZ = liftPosTemp;
|
||||
break;
|
||||
case GCodePositioningTypes.Partial:
|
||||
positionZ = Layer.RoundHeight(positionZ + liftPosTemp);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (pwmM106Regex.Success)
|
||||
{
|
||||
if (_maxLedPower == byte.MaxValue)
|
||||
{
|
||||
pwm = byte.Parse(pwmM106Regex.Groups[1].Value);
|
||||
}
|
||||
else
|
||||
{
|
||||
ushort pwmValue = ushort.Parse(pwmM106Regex.Groups[1].Value);
|
||||
pwm = (byte)(pwmValue * byte.MaxValue / _maxLedPower);
|
||||
}
|
||||
}
|
||||
|
||||
if (waitG4Regex.Count >= 1 && waitG4Regex[0].Success)
|
||||
{
|
||||
lightOffDelay = ConvertToSeconds(float.Parse(waitG4Regex[0].Groups[1].Value, CultureInfo.InvariantCulture));
|
||||
|
||||
if (waitG4Regex.Count >= 2 && waitG4Regex[1].Success)
|
||||
{
|
||||
exposureTime = ConvertToSeconds(float.Parse(waitG4Regex[1].Groups[1].Value, CultureInfo.InvariantCulture));
|
||||
}
|
||||
else // Only one match, meaning light off delay is not present and the only time is the cure time
|
||||
{
|
||||
exposureTime = lightOffDelay;
|
||||
lightOffDelay = slicerFile.GetInitialLayerValueOrNormal(layerIndex, slicerFile.BottomLightOffDelay, slicerFile.LightOffDelay);
|
||||
}
|
||||
}
|
||||
|
||||
layer.PositionZ = positionZ;
|
||||
layer.ExposureTime = exposureTime;
|
||||
layer.LiftHeight = liftHeight;
|
||||
layer.LiftSpeed = liftSpeed;
|
||||
layer.RetractSpeed = retractSpeed;
|
||||
layer.LightOffDelay = lightOffDelay;
|
||||
layer.LightPWM = pwm;
|
||||
}
|
||||
*/
|
||||
|
||||
if (rebuildGlobalTable)
|
||||
{
|
||||
slicerFile.UpdateGlobalPropertiesFromLayers();
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using Emgu.CV;
|
||||
@@ -64,7 +65,7 @@ public abstract class Aperture
|
||||
case "C":
|
||||
{
|
||||
if (match.Groups.Count < 4) return null;
|
||||
if (!double.TryParse(match.Groups[3].Value, out var diameter)) return null;
|
||||
if (!double.TryParse(match.Groups[3].Value, NumberStyles.Float, CultureInfo.InvariantCulture, out var diameter)) return null;
|
||||
return new CircleAperture(document, index, diameter);
|
||||
}
|
||||
case "O":
|
||||
@@ -72,8 +73,8 @@ public abstract class Aperture
|
||||
if (match.Groups.Count < 4) return null;
|
||||
var split = match.Groups[3].Value.Split('X', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
|
||||
if (split.Length < 2) return null;
|
||||
if (!float.TryParse(split[0], out var width)) return null;
|
||||
if (!float.TryParse(split[1], out var height)) return null;
|
||||
if (!float.TryParse(split[0], NumberStyles.Float, CultureInfo.InvariantCulture, out var width)) return null;
|
||||
if (!float.TryParse(split[1], NumberStyles.Float, CultureInfo.InvariantCulture, out var height)) return null;
|
||||
|
||||
return new EllipseAperture(document, index, width, height);
|
||||
}
|
||||
@@ -82,8 +83,8 @@ public abstract class Aperture
|
||||
if (match.Groups.Count < 4) return null;
|
||||
var split = match.Groups[3].Value.Split('X', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
|
||||
if (split.Length < 2) return null;
|
||||
if (!float.TryParse(split[0], out var width)) return null;
|
||||
if (!float.TryParse(split[1], out var height)) return null;
|
||||
if (!float.TryParse(split[0], NumberStyles.Float, CultureInfo.InvariantCulture, out var width)) return null;
|
||||
if (!float.TryParse(split[1], NumberStyles.Float, CultureInfo.InvariantCulture, out var height)) return null;
|
||||
|
||||
return new RectangleAperture(document, index, width, height);
|
||||
}
|
||||
@@ -92,8 +93,8 @@ public abstract class Aperture
|
||||
if (match.Groups.Count < 4) return null;
|
||||
var split = match.Groups[3].Value.Split('X', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
|
||||
if (split.Length < 2) return null;
|
||||
if (!double.TryParse(split[0], out var diameter)) return null;
|
||||
if (!ushort.TryParse(split[1], out var vertices)) return null;
|
||||
if (!double.TryParse(split[0], NumberStyles.Float, CultureInfo.InvariantCulture, out var diameter)) return null;
|
||||
if (!ushort.TryParse(split[1], NumberStyles.Float, CultureInfo.InvariantCulture, out var vertices)) return null;
|
||||
|
||||
return new PolygonAperture(document, index, diameter, vertices);
|
||||
}
|
||||
@@ -112,7 +113,7 @@ public abstract class Aperture
|
||||
|
||||
foreach (var primitive in macro)
|
||||
{
|
||||
primitive.ParseExpressions(document, args);
|
||||
primitive.ParseExpressions(args);
|
||||
}
|
||||
|
||||
return new MacroAperture(document, index, macro);
|
||||
|
||||
@@ -34,7 +34,7 @@ public class MacroAperture : Aperture
|
||||
foreach (var primitive in Macro)
|
||||
{
|
||||
//if(primitive.Name == "Comment") continue;
|
||||
primitive.DrawFlashD3(mat, at, color, lineType);
|
||||
primitive.DrawFlashD3(mat, at, lineType);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -31,8 +31,7 @@ public class PolygonAperture : Aperture
|
||||
Vertices = vertices;
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
public override void DrawFlashD3(Mat mat, PointF at, MCvScalar color, LineType lineType = LineType.EightConnected)
|
||||
{
|
||||
mat.DrawPolygon(Vertices, Document.SizeMmToPx(Diameter / 2), Document.PositionMmToPx(at), color, 0, -1, lineType);
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Text.RegularExpressions;
|
||||
using Emgu.CV;
|
||||
@@ -50,17 +51,20 @@ public class GerberDocument
|
||||
|
||||
public SizeF XYppmm { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the X offset for drawings in millimeters
|
||||
/// </summary>
|
||||
public float OffsetX { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the Y offset for drawings in millimeters
|
||||
/// </summary>
|
||||
public float OffsetY { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current polarity as <see cref="MCvScalar"/>. <see cref="InversePolarity"/> will affect the return value
|
||||
/// </summary>
|
||||
public MCvScalar PolarityColor =>
|
||||
Polarity == GerberPolarityType.Dark
|
||||
? !InversePolarity
|
||||
? EmguExtensions.WhiteColor
|
||||
: EmguExtensions.BlackColor
|
||||
: !InversePolarity
|
||||
? EmguExtensions.BlackColor
|
||||
: EmguExtensions.WhiteColor;
|
||||
public MCvScalar PolarityColor => GetPolarityColor(Polarity);
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets to inverse the polarity on drawing
|
||||
@@ -95,7 +99,6 @@ public class GerberDocument
|
||||
double currentX = 0;
|
||||
double currentY = 0;
|
||||
Aperture? currentAperture = null;
|
||||
Macro? currentMacro = null;
|
||||
var regionPoints = new List<Point>();
|
||||
bool insideRegion = false;
|
||||
string? line;
|
||||
@@ -105,12 +108,6 @@ public class GerberDocument
|
||||
if (line == string.Empty) continue;
|
||||
if (line.StartsWith("M02")) break;
|
||||
|
||||
if (currentMacro is not null && line[0] == '%')
|
||||
{
|
||||
currentMacro = null;
|
||||
continue;
|
||||
}
|
||||
|
||||
var accumulatedLine = line;
|
||||
while (!accumulatedLine.Contains('*') && (line = file.ReadLine()) is not null)
|
||||
{
|
||||
@@ -121,13 +118,6 @@ public class GerberDocument
|
||||
|
||||
line = accumulatedLine;
|
||||
|
||||
if (currentMacro is not null)
|
||||
{
|
||||
currentMacro.ParsePrimitive(line);
|
||||
if (line[^1] == '%') currentMacro = null;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (line.StartsWith("%MO") && line.Length >= MOlength)
|
||||
{
|
||||
if (line[3] == 'M' && line[4] == 'M') document.UnitType = GerberUnitType.Millimeter;
|
||||
@@ -240,10 +230,26 @@ public class GerberDocument
|
||||
|
||||
if (line.StartsWith("%AM"))
|
||||
{
|
||||
currentMacro = Macro.Parse(document, line);
|
||||
if (currentMacro is null) continue;
|
||||
document.Macros.Add(currentMacro.Name, currentMacro);
|
||||
//document.Apertures.Add(aperture.Index, aperture);
|
||||
accumulatedLine = line.Remove(0, 1);
|
||||
while (!accumulatedLine.Contains('%') && (line = file.ReadLine()) is not null)
|
||||
{
|
||||
line = line.Trim();
|
||||
if (line == string.Empty) continue;
|
||||
accumulatedLine += line;
|
||||
}
|
||||
line = accumulatedLine[..^2];
|
||||
|
||||
var split = line.Split(new[]{'*', '%'}, StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
|
||||
|
||||
var macro = Macro.Parse(document, split[0]);
|
||||
if (macro is null) continue;
|
||||
document.Macros.Add(macro.Name, macro);
|
||||
|
||||
for (int i = 1; i < split.Length; i++)
|
||||
{
|
||||
macro.ParsePrimitive(split[i]);
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -296,7 +302,7 @@ public class GerberDocument
|
||||
|
||||
var integers = valueStr[..document.CoordinateXIntegers];
|
||||
var fraction = valueStr[document.CoordinateXIntegers..];
|
||||
double.TryParse($"{integers}.{fraction}", out nowX);
|
||||
double.TryParse($"{integers}.{fraction}", NumberStyles.Float, CultureInfo.InvariantCulture, out nowX);
|
||||
nowX = document.GetMillimeters(nowX);
|
||||
}
|
||||
}
|
||||
@@ -317,7 +323,7 @@ public class GerberDocument
|
||||
|
||||
var integers = valueStr[..document.CoordinateYIntegers];
|
||||
var fraction = valueStr[document.CoordinateYIntegers..];
|
||||
double.TryParse($"{integers}.{fraction}", out nowY);
|
||||
double.TryParse($"{integers}.{fraction}", NumberStyles.Float, CultureInfo.InvariantCulture, out nowY);
|
||||
nowY = document.GetMillimeters(nowY);
|
||||
|
||||
}
|
||||
@@ -366,7 +372,7 @@ public class GerberDocument
|
||||
|
||||
var integers = valueStr[..document.CoordinateXIntegers];
|
||||
var fraction = valueStr[document.CoordinateXIntegers..];
|
||||
double.TryParse($"{integers}.{fraction}", out xOffset);
|
||||
double.TryParse($"{integers}.{fraction}", NumberStyles.Float, CultureInfo.InvariantCulture, out xOffset);
|
||||
xOffset = document.GetMillimeters(xOffset);
|
||||
|
||||
|
||||
@@ -379,7 +385,7 @@ public class GerberDocument
|
||||
|
||||
integers = valueStr[..document.CoordinateYIntegers];
|
||||
fraction = valueStr[document.CoordinateYIntegers..];
|
||||
double.TryParse($"{integers}.{fraction}", out yOffset);
|
||||
double.TryParse($"{integers}.{fraction}", NumberStyles.Float, CultureInfo.InvariantCulture, out yOffset);
|
||||
yOffset = document.GetMillimeters(yOffset);
|
||||
|
||||
|
||||
@@ -449,12 +455,14 @@ public class GerberDocument
|
||||
}
|
||||
}
|
||||
|
||||
public static GerberDocument ParseAndDraw(OperationPCBExposure.PCBExposureFile file, Mat mat, SizeF xyPpmm, GerberMidpointRounding sizeMidpointRounding = GerberMidpointRounding.AwayFromZero, bool enableAntiAliasing = false)
|
||||
public static GerberDocument ParseAndDraw(OperationPCBExposure.PCBExposureFile file, Mat mat, SizeF xyPpmm, GerberMidpointRounding sizeMidpointRounding = GerberMidpointRounding.AwayFromZero, SizeF offset = default, bool enableAntiAliasing = false)
|
||||
{
|
||||
var document = new GerberDocument
|
||||
{
|
||||
SizeMidpointRounding = sizeMidpointRounding,
|
||||
XYppmm = xyPpmm,
|
||||
OffsetX = offset.Width,
|
||||
OffsetY = offset.Height,
|
||||
InversePolarity = file.InvertPolarity,
|
||||
SizeScale = file.SizeScale
|
||||
};
|
||||
@@ -464,12 +472,14 @@ public class GerberDocument
|
||||
return document;
|
||||
}
|
||||
|
||||
public static GerberDocument ParseAndDraw(string filePath, Mat mat, SizeF xyPpmm, GerberMidpointRounding sizeMidpointRounding = GerberMidpointRounding.AwayFromZero, bool enableAntiAliasing = false)
|
||||
public static GerberDocument ParseAndDraw(string filePath, Mat mat, SizeF xyPpmm, GerberMidpointRounding sizeMidpointRounding = GerberMidpointRounding.AwayFromZero, SizeF offset = default, bool enableAntiAliasing = false)
|
||||
{
|
||||
var document = new GerberDocument
|
||||
{
|
||||
SizeMidpointRounding = sizeMidpointRounding,
|
||||
XYppmm = xyPpmm
|
||||
XYppmm = xyPpmm,
|
||||
OffsetX = offset.Width,
|
||||
OffsetY = offset.Height
|
||||
};
|
||||
|
||||
ParseAndDraw(document, filePath, mat, enableAntiAliasing);
|
||||
@@ -477,6 +487,18 @@ public class GerberDocument
|
||||
return document;
|
||||
}
|
||||
|
||||
public MCvScalar GetPolarityColor(GerberPolarityType polarity) => polarity == GerberPolarityType.Dark
|
||||
? !InversePolarity ? EmguExtensions.WhiteColor : EmguExtensions.BlackColor
|
||||
: !InversePolarity ? EmguExtensions.BlackColor : EmguExtensions.WhiteColor;
|
||||
|
||||
public MCvScalar GetPolarityColor(bool polarity) => polarity
|
||||
? !InversePolarity ? EmguExtensions.WhiteColor : EmguExtensions.BlackColor
|
||||
: !InversePolarity ? EmguExtensions.BlackColor : EmguExtensions.WhiteColor;
|
||||
|
||||
public MCvScalar GetPolarityColor(int polarity) => polarity > 0
|
||||
? !InversePolarity ? EmguExtensions.WhiteColor : EmguExtensions.BlackColor
|
||||
: !InversePolarity ? EmguExtensions.BlackColor : EmguExtensions.WhiteColor;
|
||||
|
||||
public float GetMillimeters(float size)
|
||||
{
|
||||
if (UnitType == GerberUnitType.Millimeter) return size;
|
||||
@@ -502,13 +524,13 @@ public class GerberDocument
|
||||
}
|
||||
|
||||
public Point PositionMmToPx(PointF atMm)
|
||||
=> new((int)Math.Round(atMm.X * XYppmm.Width, MidpointRounding.AwayFromZero), (int)Math.Round(atMm.Y * XYppmm.Height, MidpointRounding.AwayFromZero));
|
||||
=> new((int)Math.Round((atMm.X + OffsetX) * XYppmm.Width, MidpointRounding.AwayFromZero), (int)Math.Round((atMm.Y + OffsetY) * XYppmm.Height, MidpointRounding.AwayFromZero));
|
||||
|
||||
public Point PositionMmToPx(double atXmm, double atYmm)
|
||||
=> new((int)Math.Round(atXmm * XYppmm.Width, MidpointRounding.AwayFromZero), (int)Math.Round(atYmm * XYppmm.Height, MidpointRounding.AwayFromZero));
|
||||
=> new((int)Math.Round((atXmm + OffsetX) * XYppmm.Width, MidpointRounding.AwayFromZero), (int)Math.Round((atYmm + OffsetY) * XYppmm.Height, MidpointRounding.AwayFromZero));
|
||||
|
||||
public Point PositionMmToPx(float atXmm, float atYmm)
|
||||
=> new((int)Math.Round(atXmm * XYppmm.Width, MidpointRounding.AwayFromZero), (int)Math.Round(atYmm * XYppmm.Height, MidpointRounding.AwayFromZero));
|
||||
=> new((int)Math.Round((atXmm + OffsetX) * XYppmm.Width, MidpointRounding.AwayFromZero), (int)Math.Round((atYmm + OffsetY) * XYppmm.Height, MidpointRounding.AwayFromZero));
|
||||
|
||||
public Size SizeMmToPx(SizeF sizeMm)
|
||||
=> new((int)Math.Max(1, Math.Round(sizeMm.Width * XYppmm.Width * SizeScale, (MidpointRounding)SizeMidpointRounding)),
|
||||
@@ -557,7 +579,7 @@ public class GerberDocument
|
||||
{
|
||||
parseLine = parseLine.Substring(4, parseLine.Length-5);
|
||||
var split = parseLine.Split(' ');
|
||||
location = new PointF(float.Parse(split[0]), float.Parse(split[1]));
|
||||
location = new PointF(float.Parse(split[0], CultureInfo.InvariantCulture), float.Parse(split[1], CultureInfo.InvariantCulture));
|
||||
continue;
|
||||
}
|
||||
if (parseLine.StartsWith("(segment ") || parseLine.StartsWith("(gr_line "))
|
||||
@@ -575,8 +597,8 @@ public class GerberDocument
|
||||
if (!widthMatch.Success || widthMatch.Groups.Count < 2) continue;
|
||||
|
||||
var startXf = new PointF(float.Parse(startMatch.Groups[1].Value), float.Parse(startMatch.Groups[2].Value));
|
||||
var endXf = new PointF(float.Parse(endMatch.Groups[1].Value), float.Parse(endMatch.Groups[2].Value));
|
||||
var widthf = float.Parse(widthMatch.Groups[1].Value);
|
||||
var endXf = new PointF(float.Parse(endMatch.Groups[1].Value, CultureInfo.InvariantCulture), float.Parse(endMatch.Groups[2].Value, CultureInfo.InvariantCulture));
|
||||
var widthf = float.Parse(widthMatch.Groups[1].Value, CultureInfo.InvariantCulture);
|
||||
|
||||
var startX = new System.Drawing.Point((int)(startXf.X * pixelsPerMm), (int)(startXf.Y * pixelsPerMm));
|
||||
var endX = new System.Drawing.Point((int)(endXf.X * pixelsPerMm), (int)(endXf.Y * pixelsPerMm));
|
||||
@@ -598,12 +620,12 @@ public class GerberDocument
|
||||
var drillMatch = Regex.Match(parseLine, @"\(drill\s+(\S+)\)");
|
||||
|
||||
|
||||
var atf = new PointF(float.Parse(atMatch.Groups[1].Value), float.Parse(atMatch.Groups[2].Value));
|
||||
//var sizef = new SizeF(float.Parse(sizeMatch.Groups[1].Value), float.Parse(sizeMatch.Groups[2].Value));
|
||||
var atf = new PointF(float.Parse(atMatch.Groups[1].Value, CultureInfo.InvariantCulture), float.Parse(atMatch.Groups[2].Value, CultureInfo.InvariantCulture));
|
||||
//var sizef = new SizeF(float.Parse(sizeMatch.Groups[1].Value, CultureInfo.InvariantCulture), float.Parse(sizeMatch.Groups[2].Value, CultureInfo.InvariantCulture));
|
||||
|
||||
var at = new System.Drawing.Point((int)(atf.X * pixelsPerMm), (int)(atf.Y * pixelsPerMm));
|
||||
if (!drillMatch.Success || drillMatch.Groups.Count < 2) continue;
|
||||
var drillf = float.Parse(drillMatch.Groups[1].Value);
|
||||
var drillf = float.Parse(drillMatch.Groups[1].Value, CultureInfo.InvariantCulture);
|
||||
var drill = (int) (drillf * pixelsPerMm / 2);
|
||||
|
||||
CvInvoke.Circle(mat, at, drill, EmguExtensions.WhiteColor, -1);
|
||||
@@ -626,11 +648,11 @@ public class GerberDocument
|
||||
var widthMatch = Regex.Match(parseLine, @"\(width\s+(\S+)\)");
|
||||
if (!widthMatch.Success || widthMatch.Groups.Count < 2) continue;
|
||||
|
||||
var atf = new PointF(float.Parse(atMatch.Groups[1].Value), float.Parse(atMatch.Groups[2].Value));
|
||||
var atf = new PointF(float.Parse(atMatch.Groups[1].Value, CultureInfo.InvariantCulture), float.Parse(atMatch.Groups[2].Value, CultureInfo.InvariantCulture));
|
||||
var at = new System.Drawing.Point((int)(atf.X * pixelsPerMm), (int)(atf.Y * pixelsPerMm));
|
||||
var endf = new PointF(float.Parse(endMatch.Groups[1].Value), float.Parse(endMatch.Groups[2].Value));
|
||||
var endf = new PointF(float.Parse(endMatch.Groups[1].Value, CultureInfo.InvariantCulture), float.Parse(endMatch.Groups[2].Value, CultureInfo.InvariantCulture));
|
||||
var radius = (int)(Math.Max(Math.Abs(atf.X - endf.X), Math.Abs(atf.Y - endf.Y)) * pixelsPerMm);
|
||||
var widthf = float.Parse(widthMatch.Groups[1].Value);
|
||||
var widthf = float.Parse(widthMatch.Groups[1].Value, CultureInfo.InvariantCulture);
|
||||
var width = (int)(widthf * pixelsPerMm);
|
||||
|
||||
CvInvoke.Circle(mat, at, radius, EmguExtensions.WhiteColor, width);
|
||||
@@ -656,9 +678,9 @@ public class GerberDocument
|
||||
var widthMatch = Regex.Match(parseLine, @"\(width\s+(\S+)\)");
|
||||
if (!widthMatch.Success || widthMatch.Groups.Count < 2) continue;
|
||||
|
||||
var startf = new PointF(float.Parse(startMatch.Groups[1].Value), float.Parse(startMatch.Groups[2].Value));
|
||||
var endf = new PointF(float.Parse(endMatch.Groups[1].Value), float.Parse(endMatch.Groups[2].Value));
|
||||
var widthf = float.Parse(widthMatch.Groups[1].Value);
|
||||
var startf = new PointF(float.Parse(startMatch.Groups[1].Value, CultureInfo.InvariantCulture), float.Parse(startMatch.Groups[2].Value, CultureInfo.InvariantCulture));
|
||||
var endf = new PointF(float.Parse(endMatch.Groups[1].Value, CultureInfo.InvariantCulture), float.Parse(endMatch.Groups[2].Value, CultureInfo.InvariantCulture));
|
||||
var widthf = float.Parse(widthMatch.Groups[1].Value, CultureInfo.InvariantCulture);
|
||||
|
||||
var start = new System.Drawing.Point((int)(startf.X * pixelsPerMm), (int)(startf.Y * pixelsPerMm));
|
||||
var end = new System.Drawing.Point((int)(endf.X * pixelsPerMm), (int)(endf.Y * pixelsPerMm));
|
||||
@@ -689,8 +711,8 @@ public class GerberDocument
|
||||
var drillMatch = Regex.Match(parseLine, @"\(drill\s+(\S+)\)");
|
||||
|
||||
|
||||
var atf = new PointF(float.Parse(atMatch.Groups[1].Value), float.Parse(atMatch.Groups[2].Value));
|
||||
var sizef = new SizeF(float.Parse(sizeMatch.Groups[1].Value), float.Parse(sizeMatch.Groups[2].Value));
|
||||
var atf = new PointF(float.Parse(atMatch.Groups[1].Value, CultureInfo.InvariantCulture), float.Parse(atMatch.Groups[2].Value, CultureInfo.InvariantCulture));
|
||||
var sizef = new SizeF(float.Parse(sizeMatch.Groups[1].Value, CultureInfo.InvariantCulture), float.Parse(sizeMatch.Groups[2].Value, CultureInfo.InvariantCulture));
|
||||
|
||||
var at = new System.Drawing.Point((int)(location.X * pixelsPerMm + atf.X * pixelsPerMm), (int)(location.Y * pixelsPerMm + atf.Y * pixelsPerMm));
|
||||
|
||||
@@ -709,7 +731,7 @@ public class GerberDocument
|
||||
|
||||
if (drillMatch.Success && drillMatch.Groups.Count >= 2)
|
||||
{
|
||||
var drillf = float.Parse(drillMatch.Groups[1].Value);
|
||||
var drillf = float.Parse(drillMatch.Groups[1].Value, CultureInfo.InvariantCulture);
|
||||
var drill = (int)(drillf * pixelsPerMm / 2);
|
||||
|
||||
drillPoints.Add(new KeyValuePair<Point, int>(at, drill));
|
||||
|
||||
@@ -42,6 +42,8 @@ public class Macro : IReadOnlyList<Primitive>
|
||||
{
|
||||
line = line.TrimEnd('%', '*');
|
||||
|
||||
if(line.Length == 0) return;
|
||||
|
||||
// 0 Comment: A comment string
|
||||
if (line[0] == '0')
|
||||
{
|
||||
@@ -108,7 +110,7 @@ public class Macro : IReadOnlyList<Primitive>
|
||||
|
||||
public static Macro? Parse(GerberDocument document, string line)
|
||||
{
|
||||
var match = Regex.Match(line, @"\%AM(\S+)\*");
|
||||
var match = Regex.Match(line, @"%?AM([a-zA-Z\d]+)\*?");
|
||||
if (!match.Success || match.Groups.Count < 2) return null;
|
||||
|
||||
return new Macro(document, match.Groups[1].Value);
|
||||
|
||||
@@ -6,12 +6,13 @@
|
||||
* of this license document, but changing it is not allowed.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Data;
|
||||
using System.Drawing;
|
||||
using System.Globalization;
|
||||
using System.Text.RegularExpressions;
|
||||
using Emgu.CV;
|
||||
using Emgu.CV.CvEnum;
|
||||
using Emgu.CV.Structure;
|
||||
using UVtools.Core.Extensions;
|
||||
|
||||
namespace UVtools.Core.Gerber.Primitives;
|
||||
@@ -87,24 +88,17 @@ public class CenterLinePrimitive : Primitive
|
||||
}
|
||||
|
||||
|
||||
public override void DrawFlashD3(Mat mat, PointF at, MCvScalar color, LineType lineType = LineType.EightConnected)
|
||||
public override void DrawFlashD3(Mat mat, PointF at, LineType lineType = LineType.EightConnected)
|
||||
{
|
||||
if (!IsParsed) return;
|
||||
if (Width <= 0 || Height <= 0) return;
|
||||
|
||||
if (Exposure == 0) color = EmguExtensions.BlackColor;
|
||||
else if(color.V0 == 0) color = EmguExtensions.WhiteColor;
|
||||
|
||||
var halfWidth = Width / 2;
|
||||
var pt1 = Document.PositionMmToPx(at.X + CenterX - halfWidth, at.Y + CenterY);
|
||||
var pt2 = Document.PositionMmToPx(at.X + CenterX + halfWidth, at.Y + CenterY);
|
||||
CvInvoke.Line(mat, pt1, pt2, color, EmguExtensions.CorrectThickness(Document.SizeMmToPxOverride(Height, Document.XYppmm.Height)), lineType);
|
||||
//CvInvoke.Rectangle(mat, rectangle, color, -1, lineType);
|
||||
mat.DrawRotatedRectangle(Document.SizeMmToPx(Width, Height), Document.PositionMmToPx(at.X + CenterX, at.Y + CenterY), Document.GetPolarityColor(Exposure), (int) Rotation, -1, lineType);
|
||||
}
|
||||
|
||||
public override void ParseExpressions(GerberDocument document, params string[] args)
|
||||
public override void ParseExpressions(params string[] args)
|
||||
{
|
||||
string csharpExp, result;
|
||||
string csharpExp;
|
||||
float num;
|
||||
var exp = new DataTable();
|
||||
|
||||
@@ -112,57 +106,57 @@ public class CenterLinePrimitive : Primitive
|
||||
else
|
||||
{
|
||||
csharpExp = string.Format(Regex.Replace(ExposureExpression, @"\$(\d+)", "{$1}"), args);
|
||||
result = exp.Compute(csharpExp, null).ToString()!;
|
||||
if (byte.TryParse(result, out var val)) Exposure = val;
|
||||
var temp = exp.Compute(csharpExp, null);
|
||||
if(temp is not DBNull) Exposure = Convert.ToByte(temp);
|
||||
}
|
||||
|
||||
if (float.TryParse(WidthExpression, out num)) Width = num;
|
||||
if (float.TryParse(WidthExpression, NumberStyles.Float, CultureInfo.InvariantCulture, out num)) Width = num;
|
||||
else
|
||||
{
|
||||
csharpExp = Regex.Replace(WidthExpression, @"\$(\d+)", "{$1}");
|
||||
csharpExp = string.Format(csharpExp, args);
|
||||
result = exp.Compute(csharpExp, null).ToString()!;
|
||||
if (float.TryParse(result, out var val)) Width = val;
|
||||
var temp = exp.Compute(csharpExp, null);
|
||||
if (temp is not DBNull) Width = Convert.ToSingle(temp);
|
||||
}
|
||||
Width = document.GetMillimeters(Width);
|
||||
Width = Document.GetMillimeters(Width);
|
||||
|
||||
if (float.TryParse(HeightExpression, out num)) Height = num;
|
||||
if (float.TryParse(HeightExpression, NumberStyles.Float, CultureInfo.InvariantCulture, out num)) Height = num;
|
||||
else
|
||||
{
|
||||
csharpExp = Regex.Replace(HeightExpression, @"\$(\d+)", "{$1}");
|
||||
csharpExp = string.Format(csharpExp, args);
|
||||
result = exp.Compute(csharpExp, null).ToString()!;
|
||||
if (float.TryParse(result, out var val)) Height = val;
|
||||
var temp = exp.Compute(csharpExp, null);
|
||||
if (temp is not DBNull) Height = Convert.ToSingle(temp);
|
||||
}
|
||||
Height = document.GetMillimeters(Height);
|
||||
Height = Document.GetMillimeters(Height);
|
||||
|
||||
if (float.TryParse(CenterXExpression, out num)) CenterX = num;
|
||||
if (float.TryParse(CenterXExpression, NumberStyles.Float, CultureInfo.InvariantCulture, out num)) CenterX = num;
|
||||
else
|
||||
{
|
||||
csharpExp = Regex.Replace(CenterXExpression, @"\$(\d+)", "{$1}");
|
||||
csharpExp = string.Format(csharpExp, args);
|
||||
result = exp.Compute(csharpExp, null).ToString()!;
|
||||
if (float.TryParse(result, out num)) CenterX = num;
|
||||
var temp = exp.Compute(csharpExp, null);
|
||||
if (temp is not DBNull) CenterX = Convert.ToSingle(temp);
|
||||
}
|
||||
CenterX = document.GetMillimeters(CenterX);
|
||||
CenterX = Document.GetMillimeters(CenterX);
|
||||
|
||||
if (float.TryParse(CenterYExpression, out num)) CenterY = num;
|
||||
if (float.TryParse(CenterYExpression, NumberStyles.Float, CultureInfo.InvariantCulture, out num)) CenterY = num;
|
||||
else
|
||||
{
|
||||
csharpExp = Regex.Replace(CenterYExpression, @"\$(\d+)", "{$1}");
|
||||
csharpExp = string.Format(csharpExp, args);
|
||||
result = exp.Compute(csharpExp, null).ToString()!;
|
||||
if (float.TryParse(result, out num)) CenterY = num;
|
||||
var temp = exp.Compute(csharpExp, null);
|
||||
if (temp is not DBNull) CenterY = Convert.ToSingle(temp);
|
||||
}
|
||||
CenterY = document.GetMillimeters(CenterY);
|
||||
CenterY = Document.GetMillimeters(CenterY);
|
||||
|
||||
if (float.TryParse(RotationExpression, out num)) Rotation = (short)num;
|
||||
if (float.TryParse(RotationExpression, NumberStyles.Float, CultureInfo.InvariantCulture, out num)) Rotation = (short)num;
|
||||
else
|
||||
{
|
||||
csharpExp = Regex.Replace(RotationExpression, @"\$(\d+)", "{$1}");
|
||||
csharpExp = string.Format(csharpExp, args);
|
||||
result = exp.Compute(csharpExp, null).ToString()!;
|
||||
if (float.TryParse(result, out num)) Rotation = num;
|
||||
var temp = exp.Compute(csharpExp, null);
|
||||
if (temp is not DBNull) Rotation = Convert.ToSingle(temp);
|
||||
}
|
||||
|
||||
IsParsed = true;
|
||||
|
||||
@@ -6,13 +6,13 @@
|
||||
* of this license document, but changing it is not allowed.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Data;
|
||||
using System.Drawing;
|
||||
using System.Globalization;
|
||||
using System.Text.RegularExpressions;
|
||||
using Emgu.CV;
|
||||
using Emgu.CV.CvEnum;
|
||||
using Emgu.CV.Structure;
|
||||
using UVtools.Core.Extensions;
|
||||
|
||||
namespace UVtools.Core.Gerber.Primitives;
|
||||
|
||||
@@ -78,23 +78,19 @@ public class CirclePrimitive : Primitive
|
||||
RotationExpression = rotationExpression;
|
||||
}
|
||||
|
||||
public override void DrawFlashD3(Mat mat, PointF at, MCvScalar color,
|
||||
LineType lineType = LineType.EightConnected)
|
||||
public override void DrawFlashD3(Mat mat, PointF at, LineType lineType = LineType.EightConnected)
|
||||
{
|
||||
if (!IsParsed) return;
|
||||
if (Diameter <= 0) return;
|
||||
|
||||
if (Exposure == 0) color = EmguExtensions.BlackColor;
|
||||
else if (color.V0 == 0) color = EmguExtensions.WhiteColor;
|
||||
|
||||
CvInvoke.Circle(mat,
|
||||
Document.PositionMmToPx(at.X + CenterX, at.Y + CenterY),
|
||||
Document.SizeMmToPx(Diameter / 2), color, -1, lineType);
|
||||
Document.SizeMmToPx(Diameter / 2), Document.GetPolarityColor(Exposure), -1, lineType);
|
||||
}
|
||||
|
||||
public override void ParseExpressions(GerberDocument document, params string[] args)
|
||||
public override void ParseExpressions(params string[] args)
|
||||
{
|
||||
string csharpExp, result;
|
||||
string csharpExp;
|
||||
float num;
|
||||
var exp = new DataTable();
|
||||
|
||||
@@ -102,48 +98,48 @@ public class CirclePrimitive : Primitive
|
||||
else
|
||||
{
|
||||
csharpExp = string.Format(Regex.Replace(ExposureExpression, @"\$(\d+)", "{$1}"), args);
|
||||
result = exp.Compute(csharpExp, null).ToString()!;
|
||||
if (byte.TryParse(result, out var val)) Exposure = val;
|
||||
var temp = exp.Compute(csharpExp, null);
|
||||
if (temp is not DBNull) Exposure = Convert.ToByte(temp);
|
||||
}
|
||||
|
||||
if (float.TryParse(DiameterExpression, out num)) Diameter = num;
|
||||
if (float.TryParse(DiameterExpression, NumberStyles.Float, CultureInfo.InvariantCulture, out num)) Diameter = num;
|
||||
else
|
||||
{
|
||||
csharpExp = Regex.Replace(DiameterExpression, @"\$(\d+)", "{$1}");
|
||||
csharpExp = string.Format(csharpExp, args);
|
||||
result = exp.Compute(csharpExp, null).ToString()!;
|
||||
if (float.TryParse(result, out num)) Diameter = num;
|
||||
var temp = exp.Compute(csharpExp, null);
|
||||
if (temp is not DBNull) Diameter = Convert.ToSingle(temp);
|
||||
}
|
||||
Diameter = document.GetMillimeters(Diameter);
|
||||
Diameter = Document.GetMillimeters(Diameter);
|
||||
|
||||
if (float.TryParse(CenterXExpression, out num)) CenterX = num;
|
||||
if (float.TryParse(CenterXExpression, NumberStyles.Float, CultureInfo.InvariantCulture, out num)) CenterX = num;
|
||||
else
|
||||
{
|
||||
csharpExp = Regex.Replace(CenterXExpression, @"\$(\d+)", "{$1}");
|
||||
csharpExp = string.Format(csharpExp, args);
|
||||
result = exp.Compute(csharpExp, null).ToString()!;
|
||||
if (float.TryParse(result, out num)) CenterX = num;
|
||||
var temp = exp.Compute(csharpExp, null);
|
||||
if (temp is not DBNull) CenterX = Convert.ToSingle(temp);
|
||||
}
|
||||
CenterX = document.GetMillimeters(CenterX);
|
||||
CenterX = Document.GetMillimeters(CenterX);
|
||||
|
||||
if (float.TryParse(CenterYExpression, out num)) CenterY = num;
|
||||
if (float.TryParse(CenterYExpression, NumberStyles.Float, CultureInfo.InvariantCulture, out num)) CenterY = num;
|
||||
else
|
||||
{
|
||||
csharpExp = Regex.Replace(CenterYExpression, @"\$(\d+)", "{$1}");
|
||||
csharpExp = string.Format(csharpExp, args);
|
||||
result = exp.Compute(csharpExp, null).ToString()!;
|
||||
if (float.TryParse(result, out num)) CenterY = num;
|
||||
var temp = exp.Compute(csharpExp, null);
|
||||
if (temp is not DBNull) CenterY = Convert.ToSingle(temp);
|
||||
}
|
||||
CenterY = document.GetMillimeters(CenterY);
|
||||
CenterY = Document.GetMillimeters(CenterY);
|
||||
|
||||
|
||||
if (float.TryParse(RotationExpression, out num)) Rotation = (short)num;
|
||||
if (float.TryParse(RotationExpression, NumberStyles.Float, CultureInfo.InvariantCulture, out num)) Rotation = (short)num;
|
||||
else
|
||||
{
|
||||
csharpExp = Regex.Replace(RotationExpression, @"\$(\d+)", "{$1}");
|
||||
csharpExp = string.Format(csharpExp, args);
|
||||
result = exp.Compute(csharpExp, null).ToString()!;
|
||||
if (float.TryParse(result, out num)) Rotation = num;
|
||||
var temp = exp.Compute(csharpExp, null);
|
||||
if (temp is not DBNull) Rotation = Convert.ToSingle(temp);
|
||||
}
|
||||
|
||||
IsParsed = true;
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
using System.Drawing;
|
||||
using Emgu.CV;
|
||||
using Emgu.CV.CvEnum;
|
||||
using Emgu.CV.Structure;
|
||||
|
||||
namespace UVtools.Core.Gerber.Primitives;
|
||||
|
||||
@@ -23,6 +22,7 @@ public class CommentPrimitive : Primitive
|
||||
#region Constants
|
||||
public const byte Code = 0;
|
||||
#endregion
|
||||
|
||||
#region Properties
|
||||
public override string Name => "Comment";
|
||||
|
||||
@@ -45,12 +45,12 @@ public class CommentPrimitive : Primitive
|
||||
}
|
||||
|
||||
|
||||
public override void DrawFlashD3(Mat mat, PointF at, MCvScalar color, LineType lineType = LineType.EightConnected)
|
||||
public override void DrawFlashD3(Mat mat, PointF at, LineType lineType = LineType.EightConnected)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override void ParseExpressions(GerberDocument document, params string[] args)
|
||||
public override void ParseExpressions(params string[] args)
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -10,13 +10,12 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Drawing;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using Emgu.CV;
|
||||
using Emgu.CV.CvEnum;
|
||||
using Emgu.CV.Structure;
|
||||
using Emgu.CV.Util;
|
||||
using UVtools.Core.Extensions;
|
||||
|
||||
namespace UVtools.Core.Gerber.Primitives;
|
||||
|
||||
@@ -76,12 +75,14 @@ public class OutlinePrimitive : Primitive
|
||||
}
|
||||
|
||||
|
||||
public override void DrawFlashD3(Mat mat, PointF at, MCvScalar color, LineType lineType = LineType.EightConnected)
|
||||
public override void DrawFlashD3(Mat mat, PointF at, LineType lineType = LineType.EightConnected)
|
||||
{
|
||||
if (Coordinates.Length < 3) return;
|
||||
|
||||
if (Exposure == 0) color = EmguExtensions.BlackColor;
|
||||
else if (color.V0 == 0) color = EmguExtensions.WhiteColor;
|
||||
if (Rotation != 0)
|
||||
{
|
||||
throw new NotImplementedException($"{Name} primitive with code {Code} have a rotation value of {Rotation} which is not implemented. Open a issue regarding this problem and provide a sample file to be able to implement rotation correctly on this primitive.");
|
||||
}
|
||||
|
||||
var points = new List<Point>();
|
||||
for (int i = 0; i < Coordinates.Length-1; i++)
|
||||
@@ -92,12 +93,12 @@ public class OutlinePrimitive : Primitive
|
||||
}
|
||||
|
||||
using var vec = new VectorOfPoint(points.ToArray());
|
||||
CvInvoke.FillPoly(mat, vec, color, lineType);
|
||||
CvInvoke.FillPoly(mat, vec, Document.GetPolarityColor(Exposure), lineType);
|
||||
}
|
||||
|
||||
public override void ParseExpressions(GerberDocument document, params string[] args)
|
||||
public override void ParseExpressions(params string[] args)
|
||||
{
|
||||
string csharpExp, result;
|
||||
string csharpExp;
|
||||
float num;
|
||||
var exp = new DataTable();
|
||||
|
||||
@@ -105,19 +106,19 @@ public class OutlinePrimitive : Primitive
|
||||
else
|
||||
{
|
||||
csharpExp = string.Format(Regex.Replace(ExposureExpression, @"\$(\d+)", "{$1}"), args);
|
||||
result = exp.Compute(csharpExp, null).ToString()!;
|
||||
if (byte.TryParse(result, out var val)) Exposure = val;
|
||||
var temp = exp.Compute(csharpExp, null);
|
||||
if (temp is not DBNull) Exposure = Convert.ToByte(temp);
|
||||
}
|
||||
|
||||
float? x = null;
|
||||
var coordinates = new List<PointF>();
|
||||
foreach (var coordinate in CoordinatesExpression)
|
||||
{
|
||||
if (!float.TryParse(coordinate, out num))
|
||||
if (!float.TryParse(coordinate, NumberStyles.Float, CultureInfo.InvariantCulture, out num))
|
||||
{
|
||||
csharpExp = string.Format(Regex.Replace(coordinate, @"\$(\d+)", "{$1}"), args);
|
||||
result = exp.Compute(csharpExp, null).ToString()!;
|
||||
float.TryParse(result, out num);
|
||||
var temp = exp.Compute(csharpExp, null);
|
||||
if (temp is not DBNull) num = Convert.ToSingle(temp);
|
||||
}
|
||||
|
||||
if (x is null)
|
||||
@@ -126,20 +127,20 @@ public class OutlinePrimitive : Primitive
|
||||
}
|
||||
else
|
||||
{
|
||||
coordinates.Add(document.GetMillimeters(new PointF(x.Value, num)));
|
||||
coordinates.Add(Document.GetMillimeters(new PointF(x.Value, num)));
|
||||
x = null;
|
||||
}
|
||||
}
|
||||
|
||||
Coordinates = coordinates.ToArray();
|
||||
|
||||
if (float.TryParse(RotationExpression, out num)) Rotation = (short)num;
|
||||
if (float.TryParse(RotationExpression, NumberStyles.Float, CultureInfo.InvariantCulture, out num)) Rotation = (short)num;
|
||||
else
|
||||
{
|
||||
csharpExp = Regex.Replace(RotationExpression, @"\$(\d+)", "{$1}");
|
||||
csharpExp = string.Format(csharpExp, args);
|
||||
result = exp.Compute(csharpExp, null).ToString()!;
|
||||
if (float.TryParse(result, out num)) Rotation = num;
|
||||
var temp = exp.Compute(csharpExp, null);
|
||||
if (temp is not DBNull) Rotation = Convert.ToSingle(temp);
|
||||
}
|
||||
|
||||
IsParsed = true;
|
||||
|
||||
@@ -6,12 +6,13 @@
|
||||
* of this license document, but changing it is not allowed.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Data;
|
||||
using System.Drawing;
|
||||
using System.Globalization;
|
||||
using System.Text.RegularExpressions;
|
||||
using Emgu.CV;
|
||||
using Emgu.CV.CvEnum;
|
||||
using Emgu.CV.Structure;
|
||||
using UVtools.Core.Extensions;
|
||||
|
||||
namespace UVtools.Core.Gerber.Primitives;
|
||||
@@ -84,25 +85,20 @@ public class PolygonPrimitive : Primitive
|
||||
RotationExpression = rotationExpression;
|
||||
}
|
||||
|
||||
public override void DrawFlashD3(Mat mat, PointF at, MCvScalar color,
|
||||
LineType lineType = LineType.EightConnected)
|
||||
public override void DrawFlashD3(Mat mat, PointF at, LineType lineType = LineType.EightConnected)
|
||||
{
|
||||
if (!IsParsed) return;
|
||||
if (Diameter <= 0) return;
|
||||
|
||||
if (Exposure == 0) color = EmguExtensions.BlackColor;
|
||||
else if (color.V0 == 0) color = EmguExtensions.WhiteColor;
|
||||
|
||||
|
||||
mat.DrawPolygon(VerticesCount,
|
||||
Document.SizeMmToPx(Diameter / 2),
|
||||
Document.PositionMmToPx(at.X + CenterX, at.Y + CenterY),
|
||||
color, 0, -1, lineType);
|
||||
Document.GetPolarityColor(Exposure), Rotation, -1, lineType);
|
||||
}
|
||||
|
||||
public override void ParseExpressions(GerberDocument document, params string[] args)
|
||||
public override void ParseExpressions(params string[] args)
|
||||
{
|
||||
string csharpExp, result;
|
||||
string csharpExp;
|
||||
float num;
|
||||
var exp = new DataTable();
|
||||
|
||||
@@ -110,8 +106,8 @@ public class PolygonPrimitive : Primitive
|
||||
else
|
||||
{
|
||||
csharpExp = string.Format(Regex.Replace(ExposureExpression, @"\$(\d+)", "{$1}"), args);
|
||||
result = exp.Compute(csharpExp, null).ToString()!;
|
||||
if (byte.TryParse(result, out var val)) Exposure = val;
|
||||
var temp = exp.Compute(csharpExp, null);
|
||||
if (temp is not DBNull) Exposure = Convert.ToByte(temp);
|
||||
}
|
||||
|
||||
if (byte.TryParse(DiameterExpression, out var vertices)) VerticesCount = vertices;
|
||||
@@ -119,47 +115,47 @@ public class PolygonPrimitive : Primitive
|
||||
{
|
||||
csharpExp = Regex.Replace(DiameterExpression, @"\$(\d+)", "{$1}");
|
||||
csharpExp = string.Format(csharpExp, args);
|
||||
result = exp.Compute(csharpExp, null).ToString()!;
|
||||
if (byte.TryParse(result, out var vertices1)) VerticesCount = vertices1;
|
||||
var temp = exp.Compute(csharpExp, null);
|
||||
if (temp is not DBNull) VerticesCount = Convert.ToByte(temp);
|
||||
}
|
||||
|
||||
if (float.TryParse(CenterXExpression, out num)) CenterX = num;
|
||||
if (float.TryParse(CenterXExpression, NumberStyles.Float, CultureInfo.InvariantCulture, out num)) CenterX = num;
|
||||
else
|
||||
{
|
||||
csharpExp = Regex.Replace(CenterXExpression, @"\$(\d+)", "{$1}");
|
||||
csharpExp = string.Format(csharpExp, args);
|
||||
result = exp.Compute(csharpExp, null).ToString()!;
|
||||
if (float.TryParse(result, out num)) CenterX = num;
|
||||
var temp = exp.Compute(csharpExp, null);
|
||||
if (temp is not DBNull) CenterX = Convert.ToSingle(temp);
|
||||
}
|
||||
CenterX = document.GetMillimeters(CenterX);
|
||||
CenterX = Document.GetMillimeters(CenterX);
|
||||
|
||||
if (float.TryParse(CenterYExpression, out num)) CenterY = num;
|
||||
if (float.TryParse(CenterYExpression, NumberStyles.Float, CultureInfo.InvariantCulture, out num)) CenterY = num;
|
||||
else
|
||||
{
|
||||
csharpExp = Regex.Replace(CenterYExpression, @"\$(\d+)", "{$1}");
|
||||
csharpExp = string.Format(csharpExp, args);
|
||||
result = exp.Compute(csharpExp, null).ToString()!;
|
||||
if (float.TryParse(result, out num)) CenterY = num;
|
||||
var temp = exp.Compute(csharpExp, null);
|
||||
if (temp is not DBNull) CenterY = Convert.ToSingle(temp);
|
||||
}
|
||||
CenterY = document.GetMillimeters(CenterY);
|
||||
CenterY = Document.GetMillimeters(CenterY);
|
||||
|
||||
if (float.TryParse(DiameterExpression, out num)) Diameter = num;
|
||||
if (float.TryParse(DiameterExpression, NumberStyles.Float, CultureInfo.InvariantCulture, out num)) Diameter = num;
|
||||
else
|
||||
{
|
||||
csharpExp = Regex.Replace(DiameterExpression, @"\$(\d+)", "{$1}");
|
||||
csharpExp = string.Format(csharpExp, args);
|
||||
result = exp.Compute(csharpExp, null).ToString()!;
|
||||
if (float.TryParse(result, out num)) Diameter = num;
|
||||
var temp = exp.Compute(csharpExp, null);
|
||||
if (temp is not DBNull) Diameter = Convert.ToSingle(temp);
|
||||
}
|
||||
Diameter = document.GetMillimeters(Diameter);
|
||||
Diameter = Document.GetMillimeters(Diameter);
|
||||
|
||||
if (float.TryParse(RotationExpression, out num)) Rotation = (short)num;
|
||||
if (float.TryParse(RotationExpression, NumberStyles.Float, CultureInfo.InvariantCulture, out num)) Rotation = (short)num;
|
||||
else
|
||||
{
|
||||
csharpExp = Regex.Replace(RotationExpression, @"\$(\d+)", "{$1}");
|
||||
csharpExp = string.Format(csharpExp, args);
|
||||
result = exp.Compute(csharpExp, null).ToString()!;
|
||||
if (float.TryParse(result, out num)) Rotation = num;
|
||||
var temp = exp.Compute(csharpExp, null);
|
||||
if (temp is not DBNull) Rotation = Convert.ToSingle(temp);
|
||||
}
|
||||
|
||||
IsParsed = true;
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
using System.Drawing;
|
||||
using Emgu.CV;
|
||||
using Emgu.CV.CvEnum;
|
||||
using Emgu.CV.Structure;
|
||||
|
||||
namespace UVtools.Core.Gerber.Primitives;
|
||||
|
||||
@@ -31,9 +30,9 @@ public abstract class Primitive
|
||||
Document = document;
|
||||
}
|
||||
|
||||
public abstract void DrawFlashD3(Mat mat, PointF at, MCvScalar color, LineType lineType = LineType.EightConnected);
|
||||
public abstract void DrawFlashD3(Mat mat, PointF at, LineType lineType = LineType.EightConnected);
|
||||
|
||||
public abstract void ParseExpressions(GerberDocument document, params string[] args);
|
||||
public abstract void ParseExpressions(params string[] args);
|
||||
|
||||
public virtual Primitive Clone() => (Primitive)MemberwiseClone();
|
||||
}
|
||||
@@ -6,12 +6,13 @@
|
||||
* of this license document, but changing it is not allowed.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Data;
|
||||
using System.Drawing;
|
||||
using System.Globalization;
|
||||
using System.Text.RegularExpressions;
|
||||
using Emgu.CV;
|
||||
using Emgu.CV.CvEnum;
|
||||
using Emgu.CV.Structure;
|
||||
using UVtools.Core.Extensions;
|
||||
|
||||
namespace UVtools.Core.Gerber.Primitives;
|
||||
@@ -96,24 +97,25 @@ public class VectorLinePrimitive : Primitive
|
||||
RotationExpression = rotationExpression;
|
||||
}
|
||||
|
||||
public override void DrawFlashD3(Mat mat, PointF at, MCvScalar color,
|
||||
LineType lineType = LineType.EightConnected)
|
||||
public override void DrawFlashD3(Mat mat, PointF at, LineType lineType = LineType.EightConnected)
|
||||
{
|
||||
if (!IsParsed) return;
|
||||
if (LineWidth <= 0) return;
|
||||
|
||||
if (Exposure == 0) color = EmguExtensions.BlackColor;
|
||||
else if (color.V0 == 0) color = EmguExtensions.WhiteColor;
|
||||
if (Rotation != 0)
|
||||
{
|
||||
throw new NotImplementedException($"{Name} primitive with code {Code} have a rotation value of {Rotation} which is not implemented. Open a issue regarding this problem and provide a sample file to be able to implement rotation correctly on this primitive.");
|
||||
}
|
||||
|
||||
var pt1 = Document.PositionMmToPx(at.X + StartX, at.Y + StartY);
|
||||
var pt2 = Document.PositionMmToPx(at.X + EndX, at.Y + EndY);
|
||||
CvInvoke.Line(mat, pt1, pt2, color, EmguExtensions.CorrectThickness(Document.SizeMmToPxOverride(LineWidth, Document.XYppmm.Height)), lineType);
|
||||
CvInvoke.Line(mat, pt1, pt2, Document.GetPolarityColor(Exposure), EmguExtensions.CorrectThickness(Document.SizeMmToPxOverride(LineWidth, Document.XYppmm.Height)), lineType);
|
||||
//CvInvoke.Rectangle(mat, rectangle, color, -1, lineType);
|
||||
}
|
||||
|
||||
public override void ParseExpressions(GerberDocument document, params string[] args)
|
||||
public override void ParseExpressions(params string[] args)
|
||||
{
|
||||
string csharpExp, result;
|
||||
string csharpExp;
|
||||
float num;
|
||||
var exp = new DataTable();
|
||||
|
||||
@@ -121,67 +123,67 @@ public class VectorLinePrimitive : Primitive
|
||||
else
|
||||
{
|
||||
csharpExp = string.Format(Regex.Replace(ExposureExpression, @"\$(\d+)", "{$1}"), args);
|
||||
result = exp.Compute(csharpExp, null).ToString()!;
|
||||
if (byte.TryParse(result, out var val)) Exposure = val;
|
||||
var temp = exp.Compute(csharpExp, null);
|
||||
if (temp is not DBNull) Exposure = Convert.ToByte(temp);
|
||||
}
|
||||
|
||||
if (float.TryParse(LineWidthExpression, out num)) LineWidth = num;
|
||||
if (float.TryParse(LineWidthExpression, NumberStyles.Float, CultureInfo.InvariantCulture, out num)) LineWidth = num;
|
||||
else
|
||||
{
|
||||
csharpExp = Regex.Replace(LineWidthExpression, @"\$(\d+)", "{$1}");
|
||||
csharpExp = string.Format(csharpExp, args);
|
||||
result = exp.Compute(csharpExp, null).ToString()!;
|
||||
if (float.TryParse(result, out var val)) LineWidth = val;
|
||||
var temp = exp.Compute(csharpExp, null);
|
||||
if (temp is not DBNull) LineWidth = Convert.ToSingle(temp);
|
||||
}
|
||||
LineWidth = document.GetMillimeters(LineWidth);
|
||||
LineWidth = Document.GetMillimeters(LineWidth);
|
||||
|
||||
if (float.TryParse(StartXExpression, out num)) StartX = num;
|
||||
if (float.TryParse(StartXExpression, NumberStyles.Float, CultureInfo.InvariantCulture, out num)) StartX = num;
|
||||
else
|
||||
{
|
||||
csharpExp = Regex.Replace(StartXExpression, @"\$(\d+)", "{$1}");
|
||||
csharpExp = string.Format(csharpExp, args);
|
||||
result = exp.Compute(csharpExp, null).ToString()!;
|
||||
if (float.TryParse(result, out num)) StartX = num;
|
||||
var temp = exp.Compute(csharpExp, null);
|
||||
if (temp is not DBNull) StartX = Convert.ToSingle(temp);
|
||||
}
|
||||
StartX = document.GetMillimeters(StartX);
|
||||
StartX = Document.GetMillimeters(StartX);
|
||||
|
||||
if (float.TryParse(EndXExpression, out num)) EndX = num;
|
||||
if (float.TryParse(EndXExpression, NumberStyles.Float, CultureInfo.InvariantCulture, out num)) EndX = num;
|
||||
else
|
||||
{
|
||||
csharpExp = Regex.Replace(EndXExpression, @"\$(\d+)", "{$1}");
|
||||
csharpExp = string.Format(csharpExp, args);
|
||||
result = exp.Compute(csharpExp, null).ToString()!;
|
||||
if (float.TryParse(result, out num)) EndX = num;
|
||||
var temp = exp.Compute(csharpExp, null);
|
||||
if (temp is not DBNull) EndX = Convert.ToSingle(temp);
|
||||
}
|
||||
EndX = document.GetMillimeters(EndX);
|
||||
EndX = Document.GetMillimeters(EndX);
|
||||
|
||||
if (float.TryParse(StartYExpression, out num)) StartY = num;
|
||||
if (float.TryParse(StartYExpression, NumberStyles.Float, CultureInfo.InvariantCulture, out num)) StartY = num;
|
||||
else
|
||||
{
|
||||
csharpExp = Regex.Replace(StartYExpression, @"\$(\d+)", "{$1}");
|
||||
csharpExp = string.Format(csharpExp, args);
|
||||
result = exp.Compute(csharpExp, null).ToString()!;
|
||||
if (float.TryParse(result, out num)) StartY = num;
|
||||
var temp = exp.Compute(csharpExp, null);
|
||||
if (temp is not DBNull) StartY = Convert.ToSingle(temp);
|
||||
}
|
||||
StartY = document.GetMillimeters(StartY);
|
||||
StartY = Document.GetMillimeters(StartY);
|
||||
|
||||
if (float.TryParse(EndYExpression, out num)) EndY = num;
|
||||
if (float.TryParse(EndYExpression, NumberStyles.Float, CultureInfo.InvariantCulture, out num)) EndY = num;
|
||||
else
|
||||
{
|
||||
csharpExp = Regex.Replace(EndYExpression, @"\$(\d+)", "{$1}");
|
||||
csharpExp = string.Format(csharpExp, args);
|
||||
result = exp.Compute(csharpExp, null).ToString()!;
|
||||
if (float.TryParse(result, out num)) EndY = num;
|
||||
var temp = exp.Compute(csharpExp, null);
|
||||
if (temp is not DBNull) EndY = Convert.ToSingle(temp);
|
||||
}
|
||||
EndY = document.GetMillimeters(EndY);
|
||||
EndY = Document.GetMillimeters(EndY);
|
||||
|
||||
if (float.TryParse(RotationExpression, out num)) Rotation = (short)num;
|
||||
if (float.TryParse(RotationExpression, NumberStyles.Float, CultureInfo.InvariantCulture, out num)) Rotation = (short)num;
|
||||
else
|
||||
{
|
||||
csharpExp = Regex.Replace(RotationExpression, @"\$(\d+)", "{$1}");
|
||||
csharpExp = string.Format(csharpExp, args);
|
||||
result = exp.Compute(csharpExp, null).ToString()!;
|
||||
if (float.TryParse(result, out num)) Rotation = num;
|
||||
var temp = exp.Compute(csharpExp, null);
|
||||
if (temp is not DBNull) Rotation = Convert.ToSingle(temp);
|
||||
}
|
||||
|
||||
IsParsed = true;
|
||||
|
||||
@@ -70,15 +70,7 @@ public class RemotePrinter : BindableBase
|
||||
set => RaiseAndSetIfChanged(ref _port, value);
|
||||
}
|
||||
|
||||
public string HostUrl
|
||||
{
|
||||
get
|
||||
{
|
||||
var result = $"http://{_host}";
|
||||
if (_port > 0) result += $":{_port}";
|
||||
return result;
|
||||
}
|
||||
}
|
||||
public string HostUrl => _port > 0 ? $"{_host}:{_port}" :_host ;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the compatible extensions with this device.
|
||||
@@ -206,6 +198,4 @@ public class RemotePrinter : BindableBase
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
}
|
||||
@@ -8,7 +8,13 @@
|
||||
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using UVtools.Core.Extensions;
|
||||
using UVtools.Core.Objects;
|
||||
@@ -22,14 +28,20 @@ public class RemotePrinterRequest : BindableBase
|
||||
|
||||
public enum RequestMethod : byte
|
||||
{
|
||||
[Description("GET")]
|
||||
[Description("HTTP GET")]
|
||||
GET,
|
||||
|
||||
[Description("POST")]
|
||||
[Description("HTTP POST")]
|
||||
POST,
|
||||
|
||||
[Description("PUT")]
|
||||
PUT
|
||||
[Description("HTTP PUT")]
|
||||
PUT,
|
||||
|
||||
[Description("SOCK TCP")]
|
||||
TCP,
|
||||
|
||||
[Description("SOCK UDP")]
|
||||
UDP
|
||||
}
|
||||
|
||||
public enum RequestType : byte
|
||||
@@ -86,7 +98,8 @@ public class RemotePrinterRequest : BindableBase
|
||||
{
|
||||
value = value.Trim();
|
||||
if (value[0] == '/') value = value.Remove(0, 1);
|
||||
if(value[^1] == '/') value = value.Remove(value.Length-1, 1);
|
||||
if (value[^1] == '/') value = value[..^2];
|
||||
value = value.Trim();
|
||||
}
|
||||
if(!RaiseAndSetIfChanged(ref _path, value)) return;
|
||||
RaisePropertyChanged(nameof(IsValid));
|
||||
@@ -110,7 +123,6 @@ public class RemotePrinterRequest : BindableBase
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Methods
|
||||
|
||||
/// <summary>
|
||||
@@ -120,20 +132,55 @@ public class RemotePrinterRequest : BindableBase
|
||||
/// <returns></returns>
|
||||
public string GetFormattedPath(params object?[] parameters) => string.Format(_path, parameters);
|
||||
|
||||
public async Task<HttpResponseMessage> SendRequest(string host, ushort port = 0, OperationProgress? progress = null, string? param1 = null, HttpContent? content = null)
|
||||
public async Task<HttpResponseMessage> SendRequest(string host, ushort port = 0, OperationProgress? progress = null, string? param1 = null, string? uploadFilePath = null)
|
||||
{
|
||||
string url = $"http://{host}";
|
||||
if (port > 0) url += $":{port}";
|
||||
|
||||
progress ??= new();
|
||||
progress ??= new OperationProgress();
|
||||
progress.Title = $"Sending {_method} request to: {url}";
|
||||
progress.ItemName = "Megabyte(s)";
|
||||
progress.CanCancel = true;
|
||||
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(_path)) url += $"/{GetFormattedPath(param1)}";
|
||||
if(_path == "{0}") return new HttpResponseMessage(HttpStatusCode.OK);
|
||||
|
||||
string? formattedPathWithParameter = null;
|
||||
if (!string.IsNullOrWhiteSpace(_path))
|
||||
{
|
||||
if (_path.StartsWith("<$") && _path.EndsWith("$>"))
|
||||
{
|
||||
var newPath = _path[2..^2].Trim();
|
||||
var split = newPath.Split('>', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
|
||||
if (split.Length < 3) throw new ArgumentException($"Path '{_path}' is malformed", nameof(Path));
|
||||
|
||||
var firstRequest = Clone();
|
||||
firstRequest.Path = split[0];
|
||||
using var response = await firstRequest.SendRequest(host, port, progress, param1);
|
||||
if (!response.IsSuccessStatusCode) return response;
|
||||
|
||||
var content = await response.Content.ReadAsStringAsync(progress.Token);
|
||||
if (content is null) throw new InvalidDataException($"The request to {firstRequest.Path} returned no data");
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(param1)) split[1] = string.Format(split[1], Regex.Escape(param1));
|
||||
|
||||
var match = Regex.Match(content, split[1]);
|
||||
if (!match.Success || match.Groups.Count < 2) throw new InvalidDataException($"Unable to parse any data from the content.\nRegex: {split[1]}\nContent: {content}");
|
||||
|
||||
for (int i = 1; i < match.Groups.Count; i++)
|
||||
{
|
||||
split[2] = split[2].Replace($"{{#{i}}}", match.Groups[i].Value);
|
||||
}
|
||||
|
||||
formattedPathWithParameter = string.Format(split[2], param1);
|
||||
}
|
||||
else
|
||||
{
|
||||
formattedPathWithParameter = GetFormattedPath(param1);
|
||||
}
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(_path) && !string.IsNullOrWhiteSpace(formattedPathWithParameter)) url += $"/{formattedPathWithParameter}";
|
||||
|
||||
|
||||
switch (_method)
|
||||
{
|
||||
case RequestMethod.GET:
|
||||
@@ -143,26 +190,133 @@ public class RemotePrinterRequest : BindableBase
|
||||
}
|
||||
case RequestMethod.POST:
|
||||
{
|
||||
using var response = await NetworkExtensions.HttpClient.PostAsync(url, content, progress.Token);
|
||||
if (string.IsNullOrWhiteSpace(uploadFilePath)) return await NetworkExtensions.HttpClient.PostAsync(url, null, progress.Token);
|
||||
|
||||
await using var stream = File.OpenRead(uploadFilePath);
|
||||
using var httpContent = new StreamContent(stream);
|
||||
|
||||
|
||||
progress.ItemCount = (uint) (stream.Length / 1048576);
|
||||
bool isCopying = true;
|
||||
try
|
||||
{
|
||||
var task = new Task(() =>
|
||||
{
|
||||
while (isCopying)
|
||||
{
|
||||
progress.ProcessedItems = (uint) (stream.Position / 1048576);
|
||||
Thread.Sleep(200);
|
||||
}
|
||||
});
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
|
||||
using var response = await NetworkExtensions.HttpClient.PostAsync(url, httpContent, progress.Token);
|
||||
isCopying = false;
|
||||
return response;
|
||||
|
||||
}
|
||||
case RequestMethod.PUT:
|
||||
{
|
||||
using var response = await NetworkExtensions.HttpClient.PutAsync(url, content, progress.Token);
|
||||
if (string.IsNullOrWhiteSpace(uploadFilePath)) return await NetworkExtensions.HttpClient.PutAsync(url, null, progress.Token);
|
||||
|
||||
await using var stream = File.OpenRead(uploadFilePath);
|
||||
using var httpContent = new StreamContent(stream);
|
||||
|
||||
|
||||
progress.ItemCount = (uint)(stream.Length / 1048576);
|
||||
bool isCopying = true;
|
||||
try
|
||||
{
|
||||
var task = new Task(() =>
|
||||
{
|
||||
while (isCopying)
|
||||
{
|
||||
progress.ProcessedItems = (uint)(stream.Position / 1048576);
|
||||
Thread.Sleep(200);
|
||||
}
|
||||
});
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
|
||||
using var response = await NetworkExtensions.HttpClient.PutAsync(url, httpContent, progress.Token);
|
||||
isCopying = false;
|
||||
return response;
|
||||
}
|
||||
}
|
||||
case RequestMethod.TCP:
|
||||
case RequestMethod.UDP:
|
||||
{
|
||||
using var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, _method == RequestMethod.TCP ? ProtocolType.Tcp : ProtocolType.Udp)
|
||||
{
|
||||
ReceiveTimeout = 10
|
||||
};
|
||||
var ipAd = IPAddress.Parse(host);
|
||||
await socket.ConnectAsync(ipAd, port);
|
||||
|
||||
if (string.IsNullOrWhiteSpace(uploadFilePath))
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(formattedPathWithParameter))
|
||||
{
|
||||
await socket.SendAsync(ReadOnlyMemory<byte>.Empty, SocketFlags.None);
|
||||
}
|
||||
else
|
||||
{
|
||||
var requestBytes = Encoding.UTF8.GetBytes(formattedPathWithParameter);
|
||||
var bytesSent = 0;
|
||||
while (bytesSent < requestBytes.Length)
|
||||
{
|
||||
bytesSent += await socket.SendAsync(requestBytes.AsMemory(bytesSent), SocketFlags.None);
|
||||
}
|
||||
}
|
||||
}
|
||||
else // file upload
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(formattedPathWithParameter))
|
||||
{
|
||||
await socket.SendFileAsync(uploadFilePath, progress.Token);
|
||||
}
|
||||
else
|
||||
{
|
||||
var preRequestBytes = Encoding.UTF8.GetBytes(formattedPathWithParameter);
|
||||
await socket.SendFileAsync(uploadFilePath, preRequestBytes, ReadOnlyMemory<byte>.Empty, TransmitFileOptions.UseDefaultWorkerThread, progress.Token);
|
||||
}
|
||||
}
|
||||
|
||||
var responseBytes = new byte[1024];
|
||||
var sb = new StringBuilder();
|
||||
int bytesReceived; // Receiving 0 bytes means EOF has been reached
|
||||
while ((bytesReceived = await socket.ReceiveAsync(responseBytes, SocketFlags.None, progress.Token)) > 0)
|
||||
{
|
||||
var result = Encoding.UTF8.GetString(responseBytes, 0, bytesReceived);
|
||||
sb.Append(result);
|
||||
if (result.EndsWith(",end")) break;
|
||||
}
|
||||
|
||||
socket.Shutdown(SocketShutdown.Both);
|
||||
|
||||
return new HttpResponseMessage(HttpStatusCode.OK)
|
||||
{
|
||||
Content = new StringContent(sb.ToString()),
|
||||
};
|
||||
}
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(nameof(Method));
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<HttpResponseMessage> SendRequest(RemotePrinter remotePrinter,
|
||||
OperationProgress? progress = null, string? param1 = null, HttpContent? content = null)
|
||||
=> await SendRequest(remotePrinter.Host, remotePrinter.Port, progress, param1, content);
|
||||
OperationProgress? progress = null, string? param1 = null, string? uploadFilePath = null)
|
||||
=> await SendRequest(remotePrinter.Host, remotePrinter.Port, progress, param1, uploadFilePath);
|
||||
|
||||
public RemotePrinterRequest Clone()
|
||||
{
|
||||
return (MemberwiseClone() as RemotePrinterRequest)!;
|
||||
return (RemotePrinterRequest)MemberwiseClone();
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
|
||||
@@ -16,6 +16,7 @@ using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.ComponentModel;
|
||||
using System.Drawing;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
@@ -577,7 +578,7 @@ public sealed class OperationCalibrateExposureFinder : Operation
|
||||
foreach (var mmStr in split)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(mmStr)) continue;
|
||||
if (!decimal.TryParse(mmStr, out var mm)) continue;
|
||||
if (!decimal.TryParse(mmStr, NumberStyles.Float, CultureInfo.InvariantCulture, out var mm)) continue;
|
||||
var mmPx = (int)(mm * Ppmm);
|
||||
if (mmPx is <= 0 or > 500) continue;
|
||||
if(holes.Contains(mmPx)) continue;
|
||||
@@ -675,7 +676,7 @@ public sealed class OperationCalibrateExposureFinder : Operation
|
||||
foreach (var mmStr in split)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(mmStr)) continue;
|
||||
if (!decimal.TryParse(mmStr, out var mm)) continue;
|
||||
if (!decimal.TryParse(mmStr, NumberStyles.Float, CultureInfo.InvariantCulture, out var mm)) continue;
|
||||
var mmPx = (int)(mm * Yppmm);
|
||||
if (mmPx is <= 0 or > 500) continue;
|
||||
if (bars.Contains(mmPx)) continue;
|
||||
@@ -1058,8 +1059,8 @@ public sealed class OperationCalibrateExposureFinder : Operation
|
||||
|
||||
if (string.IsNullOrWhiteSpace(splitDiameterThickness[0]) ||
|
||||
string.IsNullOrWhiteSpace(splitDiameterThickness[1])) continue;
|
||||
if (!decimal.TryParse(splitDiameterThickness[0], out var diameterMm)) continue;
|
||||
if (!decimal.TryParse(splitDiameterThickness[1], out var thicknessMm)) continue;
|
||||
if (!decimal.TryParse(splitDiameterThickness[0], NumberStyles.Float, CultureInfo.InvariantCulture, out var diameterMm)) continue;
|
||||
if (!decimal.TryParse(splitDiameterThickness[1], NumberStyles.Float, CultureInfo.InvariantCulture, out var thicknessMm)) continue;
|
||||
var diameter = (int)(diameterMm * Ppmm);
|
||||
if (diameterMm is <= 0 or > 500) continue;
|
||||
var thickness = (int)(thicknessMm * Ppmm);
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using System.Linq;
|
||||
@@ -60,6 +61,7 @@ public class OperationPCBExposure : Operation
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Static
|
||||
|
||||
public static string[] ValidExtensions => new[]
|
||||
@@ -83,10 +85,13 @@ public class OperationPCBExposure : Operation
|
||||
private decimal _layerHeight;
|
||||
private decimal _exposureTime;
|
||||
private GerberMidpointRounding _sizeMidpointRounding = GerberMidpointRounding.AwayFromZero;
|
||||
private decimal _offsetX;
|
||||
private decimal _offsetY;
|
||||
private bool _mirror;
|
||||
private bool _invertColor;
|
||||
private bool _enableAntiAliasing;
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
#region Overrides
|
||||
@@ -188,6 +193,18 @@ public class OperationPCBExposure : Operation
|
||||
set => RaiseAndSetIfChanged(ref _sizeMidpointRounding, value);
|
||||
}
|
||||
|
||||
public decimal OffsetX
|
||||
{
|
||||
get => _offsetX;
|
||||
set => RaiseAndSetIfChanged(ref _offsetX, value);
|
||||
}
|
||||
|
||||
public decimal OffsetY
|
||||
{
|
||||
get => _offsetY;
|
||||
set => RaiseAndSetIfChanged(ref _offsetY, value);
|
||||
}
|
||||
|
||||
public bool Mirror
|
||||
{
|
||||
get => _mirror;
|
||||
@@ -212,7 +229,7 @@ public class OperationPCBExposure : Operation
|
||||
|
||||
protected bool Equals(OperationPCBExposure other)
|
||||
{
|
||||
return _files.Equals(other._files) && _mergeFiles == other._mergeFiles && _layerHeight == other._layerHeight && _exposureTime == other._exposureTime && _sizeMidpointRounding == other._sizeMidpointRounding && _mirror == other._mirror && _invertColor == other._invertColor && _enableAntiAliasing == other._enableAntiAliasing;
|
||||
return _files.Equals(other._files) && _mergeFiles == other._mergeFiles && _layerHeight == other._layerHeight && _exposureTime == other._exposureTime && _sizeMidpointRounding == other._sizeMidpointRounding && _offsetX == other._offsetX && _offsetY == other._offsetY && _mirror == other._mirror && _invertColor == other._invertColor && _enableAntiAliasing == other._enableAntiAliasing;
|
||||
}
|
||||
|
||||
public override bool Equals(object? obj)
|
||||
@@ -225,7 +242,18 @@ public class OperationPCBExposure : Operation
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return HashCode.Combine(_files, _mergeFiles, _layerHeight, _exposureTime, (int) _sizeMidpointRounding, _mirror, _invertColor, _enableAntiAliasing);
|
||||
var hashCode = new HashCode();
|
||||
hashCode.Add(_files);
|
||||
hashCode.Add(_mergeFiles);
|
||||
hashCode.Add(_layerHeight);
|
||||
hashCode.Add(_exposureTime);
|
||||
hashCode.Add((int) _sizeMidpointRounding);
|
||||
hashCode.Add(_offsetX);
|
||||
hashCode.Add(_offsetY);
|
||||
hashCode.Add(_mirror);
|
||||
hashCode.Add(_invertColor);
|
||||
hashCode.Add(_enableAntiAliasing);
|
||||
return hashCode.ToHashCode();
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -286,7 +314,7 @@ public class OperationPCBExposure : Operation
|
||||
{
|
||||
if (!file.Exists) return;
|
||||
|
||||
GerberDocument.ParseAndDraw(file, mat, SlicerFile.Ppmm, _sizeMidpointRounding, _enableAntiAliasing);
|
||||
GerberDocument.ParseAndDraw(file, mat, SlicerFile.Ppmm, _sizeMidpointRounding, new SizeF((float)OffsetX, (float)OffsetY), _enableAntiAliasing);
|
||||
|
||||
//var boundingRectangle = CvInvoke.BoundingRectangle(mat);
|
||||
//var cropped = mat.Roi(new Size(boundingRectangle.Right, boundingRectangle.Bottom));
|
||||
|
||||
@@ -39,8 +39,6 @@ public class PixelDrawing : PixelOperation
|
||||
|
||||
public override PixelOperationType OperationType => PixelOperationType.Drawing;
|
||||
|
||||
public static BrushShapeType[] BrushShapeTypes => (BrushShapeType[])Enum.GetValues(typeof(BrushShapeType));
|
||||
|
||||
public BrushShapeType BrushShape
|
||||
{
|
||||
get => _brushShape;
|
||||
@@ -84,7 +82,7 @@ public class PixelDrawing : PixelOperation
|
||||
|
||||
public decimal RemovePixelBrightnessPercent => Math.Round(_removePixelBrightness * 100M / 255M, 2);
|
||||
|
||||
public bool IsAdd { get; }
|
||||
public bool IsAdd { get; }
|
||||
|
||||
public byte Brightness => IsAdd ? _pixelBrightness : _removePixelBrightness;
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using UVtools.Core.Extensions;
|
||||
@@ -390,19 +391,19 @@ namespace UVtools.Core.Printer
|
||||
|
||||
if (key.StartsWith("display_width"))
|
||||
{
|
||||
if (!float.TryParse(value, out var displayWidth)) continue;
|
||||
if (!float.TryParse(value, NumberStyles.Float, CultureInfo.InvariantCulture, out var displayWidth)) continue;
|
||||
machine.DisplayWidth = displayWidth;
|
||||
}
|
||||
|
||||
if (key.StartsWith("display_height"))
|
||||
{
|
||||
if (!float.TryParse(value, out var displayHeight)) continue;
|
||||
if (!float.TryParse(value, NumberStyles.Float, CultureInfo.InvariantCulture, out var displayHeight)) continue;
|
||||
machine.DisplayHeight = displayHeight;
|
||||
}
|
||||
|
||||
if (key.StartsWith("max_print_height"))
|
||||
{
|
||||
if (!float.TryParse(value, out var machineZ)) continue;
|
||||
if (!float.TryParse(value, NumberStyles.Float, CultureInfo.InvariantCulture, out var machineZ)) continue;
|
||||
machine.MachineZ = machineZ;
|
||||
}
|
||||
|
||||
|
||||
@@ -90,6 +90,6 @@ public static class LinAlgUtils
|
||||
// I'm sure there's a better way than converting it to a string and then back to a float,
|
||||
// but that's what I've got right now, so that's what I'm doing.
|
||||
//var strVal = rawVal.ToString($"0.{precision}");
|
||||
//return float.Parse(strVal, CultureInfo.InvariantCulture.NumberFormat);
|
||||
//return float.Parse(strVal, CultureInfo.InvariantCulture);
|
||||
}*/
|
||||
}
|
||||
@@ -10,7 +10,7 @@
|
||||
<RepositoryUrl>https://github.com/sn4k3/UVtools</RepositoryUrl>
|
||||
<PackageProjectUrl>https://github.com/sn4k3/UVtools</PackageProjectUrl>
|
||||
<Description>MSLA/DLP, file analysis, calibration, repair, conversion and manipulation</Description>
|
||||
<Version>3.8.3</Version>
|
||||
<Version>3.9.0</Version>
|
||||
<Copyright>Copyright © 2020 PTRTECH</Copyright>
|
||||
<PackageIcon>UVtools.png</PackageIcon>
|
||||
<Platforms>AnyCPU;x64</Platforms>
|
||||
@@ -80,7 +80,7 @@
|
||||
<PackageReference Include="Emgu.CV.runtime.windows" Version="4.6.0.5131" />
|
||||
<PackageReference Include="K4os.Compression.LZ4" Version="1.2.16" />
|
||||
<PackageReference Include="KdTree" Version="1.4.1" />
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Scripting" Version="4.3.1" />
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Scripting" Version="4.4.0" />
|
||||
<PackageReference Include="Portable.BouncyCastle" Version="1.9.0" />
|
||||
<PackageReference Include="System.Memory" Version="4.5.5" />
|
||||
<PackageReference Include="System.Reflection.TypeExtensions" Version="4.7.0" />
|
||||
|
||||
@@ -1229,11 +1229,11 @@
|
||||
<Component Id="cmp7778D227374EB7F600A97332D1D6A45B" Guid="*">
|
||||
<File Id="filBBF13BCAC7D6B106C113F7CFA14A7840" KeyPath="yes" Source="$(var.HarvestPath)\Assets\PrusaSlicer\printer\QIDI Shadow6.0 Pro.ini" />
|
||||
</Component>
|
||||
<Component Id="cmp611309E8DB084F22DABEC724A1D09579" Guid="*">
|
||||
<File Id="fil3EB35616F56D9D096F49556019B2A109" KeyPath="yes" Source="$(var.HarvestPath)\Assets\PrusaSlicer\printer\Uniformation GKone.ini" />
|
||||
<Component Id="cmp7E817A36B682DF55D0E86D145E27394E" Guid="*">
|
||||
<File Id="fil4627AA2319ACB8D222BCE61C11BA0B53" KeyPath="yes" Source="$(var.HarvestPath)\Assets\PrusaSlicer\printer\UniFormation GKone.ini" />
|
||||
</Component>
|
||||
<Component Id="cmp349785BA16BE1BC96FC0531A753E8896" Guid="*">
|
||||
<File Id="fil527DACB7C01D8842E81DE8453192A8ED" KeyPath="yes" Source="$(var.HarvestPath)\Assets\PrusaSlicer\printer\Uniformation GKtwo.ini" />
|
||||
<Component Id="cmp4E19DB4221A31764E993B0CCD95D7642" Guid="*">
|
||||
<File Id="fil0AC1D01236214C81A892BE4C0F3760D4" KeyPath="yes" Source="$(var.HarvestPath)\Assets\PrusaSlicer\printer\UniFormation GKtwo.ini" />
|
||||
</Component>
|
||||
<Component Id="cmp9F6872E41F10EFB360C028C3E540E02F" Guid="*">
|
||||
<File Id="fil1B5EBFEF6E7FB1A3AA3FE683B0D343AE" KeyPath="yes" Source="$(var.HarvestPath)\Assets\PrusaSlicer\printer\Uniz IBEE.ini" />
|
||||
@@ -1989,8 +1989,8 @@
|
||||
<ComponentRef Id="cmp40B90D04961D1E3743872E5411202E92" />
|
||||
<ComponentRef Id="cmp5E7F87B7AC98D09CB9045D5993BB28D3" />
|
||||
<ComponentRef Id="cmp7778D227374EB7F600A97332D1D6A45B" />
|
||||
<ComponentRef Id="cmp611309E8DB084F22DABEC724A1D09579" />
|
||||
<ComponentRef Id="cmp349785BA16BE1BC96FC0531A753E8896" />
|
||||
<ComponentRef Id="cmp7E817A36B682DF55D0E86D145E27394E" />
|
||||
<ComponentRef Id="cmp4E19DB4221A31764E993B0CCD95D7642" />
|
||||
<ComponentRef Id="cmp9F6872E41F10EFB360C028C3E540E02F" />
|
||||
<ComponentRef Id="cmp6ABBC7705A2469FF9059CF75A7EC20B7" />
|
||||
<ComponentRef Id="cmp4E6FE2176F0460D349008DACFB98DA6A" />
|
||||
|
||||
+30
-21
@@ -212,32 +212,26 @@ public class App : Application
|
||||
if (string.IsNullOrWhiteSpace(Program.Args[1])) return;
|
||||
if (string.IsNullOrWhiteSpace(Program.Args[2])) return;
|
||||
var category = Program.Args[1];
|
||||
var message = $"{Program.Args[2]}\nCategory: {category}";
|
||||
var bugDescription = $"{Program.Args[2]}\nCategory: {category}";
|
||||
var system = string.Empty;
|
||||
if (Program.Args.Length >= 4 && !string.IsNullOrWhiteSpace(Program.Args[3]))
|
||||
{
|
||||
message += $"\nFile: {Program.Args[3]}";
|
||||
bugDescription += $"\nFile: {Program.Args[3]}";
|
||||
}
|
||||
|
||||
var bugReportMessageMk = $"# Report\n```\n{message}\n```";
|
||||
bugDescription += $"\n\nMachine date time: {DateTime.Now}\n UTC date time: {DateTime.UtcNow}";
|
||||
|
||||
try
|
||||
{
|
||||
var append = $"\n\n# System\n{AboutWindow.GetEssentialInformationStatic()}";
|
||||
message += append;
|
||||
bugReportMessageMk += append;
|
||||
system = AboutWindow.GetEssentialInformationStatic();
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
|
||||
var append2 = $"\n\nMachine date time: {DateTime.Now}\n UTC date time: {DateTime.UtcNow}";
|
||||
message += append2;
|
||||
bugReportMessageMk += $"{append2}\n\n# Additional information and Workflow\nComplete with additional information and the workflow that caused this crash with the file as well.";
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
Current?.Clipboard?.SetTextAsync(bugReportMessageMk);
|
||||
Current?.Clipboard?.SetTextAsync(bugDescription);
|
||||
}
|
||||
catch
|
||||
{
|
||||
@@ -245,15 +239,15 @@ public class App : Application
|
||||
}
|
||||
|
||||
|
||||
using var reader = new StringReader(message);
|
||||
using var reader = new StringReader(bugDescription);
|
||||
desktop.MainWindow = new MessageWindow($"{About.SoftwareWithVersion} - Crash report",
|
||||
"fa-regular fa-frown",
|
||||
$"{About.Software} crashed due an unexpected {category.ToLowerInvariant()} error.\nYou can report this error if you find necessary.\nFind more details below:\n",
|
||||
message,
|
||||
$"{About.Software} crashed due an unexpected {category.ToLowerInvariant()} error.\nYou can report this error if you find necessary.\nFind more details below:\n",
|
||||
bugDescription,
|
||||
new[]
|
||||
{
|
||||
MessageWindow.CreateLinkButtonAction("Report", "fa-solid fa-bug", $"https://github.com/sn4k3/UVtools/issues/new?assignees=sn4k3&labels=&template=bug_report.md&title={HttpUtility.UrlEncode($"[Crash] {reader.ReadLine()}")}&body={HttpUtility.UrlEncode("<!--\n# Instructions:\n1. Click on this box;\n2. Select all it text (Ctrl + A);\n3. Paste the report content (Ctrl + V);\n4. Review the content;\n5. Submit the issue.\n!-->")}", () => Current?.Clipboard?.SetTextAsync(bugReportMessageMk)),
|
||||
MessageWindow.CreateLinkButtonAction("Help", "fa-solid fa-question", "https://github.com/sn4k3/UVtools/discussions/categories/q-a", () => Current?.Clipboard?.SetTextAsync(bugReportMessageMk)),
|
||||
MessageWindow.CreateLinkButtonAction("Report", "fa-solid fa-bug", $"https://github.com/sn4k3/UVtools/issues/new?template=bug_report_form.yml&title={HttpUtility.UrlEncode($"[Crash] {reader.ReadLine()}")}&system={HttpUtility.UrlEncode(system)}&bug_description={HttpUtility.UrlEncode($"```\n{bugDescription}\n```")}", () => Current?.Clipboard?.SetTextAsync($"```\n{bugDescription}\n```")),
|
||||
MessageWindow.CreateLinkButtonAction("Help", "fa-solid fa-question", "https://github.com/sn4k3/UVtools/discussions/categories/q-a", () => Current?.Clipboard?.SetTextAsync($"```\n{bugDescription}\n```")),
|
||||
MessageWindow.CreateButtonAction("Restart", "fa-solid fa-redo-alt", () => SystemAware.StartThisApplication()),
|
||||
MessageWindow.CreateCloseButton("fa-solid fa-sign-out-alt")
|
||||
});
|
||||
@@ -315,10 +309,25 @@ public class App : Application
|
||||
{
|
||||
try
|
||||
{
|
||||
var ldd = SystemAware.GetProcessOutput("bash", $"-c \"ldd '{Path.Combine(ApplicationPath, "libcvextern.so")}' | grep not\"");
|
||||
if (!string.IsNullOrWhiteSpace(ldd))
|
||||
var result = SystemAware.GetProcessOutput("bash", $"-c \"ldd '{Path.Combine(ApplicationPath, "libcvextern.so")}' | grep not\"");
|
||||
if (!string.IsNullOrWhiteSpace(result))
|
||||
{
|
||||
message += $"Missing dependencies:\n{ldd}\n";
|
||||
message += $"Missing dependencies:\n{result}\n";
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.WriteLine(e);
|
||||
}
|
||||
}
|
||||
else if (OperatingSystem.IsMacOS())
|
||||
{
|
||||
try
|
||||
{
|
||||
var result = SystemAware.GetProcessOutput("otool", $"-L '{Path.Combine(ApplicationPath, "libcvextern.dylib")}'");
|
||||
if (!string.IsNullOrWhiteSpace(result))
|
||||
{
|
||||
message += $"Dependencies:\n{result}\n";
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
|
||||
@@ -96,7 +96,7 @@
|
||||
</DataGrid>
|
||||
|
||||
|
||||
<Grid RowDefinitions="Auto,10,Auto,10,Auto,10,Auto,10,Auto"
|
||||
<Grid RowDefinitions="Auto,10,Auto,10,Auto,10,Auto,10,Auto,10,Auto"
|
||||
ColumnDefinitions="Auto,10,400">
|
||||
|
||||
<ToggleSwitch Grid.Row="0" Grid.Column="2"
|
||||
@@ -136,11 +136,37 @@
|
||||
Items="{Binding Operation.SizeMidpointRounding, Converter={StaticResource EnumToCollectionConverter}, Mode=OneTime}"
|
||||
SelectedItem="{Binding Operation.SizeMidpointRounding, Converter={StaticResource FromValueDescriptionToEnumConverter}}"/>
|
||||
|
||||
|
||||
<TextBlock Grid.Row="8" Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
ToolTip.Tip="Offset the PCB origin.
|
||||

Use the 'Show full preview image (The final result)' option to preview the resulting position."
|
||||
Text="Offset X/Y:"/>
|
||||
|
||||
<StackPanel Grid.Row="8" Grid.Column="2"
|
||||
Orientation="Horizontal" Spacing="20">
|
||||
<NumericUpDown Classes="ValueLabel ValueLabel_mm"
|
||||
Increment="0.05"
|
||||
Minimum="-10000"
|
||||
Maximum="10000"
|
||||
FormatString="F2"
|
||||
Width="187"
|
||||
Value="{Binding Operation.OffsetX}"/>
|
||||
|
||||
<NumericUpDown Classes="ValueLabel ValueLabel_mm"
|
||||
Increment="0.05"
|
||||
Minimum="-10000"
|
||||
Maximum="10000"
|
||||
FormatString="F2"
|
||||
Width="187"
|
||||
Value="{Binding Operation.OffsetY}"/>
|
||||
</StackPanel>
|
||||
|
||||
<TextBlock Grid.Row="10" Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Text="Options:"/>
|
||||
|
||||
<StackPanel Grid.Row="8" Grid.Column="2"
|
||||
<StackPanel Grid.Row="10" Grid.Column="2"
|
||||
Orientation="Horizontal" Spacing="20">
|
||||
<CheckBox VerticalAlignment="Center"
|
||||
IsChecked="{Binding Operation.Mirror}"
|
||||
@@ -154,14 +180,17 @@
|
||||
IsChecked="{Binding Operation.EnableAntiAliasing}"
|
||||
Content="Enable Anti-Aliasing"/>
|
||||
</StackPanel>
|
||||
|
||||
|
||||
</Grid>
|
||||
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel Grid.Column="2" Orientation="Vertical" Spacing="10">
|
||||
<Image Stretch="Uniform"
|
||||
<ToggleSwitch IsChecked="{Binding CropPreview}"
|
||||
OnContent="Show preview image cropped by it bounds"
|
||||
OffContent="Show full preview image (The final result)"/>
|
||||
|
||||
<Image Stretch="Uniform"
|
||||
MaxHeight="700"
|
||||
Source="{Binding PreviewImage}"/>
|
||||
|
||||
<TextBlock Text="{Binding PreviewImage.Size, StringFormat=Size: {0}}" HorizontalAlignment="Center"/>
|
||||
|
||||
@@ -25,6 +25,7 @@ namespace UVtools.WPF.Controls.Tools
|
||||
|
||||
private Bitmap _previewImage;
|
||||
private OperationPCBExposure.PCBExposureFile _selectedFile;
|
||||
private bool _cropPreview = true;
|
||||
|
||||
public Bitmap PreviewImage
|
||||
{
|
||||
@@ -42,6 +43,16 @@ namespace UVtools.WPF.Controls.Tools
|
||||
}
|
||||
}
|
||||
|
||||
public bool CropPreview
|
||||
{
|
||||
get => _cropPreview;
|
||||
set
|
||||
{
|
||||
if(!RaiseAndSetIfChanged(ref _cropPreview, value)) return;
|
||||
UpdatePreview();
|
||||
}
|
||||
}
|
||||
|
||||
public ToolPCBExposureControl()
|
||||
{
|
||||
BaseOperation = new OperationPCBExposure(SlicerFile);
|
||||
@@ -55,7 +66,7 @@ namespace UVtools.WPF.Controls.Tools
|
||||
Operation.AddFiles(args.Data.GetFileNames()?.ToArray() ?? Array.Empty<string>());
|
||||
});
|
||||
|
||||
_timer = new Timer(20)
|
||||
_timer = new Timer(50)
|
||||
{
|
||||
AutoReset = false
|
||||
};
|
||||
@@ -115,10 +126,18 @@ namespace UVtools.WPF.Controls.Tools
|
||||
if (!OperationPCBExposure.ValidExtensions.Any(extension => _selectedFile.IsExtension(extension)) || !_selectedFile.Exists) return;
|
||||
var file = (OperationPCBExposure.PCBExposureFile)_selectedFile.Clone();
|
||||
file.InvertPolarity = false;
|
||||
using var mat = Operation.GetMat(file);
|
||||
using var matCropped = mat.CropByBounds(20);
|
||||
_previewImage?.Dispose();
|
||||
PreviewImage = matCropped.ToBitmap();
|
||||
using var mat = Operation.GetMat(file);
|
||||
|
||||
if (_cropPreview)
|
||||
{
|
||||
using var matCropped = mat.CropByBounds(20);
|
||||
PreviewImage = matCropped.ToBitmap();
|
||||
}
|
||||
else
|
||||
{
|
||||
PreviewImage = mat.ToBitmap();
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Diagnostics;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
@@ -22,7 +21,6 @@ using Emgu.CV.CvEnum;
|
||||
using Emgu.CV.Structure;
|
||||
using MessageBox.Avalonia.Enums;
|
||||
using SkiaSharp;
|
||||
using UVtools.Core;
|
||||
using UVtools.Core.Extensions;
|
||||
using UVtools.Core.Layers;
|
||||
using UVtools.Core.PixelEditor;
|
||||
|
||||
@@ -216,9 +216,8 @@
|
||||
<Separator/>
|
||||
|
||||
<MenuItem Header="_Report a issue"
|
||||
Command="{Binding OpenWebsite}"
|
||||
CommandParameter="https://github.com/sn4k3/UVtools/issues/new?assignees=sn4k3&labels=&template=bug_report.md&title=%5BBUG%5D+"
|
||||
i:MenuItem.Icon="fa-solid fa-bug"/>
|
||||
Command="{Binding MenuHelpReportIssueClicked}"
|
||||
i:MenuItem.Icon="fa-solid fa-bug"/>
|
||||
|
||||
<MenuItem Header="Ask a _question"
|
||||
Command="{Binding OpenWebsite}"
|
||||
@@ -339,7 +338,7 @@
|
||||
|
||||
|
||||
<TextBlock IsVisible="{Binding SlicerFile.MaterialCost}" Text=" | "/>
|
||||
<TextBlock IsVisible="{Binding SlicerFile.MaterialCost}" Text="{Binding SlicerFile.MaterialCost, StringFormat=Material cost: {0}€}"/>
|
||||
<TextBlock IsVisible="{Binding SlicerFile.MaterialCost}" Text="{Binding SlicerFile.MaterialCost, StringFormat=Material cost: {0:C}}"/>
|
||||
|
||||
|
||||
<TextBlock IsVisible="{Binding SlicerFile.MaterialName, Converter={x:Static StringConverters.IsNotNullOrEmpty}}"
|
||||
@@ -862,18 +861,17 @@
|
||||
|
||||
</StackPanel>
|
||||
|
||||
<DataGrid
|
||||
Name="IssuesGrid"
|
||||
Grid.Row="1"
|
||||
CanUserReorderColumns="True"
|
||||
CanUserResizeColumns="True"
|
||||
CanUserSortColumns="True"
|
||||
GridLinesVisibility="Horizontal"
|
||||
SelectionMode="Extended"
|
||||
SelectedIndex="{Binding IssueSelectedIndex, Mode=TwoWay}"
|
||||
IsReadOnly="True"
|
||||
ClipboardCopyMode="None"
|
||||
Items="{Binding IssuesGridItems}">
|
||||
<DataGrid Name="IssuesGrid"
|
||||
Grid.Row="1"
|
||||
CanUserReorderColumns="True"
|
||||
CanUserResizeColumns="True"
|
||||
CanUserSortColumns="True"
|
||||
GridLinesVisibility="Horizontal"
|
||||
SelectionMode="Extended"
|
||||
SelectedIndex="{Binding IssueSelectedIndex, Mode=TwoWay}"
|
||||
IsReadOnly="True"
|
||||
ClipboardCopyMode="None"
|
||||
Items="{Binding IssuesGridItems}">
|
||||
<DataGrid.ContextMenu>
|
||||
<ContextMenu IsVisible="{Binding #IssuesGrid.SelectedItem, Converter={x:Static ObjectConverters.IsNotNull}}">
|
||||
<MenuItem i:MenuItem.Icon="fa-solid fa-eye-slash" Command="{Binding OnClickIssueIgnore}" Header="Ignore issue(s)"/>
|
||||
@@ -892,6 +890,7 @@
|
||||
Width="Auto" />
|
||||
<DataGridTextColumn Header="Layer(s)"
|
||||
Binding="{Binding LayerInfoStr}"
|
||||
SortMemberPath="StartLayerIndex"
|
||||
Width="Auto" />
|
||||
<DataGridTextColumn Header="Area"
|
||||
Binding="{Binding Area, StringFormat={}{0:N0}}"
|
||||
@@ -1107,8 +1106,8 @@
|
||||
Grid.Column="2"
|
||||
Grid.ColumnSpan="3"
|
||||
Width="180"
|
||||
Items="{Binding DrawingPixelDrawing.BrushShapeTypes}"
|
||||
SelectedItem="{Binding DrawingPixelDrawing.BrushShape}"/>
|
||||
Items="{Binding DrawingPixelDrawing.BrushShape, Converter={StaticResource EnumToCollectionConverter}, Mode=OneTime}"
|
||||
SelectedItem="{Binding DrawingPixelDrawing.BrushShape, Converter={StaticResource FromValueDescriptionToEnumConverter}}"/>
|
||||
|
||||
<TextBlock Grid.Row="4" Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
|
||||
@@ -20,8 +20,8 @@ using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Web;
|
||||
using UVtools.AvaloniaControls;
|
||||
using UVtools.Core;
|
||||
using UVtools.Core.Extensions;
|
||||
@@ -392,7 +392,7 @@ public partial class MainWindow : WindowEx
|
||||
{
|
||||
foreach (var remotePrinter in Settings.Network.RemotePrinters)
|
||||
{
|
||||
if(!remotePrinter.IsEnabled || !remotePrinter.IsValid) continue;
|
||||
if(!remotePrinter.IsEnabled || !remotePrinter.IsValid || (!remotePrinter.RequestUploadFile.IsValid && !remotePrinter.RequestPrintFile.IsValid)) continue;
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(remotePrinter.CompatibleExtensions))
|
||||
{
|
||||
@@ -508,67 +508,59 @@ public partial class MainWindow : WindowEx
|
||||
}
|
||||
}
|
||||
|
||||
ShowProgressWindow($"Sending: {SlicerFile.Filename} to {path}");
|
||||
Progress.ItemName = "Sending";
|
||||
|
||||
|
||||
if (menuItem.Tag is RemotePrinter remotePrinter)
|
||||
{
|
||||
var startPrint = (_globalModifiers & KeyModifiers.Shift) != 0 && remotePrinter.RequestPrintFile is not null && remotePrinter.RequestPrintFile.IsValid;
|
||||
if (!startPrint && !remotePrinter.RequestUploadFile.IsValid) return;
|
||||
if (startPrint)
|
||||
{
|
||||
if (await this.MessageBoxQuestion(
|
||||
"If supported, you are about to send the file and start the print with it.\n" +
|
||||
"Keep in mind there is no guarantee that the file will start to print.\n" +
|
||||
"Are you sure you want to continue?\n\n" +
|
||||
"Yes: Send file and print it.\n" +
|
||||
"No: Cancel file sending and print.", "Send and print the file?") != ButtonResult.Yes) return;
|
||||
if (!remotePrinter.RequestUploadFile.IsValid)
|
||||
{
|
||||
if (await this.MessageBoxQuestion(
|
||||
$"If supported, you are about to start the print with the filename: {SlicerFile.Filename}\n" +
|
||||
"This file will not upload, so, it will print the file already present in printer disk.\n" +
|
||||
"Keep in mind there is no guarantee that the file will start to print.\n" +
|
||||
"Are you sure you want to continue?\n\n" +
|
||||
"Yes: Print this file name.\n" +
|
||||
"No: Cancel file print.", "Print the filename?") != ButtonResult.Yes) return;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (await this.MessageBoxQuestion(
|
||||
"If supported, you are about to send the file and start the print with it.\n" +
|
||||
"Keep in mind there is no guarantee that the file will start to print.\n" +
|
||||
"Are you sure you want to continue?\n\n" +
|
||||
"Yes: Send file and print it.\n" +
|
||||
"No: Cancel file sending and print.", "Send and print the file?") != ButtonResult.Yes) return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ShowProgressWindow($"Sending: {SlicerFile.Filename} to {path}");
|
||||
Progress.ItemName = "Sending";
|
||||
|
||||
HttpResponseMessage response = null;
|
||||
try
|
||||
if(remotePrinter.RequestUploadFile.IsValid)
|
||||
{
|
||||
await using var stream = File.OpenRead(SlicerFile.FileFullPath);
|
||||
using var httpContent = new StreamContent(stream);
|
||||
|
||||
|
||||
Progress.ItemCount = (uint)(stream.Length / 1000000);
|
||||
bool isCopying = true;
|
||||
try
|
||||
{
|
||||
var task = new Task(() =>
|
||||
response = await remotePrinter.RequestUploadFile.SendRequest(remotePrinter, Progress, SlicerFile.Filename, SlicerFile.FileFullPath);
|
||||
if (!response.IsSuccessStatusCode)
|
||||
{
|
||||
while (isCopying)
|
||||
{
|
||||
Progress.ProcessedItems = (uint)(stream.Position / 1000000);
|
||||
Thread.Sleep(200);
|
||||
}
|
||||
});
|
||||
await this.MessageBoxError(response.ToString(), "Send to printer");
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
catch (OperationCanceledException) { }
|
||||
catch (Exception ex)
|
||||
{
|
||||
// ignored
|
||||
await this.MessageBoxError(ex.Message, "Send to printer");
|
||||
}
|
||||
|
||||
response = await remotePrinter.RequestUploadFile.SendRequest(remotePrinter, Progress, SlicerFile.Filename, httpContent);
|
||||
isCopying = false;
|
||||
if (!response.IsSuccessStatusCode)
|
||||
{
|
||||
await this.MessageBoxError(response.ToString(), "Send to printer");
|
||||
}
|
||||
}
|
||||
catch (OperationCanceledException) { }
|
||||
catch (Exception ex)
|
||||
{
|
||||
await this.MessageBoxError(ex.Message, "Send to printer");
|
||||
}
|
||||
|
||||
|
||||
if (
|
||||
response is not null && response.IsSuccessStatusCode &&
|
||||
startPrint)
|
||||
if (startPrint && (!remotePrinter.RequestUploadFile.IsValid || (response is not null && response.IsSuccessStatusCode)))
|
||||
{
|
||||
response.Dispose();
|
||||
response?.Dispose();
|
||||
Progress.Title = "Waiting 2 seconds...";
|
||||
await Task.Delay(2000);
|
||||
try
|
||||
@@ -578,6 +570,7 @@ public partial class MainWindow : WindowEx
|
||||
{
|
||||
await this.MessageBoxError(response.ToString(), "Unable to send the print command");
|
||||
}
|
||||
response.Dispose();
|
||||
/*else
|
||||
{
|
||||
await this.MessageBoxInfo(response.ToString(), "Print send command report");
|
||||
@@ -592,6 +585,7 @@ public partial class MainWindow : WindowEx
|
||||
}
|
||||
else if (menuItem.Tag is MappedProcess process)
|
||||
{
|
||||
ShowProgressWindow($"Sending: {SlicerFile.Filename} to {path}");
|
||||
Progress.ItemName = "Waiting for completion";
|
||||
try
|
||||
{
|
||||
@@ -606,51 +600,8 @@ public partial class MainWindow : WindowEx
|
||||
}
|
||||
else
|
||||
{
|
||||
/*var copyResult = await Task.Factory.StartNew(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var fileDest = Path.Combine(path, SlicerFile.Filename);
|
||||
//File.Copy(SlicerFile.FileFullPath, $"{Path.Combine(path, SlicerFile.Filename)}", true);
|
||||
var buffer = new byte[1024 * 1024]; // 1MB buffer
|
||||
|
||||
using var source = File.OpenRead(SlicerFile.FileFullPath);
|
||||
using var dest = new FileStream(fileDest, FileMode.Create, FileAccess.Write);
|
||||
//long totalBytes = 0;
|
||||
//int currentBlockSize;
|
||||
|
||||
Progress.Reset("Megabyte(s)", (uint)(source.Length / 1000000));
|
||||
var copyProgress = new Progress<long>(copiedBytes => Progress.ProcessedItems = (uint)(copiedBytes / 1000000));
|
||||
source.CopyToAsync(dest, 0, copyProgress, Progress.Token).ConfigureAwait(false);
|
||||
|
||||
/*while ((currentBlockSize = source.Read(buffer)) > 0)
|
||||
{
|
||||
totalBytes += currentBlockSize;
|
||||
|
||||
dest.Write(buffer, 0, currentBlockSize);
|
||||
|
||||
if (Progress.Token.IsCancellationRequested)
|
||||
{
|
||||
// Delete dest file here
|
||||
dest.Dispose();
|
||||
File.Delete(fileDest);
|
||||
return false;
|
||||
}
|
||||
|
||||
Progress.ProcessedItems = (uint)(totalBytes / 1000000);
|
||||
}*/
|
||||
|
||||
/* return true;
|
||||
}
|
||||
catch (OperationCanceledException) { }
|
||||
catch (Exception exception)
|
||||
{
|
||||
Dispatcher.UIThread.InvokeAsync(async () =>
|
||||
await this.MessageBoxError(exception.ToString(), "Unable to copy the file"));
|
||||
}
|
||||
|
||||
return false;
|
||||
});*/
|
||||
ShowProgressWindow($"Sending: {SlicerFile.Filename} to {path}");
|
||||
Progress.ItemName = "Sending";
|
||||
|
||||
bool copyResult = false;
|
||||
var fileDest = Path.Combine(path, SlicerFile.Filename);
|
||||
@@ -659,8 +610,8 @@ public partial class MainWindow : WindowEx
|
||||
await using var source = File.OpenRead(SlicerFile.FileFullPath);
|
||||
await using var dest = new FileStream(fileDest, FileMode.Create, FileAccess.Write);
|
||||
|
||||
Progress.Reset("Megabyte(s)", (uint)(source.Length / 1000000));
|
||||
var copyProgress = new Progress<long>(copiedBytes => Progress.ProcessedItems = (uint)(copiedBytes / 1000000));
|
||||
Progress.Reset("Megabyte(s)", (uint)(source.Length / 1048576));
|
||||
var copyProgress = new Progress<long>(copiedBytes => Progress.ProcessedItems = (uint)(copiedBytes / 1048576));
|
||||
await source.CopyToAsync(dest, copyProgress, Progress.Token);
|
||||
|
||||
copyResult = true;
|
||||
@@ -688,6 +639,7 @@ public partial class MainWindow : WindowEx
|
||||
$"File '{SlicerFile.Filename}' has copied successfully into {removableDrive.Name}\n" +
|
||||
$"Do you want to eject the {removableDrive.Name} drive now?", "Copied ok, eject the drive?") == ButtonResult.Yes)
|
||||
{
|
||||
|
||||
Progress.ResetAll($"Ejecting {removableDrive.Name}");
|
||||
var ejectResult = await Task.Factory.StartNew(() =>
|
||||
{
|
||||
@@ -1147,7 +1099,23 @@ public partial class MainWindow : WindowEx
|
||||
SystemAware.StartProcess(UserSettings.SettingsFolder);
|
||||
}
|
||||
|
||||
private async void MenuHelpMaterialManagerClicked()
|
||||
public void MenuHelpReportIssueClicked()
|
||||
{
|
||||
var system = string.Empty;
|
||||
|
||||
try
|
||||
{
|
||||
system = AboutWindow.GetEssentialInformationStatic();
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
|
||||
SystemAware.OpenBrowser($"https://github.com/sn4k3/UVtools/issues/new?template=bug_report_form.yml&title=%5BBug%5D+&system={HttpUtility.UrlEncode(system)}");
|
||||
}
|
||||
|
||||
public async void MenuHelpMaterialManagerClicked()
|
||||
{
|
||||
await new MaterialManagerWindow().ShowDialog(this);
|
||||
}
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Avalonia;
|
||||
using Projektanker.Icons.Avalonia;
|
||||
using Projektanker.Icons.Avalonia.FontAwesome;
|
||||
using Projektanker.Icons.Avalonia.MaterialDesign;
|
||||
using UVtools.Core;
|
||||
using UVtools.Core.SystemOS;
|
||||
|
||||
namespace UVtools.WPF;
|
||||
@@ -40,9 +42,8 @@ public static class Program
|
||||
[STAThread]
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
CultureInfo.DefaultThreadCurrentCulture = CultureInfo.InvariantCulture;
|
||||
CultureInfo.DefaultThreadCurrentUICulture = CultureInfo.InvariantCulture;
|
||||
|
||||
CultureInfo.DefaultThreadCurrentUICulture =
|
||||
CultureInfo.DefaultThreadCurrentCulture = CoreSettings.OptimalCultureInfo;
|
||||
ProgramStartupTime = Stopwatch.StartNew();
|
||||
Args = args;
|
||||
try
|
||||
@@ -66,7 +67,8 @@ public static class Program
|
||||
IsCrashReport = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*using var mat = CvInvoke.Imread(@"D:\layer0.png", ImreadModes.Grayscale);
|
||||
var contours = mat.FindContours(out var hierarchy, RetrType.Tree, ChainApproxMethod.ChainApproxTc89Kcos);
|
||||
|
||||
@@ -274,6 +274,10 @@ public class AppVersionChecker : BindableBase
|
||||
await stream.WriteLineAsync("else");
|
||||
await stream.WriteLineAsync($" cp -fR '{extractDirectoryPath}/'* '{macOSAppPath}'");
|
||||
await stream.WriteLineAsync("fi");
|
||||
|
||||
await stream.WriteLineAsync();
|
||||
await stream.WriteLineAsync("echo '- Force codesign to allow the app to run directly'");
|
||||
await stream.WriteLineAsync($"codesign --force --deep --sign - '{macOSAppPath}'");
|
||||
}
|
||||
else // Linux generic and macOS generic
|
||||
{
|
||||
@@ -305,10 +309,11 @@ public class AppVersionChecker : BindableBase
|
||||
}
|
||||
else // Can move
|
||||
{
|
||||
await stream.WriteLineAsync("echo '- Attempt to rename directory to the new version name'");
|
||||
await stream.WriteLineAsync($"if [ -d '{applicationPath}' ]; then");
|
||||
await stream.WriteLineAsync("echo '- Could not rename directory to the new version name, a directory with same name already exists'");
|
||||
await stream.WriteLineAsync($" cd '{App.ApplicationPath}'");
|
||||
await stream.WriteLineAsync("else");
|
||||
await stream.WriteLineAsync($"echo '- Attempt to rename directory {new DirectoryInfo(App.ApplicationPath).Name} to {new DirectoryInfo(applicationPath)}'");
|
||||
await stream.WriteLineAsync($" mv -f '{App.ApplicationPath}' '{applicationPath}'");
|
||||
await stream.WriteLineAsync($" cd '{applicationPath}'");
|
||||
await stream.WriteLineAsync("fi");
|
||||
@@ -318,11 +323,11 @@ public class AppVersionChecker : BindableBase
|
||||
if (App.SlicerFile is not null && App.SlicerFile.FileFullPath != Path.Combine(App.ApplicationPath, About.DemoFile))
|
||||
{
|
||||
// Reload last file
|
||||
await stream.WriteLineAsync($"nohup bash 'UVtools.sh' '{App.SlicerFile.FileFullPath}' &> /dev/null &");
|
||||
await stream.WriteLineAsync($"nohup ./UVtools.sh '{App.SlicerFile.FileFullPath}' &> /dev/null &");
|
||||
}
|
||||
else
|
||||
{
|
||||
await stream.WriteLineAsync("nohup bash 'UVtools.sh' &> /dev/null &");
|
||||
await stream.WriteLineAsync("nohup ./UVtools.sh &> /dev/null &");
|
||||
}
|
||||
await stream.WriteLineAsync("disown");
|
||||
await stream.WriteLineAsync();
|
||||
@@ -334,10 +339,12 @@ public class AppVersionChecker : BindableBase
|
||||
//await stream.WriteLine("exit");
|
||||
}
|
||||
|
||||
//SystemAware.StartProcess("chmod", $"775 \"{upgradeScriptFilePath}\"", true);
|
||||
|
||||
if (Program.IsDebug)
|
||||
{
|
||||
Console.WriteLine("In debug mode, will not auto-upgrade, please run:");
|
||||
Console.WriteLine($"bash \"{upgradeScriptFilePath}\"");
|
||||
Console.WriteLine($"bash '{upgradeScriptFilePath}'");
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
<PackageLicenseFile>LICENSE</PackageLicenseFile>
|
||||
<RepositoryUrl>https://github.com/sn4k3/UVtools</RepositoryUrl>
|
||||
<RepositoryType>Git</RepositoryType>
|
||||
<Version>3.8.3</Version>
|
||||
<Version>3.9.0</Version>
|
||||
<Platforms>AnyCPU;x64</Platforms>
|
||||
<PackageIcon>UVtools.png</PackageIcon>
|
||||
<PackageReadmeFile>README.md</PackageReadmeFile>
|
||||
@@ -44,9 +44,9 @@
|
||||
<PackageReference Include="Avalonia.Desktop" Version="0.10.18" />
|
||||
<PackageReference Condition="'$(Configuration)' == 'Debug'" Include="Avalonia.Diagnostics" Version="0.10.18" />
|
||||
<PackageReference Include="MessageBox.Avalonia" Version="2.1.0" />
|
||||
<PackageReference Include="Projektanker.Icons.Avalonia" Version="5.5.0" />
|
||||
<PackageReference Include="Projektanker.Icons.Avalonia.FontAwesome" Version="5.5.0" />
|
||||
<PackageReference Include="Projektanker.Icons.Avalonia.MaterialDesign" Version="5.5.0" />
|
||||
<PackageReference Include="Projektanker.Icons.Avalonia" Version="5.6.0" />
|
||||
<PackageReference Include="Projektanker.Icons.Avalonia.FontAwesome" Version="5.6.0" />
|
||||
<PackageReference Include="Projektanker.Icons.Avalonia.MaterialDesign" Version="5.6.0" />
|
||||
<PackageReference Include="ThemeEditor.Controls.ColorPicker" Version="0.10.17" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
||||
@@ -1,21 +1,22 @@
|
||||
#!/bin/bash
|
||||
path="$(dirname "$0")"
|
||||
arch="$(uname -m)" # x86_64 or arm64
|
||||
args="$@"
|
||||
|
||||
testcmd() { command -v "$1" &> /dev/null; }
|
||||
|
||||
run_app_normal(){
|
||||
"$path/UVtools" $args
|
||||
exec "$path/UVtools" $@
|
||||
}
|
||||
|
||||
run_app_dotnet(){
|
||||
if [ -z "$(command -v dotnet)" ]; then
|
||||
if ! testcmd dotnet; then
|
||||
echo "$(uname) $arch requires dotnet in order to run."
|
||||
echo 'Please use the auto installer script to install all the dependencies.'
|
||||
exit -1
|
||||
fi
|
||||
|
||||
if [ -f "$path/UVtools.dll" ]; then
|
||||
dotnet "$path/UVtools.dll" $args
|
||||
exec dotnet "$path/UVtools.dll" $@
|
||||
else
|
||||
echo "Error: UVtools.dll not found."
|
||||
exit -1
|
||||
@@ -23,10 +24,8 @@ run_app_dotnet(){
|
||||
}
|
||||
|
||||
if [ "${OSTYPE:0:6}" == "darwin" ]; then
|
||||
if [ "$arch" == "arm64" ]; then
|
||||
run_app_dotnet
|
||||
elif [ -d "$path/../../../UVtools.app" ]; then
|
||||
open -n "$path/../../../UVtools.app" --args $args
|
||||
if [ -d "$path/../../../UVtools.app" ]; then
|
||||
open -n "$path/../../../UVtools.app" --args $@
|
||||
else
|
||||
run_app_normal
|
||||
fi
|
||||
|
||||
@@ -1760,6 +1760,28 @@ public sealed class UserSettings : BindableBase
|
||||
RequestPrintStatus = new (RemotePrinterRequest.RequestType.PrintStatus, RemotePrinterRequest.RequestMethod.GET, "job/list"),
|
||||
RequestPrinterInfo = new (RemotePrinterRequest.RequestType.PrinterInfo, RemotePrinterRequest.RequestMethod.GET, "setting/printerInfo"),
|
||||
},
|
||||
new RemotePrinter("0.0.0.0", 6000, "AnyCubic")
|
||||
{
|
||||
// https://github.com/rudetrooper/Octoprint-Chituboard/issues/4#issuecomment-961264287
|
||||
// https://github.com/adamoutler/anycubic-python
|
||||
// https://github.com/adamoutler/Pi-Zero-W-Smart-USB-Flash-Drive/tree/main/src/home/pi/usb_share/scripts
|
||||
CompatibleExtensions = "pws;pw0;pwx;dlp;dl2p;pwmo;pwma;pwms;pwmx;pmx2;pwmb;pwsq;pm3;pm3m;pm3r;pwc",
|
||||
RequestUploadFile = new (RemotePrinterRequest.RequestType.UploadFile, RemotePrinterRequest.RequestMethod.TCP),
|
||||
RequestPrintFile = new (RemotePrinterRequest.RequestType.PrintFile, RemotePrinterRequest.RequestMethod.TCP, @"<$getfile>{0}\/(\d+\.[\da-zA-Z]+),>goprint,{#1}$>"),
|
||||
RequestDeleteFile = new (RemotePrinterRequest.RequestType.DeleteFile, RemotePrinterRequest.RequestMethod.TCP, @"<$getfile>{0}\/(\d+\.[\da-zA-Z]+),>delfile,{#1}$>"),
|
||||
RequestPausePrint = new (RemotePrinterRequest.RequestType.PausePrint, RemotePrinterRequest.RequestMethod.TCP, "gopause"),
|
||||
RequestResumePrint = new (RemotePrinterRequest.RequestType.ResumePrint, RemotePrinterRequest.RequestMethod.TCP, "goresume"),
|
||||
RequestStopPrint = new (RemotePrinterRequest.RequestType.StopPrint, RemotePrinterRequest.RequestMethod.TCP, "gostop"),
|
||||
RequestGetFiles = new (RemotePrinterRequest.RequestType.GetFiles, RemotePrinterRequest.RequestMethod.TCP, "getfile"),
|
||||
RequestPrintStatus = new (RemotePrinterRequest.RequestType.PrintStatus, RemotePrinterRequest.RequestMethod.TCP, "getstatus"),
|
||||
RequestPrinterInfo = new (RemotePrinterRequest.RequestType.PrinterInfo, RemotePrinterRequest.RequestMethod.TCP, "sysinfo"),
|
||||
// getmode
|
||||
// getwifi - displays the current wifi network name.
|
||||
// gethistory - gets the history and print settings of previous prints.
|
||||
// delhistory - deletes printing history.
|
||||
// getPreview1 - returns a list of dimensions used for the print.
|
||||
// getPreview2 - returns a binary preview image of the print.
|
||||
},
|
||||
/*new RemotePrinter("0.0.0.0", 40454, "Creality Halot")
|
||||
{
|
||||
CompatibleExtensions = "cxdlp",
|
||||
|
||||
@@ -135,7 +135,8 @@
|
||||
<TextBlock Grid.Row="6" Text="{Binding Source={x:Static core:About.Author}}"/>
|
||||
<!--<TextBlock Grid.Row="8" Text="{Binding AgeStr, StringFormat=Age: {0}}"/>-->
|
||||
<controls:ButtonWithIcon Grid.Row="8" VerticalAlignment="Center"
|
||||
Command="{Binding OpenLicense}"
|
||||
Command="{Binding OpenWebsite}"
|
||||
CommandParameter="{Binding Source={x:Static core:About.LicenseUrl}}"
|
||||
Text="{Binding Source={x:Static core:About.License}}"
|
||||
Icon="fa-solid fa-balance-scale"/>
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using Avalonia;
|
||||
using Avalonia.Markup.Xaml;
|
||||
using Emgu.CV;
|
||||
using UVtools.Core;
|
||||
using UVtools.Core.Extensions;
|
||||
using UVtools.Core.SystemOS;
|
||||
using UVtools.WPF.Controls;
|
||||
|
||||
@@ -36,10 +36,11 @@ public class AboutWindow : WindowEx
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
var assemblies = AppDomain.CurrentDomain.GetAssemblies();
|
||||
var assembliesLengthPad = assemblies.Length.DigitCount();
|
||||
for (var i = 0; i < assemblies.Length; i++)
|
||||
{
|
||||
var assembly = assemblies[i].GetName();
|
||||
sb.AppendLine($"{(i + 1).ToString().PadLeft(assemblies.Length.ToString().Length, '0')}: {assembly.Name}, Version={assembly.Version}");
|
||||
sb.AppendLine($"{(i + 1).ToString().PadLeft(assembliesLengthPad, '0')}: {assembly.Name}, Version={assembly.Version}");
|
||||
}
|
||||
|
||||
return sb.ToString();
|
||||
@@ -60,11 +61,6 @@ public class AboutWindow : WindowEx
|
||||
try
|
||||
{
|
||||
return typeof(Mat).Assembly.GetName().Version!.ToString(3);
|
||||
/*var match = Regex.Match(CvInvoke.BuildInformation, @"(?:Version control:\s*)(\S*)");
|
||||
if (!match.Success) return "Not found!";
|
||||
var index = match.Groups[1].Value.LastIndexOf('-');
|
||||
if (index < 0) return match.Groups[1].Value;
|
||||
return match.Groups[1].Value[..index];*/
|
||||
}
|
||||
catch
|
||||
{
|
||||
@@ -109,13 +105,13 @@ public class AboutWindow : WindowEx
|
||||
// ReSharper disable once ConditionIsAlwaysTrueOrFalse
|
||||
var onScreen = Screens.ScreenFromVisual(App.MainWindow is not null ? App.MainWindow : this);
|
||||
var screen = Screens.All[i];
|
||||
result.AppendLine($"{i+1}: {screen.Bounds.Width} x {screen.Bounds.Height} @ {screen.PixelDensity * 100}%" +
|
||||
(screen.Primary ? " (Primary)" : string.Empty) +
|
||||
(onScreen == screen ? " (On this)" : string.Empty)
|
||||
result.AppendLine($"{i+1}: {screen.Bounds.Width} x {screen.Bounds.Height} @ {Math.Round(screen.PixelDensity * 100, 2)}%" +
|
||||
(screen.Primary ? " (Primary)" : null) +
|
||||
(onScreen == screen ? " (On this)" : null)
|
||||
);
|
||||
result.AppendLine($" WA: {screen.WorkingArea.Width} x {screen.WorkingArea.Height} UA: {Math.Round(screen.WorkingArea.Width / screen.PixelDensity)} x {Math.Round(screen.WorkingArea.Height / screen.PixelDensity)}");
|
||||
}
|
||||
return result.ToString().TrimEnd();
|
||||
return result.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -131,8 +127,6 @@ public class AboutWindow : WindowEx
|
||||
AvaloniaXamlLoader.Load(this);
|
||||
}
|
||||
|
||||
public void OpenLicense() => SystemAware.OpenBrowser(About.LicenseUrl);
|
||||
|
||||
public static string GetEssentialInformationStatic()
|
||||
{
|
||||
var message = new StringBuilder();
|
||||
|
||||
@@ -2115,7 +2115,7 @@
|
||||
Width="Auto" />
|
||||
<DataGridTemplateColumn Header="Method"
|
||||
IsReadOnly="False"
|
||||
Width="100">
|
||||
Width="130">
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate>
|
||||
<ComboBox
|
||||
|
||||
@@ -1,5 +1,62 @@
|
||||
#!/bin/sh
|
||||
#!/bin/bash
|
||||
|
||||
# The purpose of this custom AppRun script is to enablesymlinking the AppImage and invoking the corresponding
|
||||
# binary depending on which symlink name was used to invoke the AppImage.
|
||||
#
|
||||
# It also provides some additional help parameters in order to allow faster familiarization with functionality
|
||||
# embedded in this AppImage.
|
||||
|
||||
HERE="$(dirname "$(readlink -f "${0}")")"
|
||||
export PATH="${HERE}"/usr/bin/:"${PATH}"
|
||||
EXEC=$(grep -e '^Exec=.*' "${HERE}"/*.desktop | head -n 1 | cut -d "=" -f 2 | cut -d " " -f 1)
|
||||
exec "${EXEC}" $@
|
||||
|
||||
function help() {
|
||||
echo ' _ ___ ___ _ '
|
||||
echo ' | | | \ \ / / |_ ___ ___ | |___ '
|
||||
echo ' | | | |\ \ / /| __/ _ \ / _ \| / __|'
|
||||
echo ' | |_| | \ V / | || (_) | (_) | \__ \'
|
||||
echo ' \___/ \_/ \__\___/ \___/|_|___/'
|
||||
echo "
|
||||
--------------------------------------------------------------------------
|
||||
All the great UVtools functionality inside an AppImage package.
|
||||
--------------------------------------------------------------------------
|
||||
(This package uses the AppImage software packaging technology for Linux
|
||||
['One App == One File'] for easy availability of the newest UVtools
|
||||
releases across all major Linux distributions.)
|
||||
Usage: --help, -h
|
||||
------ # This message
|
||||
<path/to/file1> [path/to/file2] [path/to/file3] [...]
|
||||
# Opens and loads specific file(s) with UVtools
|
||||
--cmd-help
|
||||
# Display UVtoolsCmd help message
|
||||
--cmd, -c <argument(s)> [option(s)]
|
||||
# Redirect a command to UVtoolsCmd
|
||||
--appimage-extract
|
||||
# Unpack this AppImage into a local sub-directory [currently named 'squashfs-root']
|
||||
--appimage-help
|
||||
# Show available AppImage options
|
||||
"
|
||||
}
|
||||
|
||||
if [ "$1" == "--help" -o "$1" == "-h" ]; then
|
||||
help
|
||||
exit $?
|
||||
fi
|
||||
|
||||
if [ "$1" == "--cmd-help" ]; then
|
||||
exec 'UVtoolsCmd' --help
|
||||
exit $?
|
||||
fi
|
||||
|
||||
if [ "$1" == "--cmd" -o "$1" == "-c" ]; then
|
||||
if [ "$#" -lt 2 ]; then
|
||||
echo 'UVtoolsCmd requires at least one parameter'
|
||||
exec 'UVtoolsCmd' --help
|
||||
exit $?
|
||||
fi
|
||||
|
||||
shift
|
||||
exec 'UVtoolsCmd' $@
|
||||
exit $?
|
||||
fi
|
||||
|
||||
exec 'UVtools' $@
|
||||
@@ -0,0 +1,87 @@
|
||||
"\n"
|
||||
"General configuration for OpenCV 4.6.0 =====================================\n"
|
||||
" Version control: 3.4.2-7879-g1ca4fc084b\n"
|
||||
"\n"
|
||||
" Platform:\n"
|
||||
" Timestamp: 2022-11-29T05:23:11Z\n"
|
||||
" Host: Darwin 22.1.0 arm64\n"
|
||||
" CMake: 3.25.0\n"
|
||||
" CMake generator: Unix Makefiles\n"
|
||||
" CMake build tool: /usr/bin/make\n"
|
||||
" Configuration: Release\n"
|
||||
"\n"
|
||||
" CPU/HW features:\n"
|
||||
" Baseline: NEON FP16\n"
|
||||
"\n"
|
||||
" C/C++:\n"
|
||||
" Built as dynamic libs?: NO\n"
|
||||
" C++ standard: 11\n"
|
||||
" C++ Compiler: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/c++ (ver 14.0.0.14000029)\n"
|
||||
" C++ flags (Release): -fsigned-char -W -Wall -Wreturn-type -Wnon-virtual-dtor -Waddress -Wsequence-point -Wformat -Wformat-security -Wmissing-declarations -Wmissing-prototypes -Wstrict-prototypes -Wundef -Winit-self -Wpointer-arith -Wshadow -Wsign-promo -Wuninitialized -Winconsistent-missing-override -Wno-delete-non-virtual-dtor -Wno-unnamed-type-template-args -Wno-comment -Wno-deprecated-enum-enum-conversion -Wno-deprecated-anon-enum-enum-conversion -fdiagnostics-show-option -Qunused-arguments -Wno-semicolon-before-method-body -ffunction-sections -fdata-sections -fvisibility=hidden -fvisibility-inlines-hidden -O3 -DNDEBUG -DNDEBUG\n"
|
||||
" C++ flags (Debug): -fsigned-char -W -Wall -Wreturn-type -Wnon-virtual-dtor -Waddress -Wsequence-point -Wformat -Wformat-security -Wmissing-declarations -Wmissing-prototypes -Wstrict-prototypes -Wundef -Winit-self -Wpointer-arith -Wshadow -Wsign-promo -Wuninitialized -Winconsistent-missing-override -Wno-delete-non-virtual-dtor -Wno-unnamed-type-template-args -Wno-comment -Wno-deprecated-enum-enum-conversion -Wno-deprecated-anon-enum-enum-conversion -fdiagnostics-show-option -Qunused-arguments -Wno-semicolon-before-method-body -ffunction-sections -fdata-sections -fvisibility=hidden -fvisibility-inlines-hidden -g -O0 -DDEBUG -D_DEBUG\n"
|
||||
" C Compiler: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/cc\n"
|
||||
" C flags (Release): -fsigned-char -W -Wall -Wreturn-type -Wnon-virtual-dtor -Waddress -Wsequence-point -Wformat -Wformat-security -Wmissing-declarations -Wmissing-prototypes -Wstrict-prototypes -Wundef -Winit-self -Wpointer-arith -Wshadow -Wsign-promo -Wuninitialized -Winconsistent-missing-override -Wno-delete-non-virtual-dtor -Wno-unnamed-type-template-args -Wno-comment -Wno-deprecated-enum-enum-conversion -Wno-deprecated-anon-enum-enum-conversion -fdiagnostics-show-option -Qunused-arguments -Wno-semicolon-before-method-body -ffunction-sections -fdata-sections -fvisibility=hidden -fvisibility-inlines-hidden -O3 -DNDEBUG -DNDEBUG\n"
|
||||
" C flags (Debug): -fsigned-char -W -Wall -Wreturn-type -Wnon-virtual-dtor -Waddress -Wsequence-point -Wformat -Wformat-security -Wmissing-declarations -Wmissing-prototypes -Wstrict-prototypes -Wundef -Winit-self -Wpointer-arith -Wshadow -Wsign-promo -Wuninitialized -Winconsistent-missing-override -Wno-delete-non-virtual-dtor -Wno-unnamed-type-template-args -Wno-comment -Wno-deprecated-enum-enum-conversion -Wno-deprecated-anon-enum-enum-conversion -fdiagnostics-show-option -Qunused-arguments -Wno-semicolon-before-method-body -ffunction-sections -fdata-sections -fvisibility=hidden -fvisibility-inlines-hidden -g -O0 -DDEBUG -D_DEBUG\n"
|
||||
" Linker flags (Release): -Wl,-dead_strip \n"
|
||||
" Linker flags (Debug): -Wl,-dead_strip \n"
|
||||
" ccache: NO\n"
|
||||
" Precompiled headers: NO\n"
|
||||
" Extra dependencies: -framework OpenCL /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX13.0.sdk/System/Library/Frameworks/Accelerate.framework -lm -ldl -framework Cocoa -framework AppKit\n"
|
||||
" 3rdparty dependencies: ittnotify libjpeg-turbo libwebp libpng libtiff libopenjp2 IlmImf zlib tegra_hal\n"
|
||||
"\n"
|
||||
" OpenCV modules:\n"
|
||||
" To be built: core highgui imgcodecs imgproc videoio\n"
|
||||
" Disabled: dnn features2d flann gapi ml photo video world\n"
|
||||
" Disabled by dependency: calib3d objdetect stitching\n"
|
||||
" Unavailable: java python2 python3 ts\n"
|
||||
" Applications: -\n"
|
||||
" Documentation: NO\n"
|
||||
" Non-free algorithms: NO\n"
|
||||
"\n"
|
||||
" GUI: COCOA\n"
|
||||
" Cocoa: YES\n"
|
||||
" VTK support: NO\n"
|
||||
"\n"
|
||||
" Media I/O: \n"
|
||||
" ZLib: build (ver 1.2.12)\n"
|
||||
" JPEG: build-libjpeg-turbo (ver 2.1.2-62)\n"
|
||||
" WEBP: build (ver encoder: 0x020f)\n"
|
||||
" PNG: build (ver 1.6.37)\n"
|
||||
" TIFF: build (ver 42 - 4.2.0)\n"
|
||||
" JPEG 2000: build (ver 2.4.0)\n"
|
||||
" OpenEXR: build (ver 2.3.0)\n"
|
||||
" HDR: YES\n"
|
||||
" SUNRASTER: YES\n"
|
||||
" PXM: YES\n"
|
||||
" PFM: YES\n"
|
||||
"\n"
|
||||
" Video I/O:\n"
|
||||
" DC1394: NO\n"
|
||||
" FFMPEG: NO\n"
|
||||
" avcodec: NO\n"
|
||||
" avformat: NO\n"
|
||||
" avutil: NO\n"
|
||||
" swscale: NO\n"
|
||||
" avresample: NO\n"
|
||||
" GStreamer: NO\n"
|
||||
" AVFoundation: YES\n"
|
||||
"\n"
|
||||
" Parallel framework: GCD\n"
|
||||
"\n"
|
||||
" Trace: YES (with Intel ITT)\n"
|
||||
"\n"
|
||||
" Other third-party libraries:\n"
|
||||
" Lapack: YES (/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX13.0.sdk/System/Library/Frameworks/Accelerate.framework -lm -ldl)\n"
|
||||
" Eigen: YES (ver 3.4.0)\n"
|
||||
" Custom HAL: YES (carotene (ver 0.0.1))\n"
|
||||
" Protobuf: build (3.19.1)\n"
|
||||
"\n"
|
||||
" OpenCL: YES (no extra features)\n"
|
||||
" Include path: NO\n"
|
||||
" Link libraries: -framework OpenCL\n"
|
||||
"\n"
|
||||
" Python (for build): /opt/local/bin/python2.7\n"
|
||||
"\n"
|
||||
" Install to: /Users/palmer/emgucv/platforms/ubuntu/22.04/build/install\n"
|
||||
"-----------------------------------------------------------------\n"
|
||||
"\n"
|
||||
Binary file not shown.
@@ -933,6 +933,28 @@
|
||||
<param name="thickness"></param>
|
||||
<param name="lineType"></param>
|
||||
</member>
|
||||
<member name="M:UVtools.Core.Extensions.EmguExtensions.DrawCenteredSquare(Emgu.CV.Mat,System.Int32,System.Drawing.Point,Emgu.CV.Structure.MCvScalar,System.Int32,Emgu.CV.CvEnum.LineType)">
|
||||
<summary>
|
||||
Draw a square around a center point
|
||||
</summary>
|
||||
<param name="src"></param>
|
||||
<param name="size"></param>
|
||||
<param name="center"></param>
|
||||
<param name="color"></param>
|
||||
<param name="thickness"></param>
|
||||
<param name="lineType"></param>
|
||||
</member>
|
||||
<member name="M:UVtools.Core.Extensions.EmguExtensions.DrawCenteredRectangle(Emgu.CV.Mat,System.Drawing.Size,System.Drawing.Point,Emgu.CV.Structure.MCvScalar,System.Int32,Emgu.CV.CvEnum.LineType)">
|
||||
<summary>
|
||||
Draw a rectangle around a center point
|
||||
</summary>
|
||||
<param name="src"></param>
|
||||
<param name="size"></param>
|
||||
<param name="center"></param>
|
||||
<param name="color"></param>
|
||||
<param name="thickness"></param>
|
||||
<param name="lineType"></param>
|
||||
</member>
|
||||
<member name="M:UVtools.Core.Extensions.EmguExtensions.DrawPolygon(Emgu.CV.Mat,System.Int32,System.Int32,System.Drawing.Point,Emgu.CV.Structure.MCvScalar,System.Double,System.Int32,Emgu.CV.CvEnum.LineType,System.Nullable{Emgu.CV.CvEnum.FlipType})">
|
||||
<summary>
|
||||
Draw a polygon given number of sides and length
|
||||
@@ -4378,6 +4400,16 @@
|
||||
https://www.ucamco.com/files/downloads/file_en/456/gerber-layer-format-specification-revision-2022-02_en.pdf?ac97011bf6bce9aaf0b1aac43d84b05f
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:UVtools.Core.Gerber.GerberDocument.OffsetX">
|
||||
<summary>
|
||||
Gets or sets the X offset for drawings in millimeters
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:UVtools.Core.Gerber.GerberDocument.OffsetY">
|
||||
<summary>
|
||||
Gets or sets the Y offset for drawings in millimeters
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:UVtools.Core.Gerber.GerberDocument.PolarityColor">
|
||||
<summary>
|
||||
Gets the current polarity as <see cref="T:Emgu.CV.Structure.MCvScalar"/>. <see cref="P:UVtools.Core.Gerber.GerberDocument.InversePolarity"/> will affect the return value
|
||||
|
||||
Reference in New Issue
Block a user