mirror of
https://github.com/greenshot/greenshot
synced 2025-08-22 14:24:43 -07:00
Compare commits
No commits in common. "release/1.3" and "v1.3.239" have entirely different histories.
release/1.
...
v1.3.239
307 changed files with 9154 additions and 7157 deletions
14
.github/workflows/purge-cloudflare-cache.yml
vendored
14
.github/workflows/purge-cloudflare-cache.yml
vendored
|
@ -1,14 +0,0 @@
|
|||
name: Purge CloudFlare Cache
|
||||
|
||||
on:
|
||||
page_build:
|
||||
|
||||
jobs:
|
||||
purge_cache:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: purge
|
||||
uses: jakejarvis/cloudflare-purge-action@master
|
||||
env:
|
||||
CLOUDFLARE_ZONE: ${{ secrets.CLOUDFLARE_ZONE }}
|
||||
CLOUDFLARE_TOKEN: ${{ secrets.CLOUDFLARE_TOKEN }}
|
163
.github/workflows/release.yml
vendored
163
.github/workflows/release.yml
vendored
|
@ -1,163 +0,0 @@
|
|||
env:
|
||||
IS_RELEASE_BRANCH: ${{ startsWith(github.ref, 'refs/heads/release/') }}
|
||||
BRANCH_NAME: ${{ github.ref_name }}
|
||||
|
||||
name: Build and Deploy
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches:
|
||||
- 'release/1.*'
|
||||
paths-ignore:
|
||||
- '.github/**'
|
||||
- '.gitignore'
|
||||
- '*.md'
|
||||
- 'LICENSE'
|
||||
- 'build-and-deploy.ps1'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: windows-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Setup MSBuild
|
||||
uses: microsoft/setup-msbuild@v2
|
||||
|
||||
- name: Set up .NET
|
||||
uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
dotnet-version: '7.x'
|
||||
|
||||
- name: Restore NuGet packages
|
||||
run: msbuild src/Greenshot.sln /p:Configuration=Release /restore /t:PrepareForBuild
|
||||
env:
|
||||
Box13_ClientId: ${{ secrets.Box13_ClientId }}
|
||||
Box13_ClientSecret: ${{ secrets.Box13_ClientSecret }}
|
||||
DropBox13_ClientId: ${{ secrets.DropBox13_ClientId }}
|
||||
DropBox13_ClientSecret: ${{ secrets.DropBox13_ClientSecret }}
|
||||
Flickr_ClientId: ${{ secrets.Flickr_ClientId }}
|
||||
Flickr_ClientSecret: ${{ secrets.Flickr_ClientSecret }}
|
||||
Imgur13_ClientId: ${{ secrets.Imgur13_ClientId }}
|
||||
Imgur13_ClientSecret: ${{ secrets.Imgur13_ClientSecret }}
|
||||
Photobucket_ClientId: ${{ secrets.Photobucket_ClientId }}
|
||||
Photobucket_ClientSecret: ${{ secrets.Photobucket_ClientSecret }}
|
||||
Picasa_ClientId: ${{ secrets.Picasa_ClientId }}
|
||||
Picasa_ClientSecret: ${{ secrets.Picasa_ClientSecret }}
|
||||
|
||||
- name: Build and package
|
||||
run: msbuild src/Greenshot.sln /p:Configuration=Release /t:Rebuild /v:normal
|
||||
env:
|
||||
Box13_ClientId: ${{ secrets.Box13_ClientId }}
|
||||
Box13_ClientSecret: ${{ secrets.Box13_ClientSecret }}
|
||||
DropBox13_ClientId: ${{ secrets.DropBox13_ClientId }}
|
||||
DropBox13_ClientSecret: ${{ secrets.DropBox13_ClientSecret }}
|
||||
Flickr_ClientId: ${{ secrets.Flickr_ClientId }}
|
||||
Flickr_ClientSecret: ${{ secrets.Flickr_ClientSecret }}
|
||||
Imgur13_ClientId: ${{ secrets.Imgur13_ClientId }}
|
||||
Imgur13_ClientSecret: ${{ secrets.Imgur13_ClientSecret }}
|
||||
Photobucket_ClientId: ${{ secrets.Photobucket_ClientId }}
|
||||
Photobucket_ClientSecret: ${{ secrets.Photobucket_ClientSecret }}
|
||||
Picasa_ClientId: ${{ secrets.Picasa_ClientId }}
|
||||
Picasa_ClientSecret: ${{ secrets.Picasa_ClientSecret }}
|
||||
|
||||
- name: Copy Files
|
||||
run: |
|
||||
mkdir -p ${{ github.workspace }}/artifacts
|
||||
cp installer/Greenshot-INSTALLER-*.exe ${{ github.workspace }}/artifacts/
|
||||
|
||||
- name: Upload Artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: drop
|
||||
path: ${{ github.workspace }}/artifacts
|
||||
|
||||
deploy:
|
||||
runs-on: windows-latest
|
||||
needs: build
|
||||
|
||||
steps:
|
||||
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Download build artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: drop # Name of the artifact uploaded in previous steps
|
||||
path: drop # Local folder where artifacts are downloaded
|
||||
|
||||
- name: Extract version from file name
|
||||
if: env.IS_RELEASE_BRANCH == 'true'
|
||||
id: version_from_filename
|
||||
run: |
|
||||
$file = Get-ChildItem drop -Filter "Greenshot-INSTALLER-*.exe" | Select-Object -First 1
|
||||
if (-not $file) {
|
||||
throw "No matching file found in 'drop' directory."
|
||||
}
|
||||
if ($file.Name -match "Greenshot-INSTALLER-([\d\.]+)(.*)\.exe") {
|
||||
echo "version=$($matches[1])" >> $Env:GITHUB_OUTPUT
|
||||
} else {
|
||||
throw "Version number could not be extracted from file name: $($file.Name)"
|
||||
}
|
||||
shell: pwsh
|
||||
|
||||
- name: Set version from sanitized branch name
|
||||
if: env.IS_RELEASE_BRANCH != 'true'
|
||||
id: version_from_branchname
|
||||
run: |
|
||||
$branch = "${{ github.ref }}" -replace '^refs/heads/', ''
|
||||
$sanitized = $branch -replace '[^a-zA-Z0-9._-]', '_'
|
||||
echo "version=$sanitized" >> $Env:GITHUB_OUTPUT
|
||||
shell: pwsh
|
||||
|
||||
- name: Set version info
|
||||
id: version_info
|
||||
run: |
|
||||
echo "version=${{ steps.version_from_filename.outputs.version || steps.version_from_branchname.outputs.version }}" >> $GITHUB_OUTPUT
|
||||
shell: bash
|
||||
|
||||
|
||||
- name: Create tag
|
||||
if: env.IS_RELEASE_BRANCH == 'true'
|
||||
run: |
|
||||
git config user.name "github-actions[bot]"
|
||||
git config user.email "github-actions[bot]@users.noreply.github.com"
|
||||
git tag -a "v${{ steps.version_info.outputs.version }}" -m "v${{ steps.version_info.outputs.version }}"
|
||||
git push origin "v${{ steps.version_info.outputs.version }}"
|
||||
|
||||
- name: Rename installer for non-release branch
|
||||
if: env.IS_RELEASE_BRANCH != 'true'
|
||||
run: |
|
||||
branch="${BRANCH_NAME:-${GITHUB_REF#refs/heads/}}"
|
||||
sanitized=$(echo "$branch" | sed 's/[^a-zA-Z0-9._-]/_/g')
|
||||
mv drop/Greenshot-INSTALLER-*.exe "drop/Greenshot-INSTALLER-${sanitized}.exe"
|
||||
shell: bash
|
||||
|
||||
- name: Create GitHub Release
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
name: "Greenshot ${{ steps.version_info.outputs.version }} (continuous build)"
|
||||
tag_name: ${{ env.IS_RELEASE_BRANCH == 'true' && format('v{0}', steps.version_info.outputs.version) || env.BRANCH_NAME }}
|
||||
files: drop/*.exe
|
||||
generate_release_notes: true
|
||||
draft: ${{ env.IS_RELEASE_BRANCH != 'true' }}
|
||||
prerelease: true
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Trigger GitHub Pages rebuild
|
||||
shell: bash
|
||||
run: |
|
||||
curl -X POST \
|
||||
-H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" \
|
||||
-H "Accept: application/vnd.github+json" \
|
||||
https://api.github.com/repos/${{ github.repository }}/pages/builds
|
||||
|
18
.github/workflows/update-gh-pages.yml
vendored
18
.github/workflows/update-gh-pages.yml
vendored
|
@ -1,18 +0,0 @@
|
|||
name: Update GitHub Pages
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
release:
|
||||
types: [published, unpublished, created, edited, deleted, prereleased, released]
|
||||
|
||||
jobs:
|
||||
update-gh-pages:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Trigger GitHub Pages rebuild
|
||||
shell: bash
|
||||
run: |
|
||||
curl -X POST \
|
||||
-H "Authorization: Bearer ${{ secrets.GH_PAGES_TOKEN }}" \
|
||||
-H "Accept: application/vnd.github+json" \
|
||||
https://api.github.com/repos/${{ github.repository }}/pages/builds
|
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -215,5 +215,3 @@ ModelManifest.xml
|
|||
|
||||
# Rider files
|
||||
.idea
|
||||
|
||||
/installer/Greenshot-INSTALLER-*.exe
|
||||
|
|
23
README.md
23
README.md
|
@ -21,25 +21,4 @@ Being easy to understand and configurable, Greenshot is an efficient tool for pr
|
|||
|
||||
About this repository
|
||||
---------------------
|
||||
This is the development branch is for Greenshot 1.3, which has been first released on 2025-07-14.
|
||||
|
||||
Releases
|
||||
--------
|
||||
|
||||
You can find a list of all releases (stable and unstable) in the [Github releases](https://github.com/greenshot/greenshot/releases) or in the [version history on our website](https://getgreenshot.org/version-history/).
|
||||
The [downloads page on our website](https://getgreenshot.org/downloads/) always links to the latest stable release.
|
||||
|
||||
Trademark and Logo Usage Policy
|
||||
-------------------------------
|
||||
|
||||
The Greenshot logo and trademark are the property of the Greenshot development team. Unauthorized use of the logo and trademark is generally prohibited. However, we allow the use of the Greenshot name and logo in the following contexts:
|
||||
|
||||
* In blog posts, articles, or reviews that discuss or promote the Greenshot, provided that the usage is fair and does not imply endorsement by Greenshot.
|
||||
* In educational materials or presentations that accurately represent the project.
|
||||
|
||||
Please refrain from using the Greenshot logo and trademark in any promotional materials, products, or in a manner that may cause confusion or imply endorsement without prior written permission.
|
||||
|
||||
If you have any questions or wish to seek permission for other uses, please contact us.
|
||||
|
||||
Thank you for your understanding and cooperation.
|
||||
|
||||
This repository is for Greenshot 1.3, currently in development, but is the next planned release
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
# Security Policy
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
If you think you found a security issue in Greenshot, please report it responsibly [in our security section](https://github.com/greenshot/greenshot/security). We try to look into it as soon as possible - please give us some time for reaction, though.
|
106
azure-pipelines.yml
Normal file
106
azure-pipelines.yml
Normal file
|
@ -0,0 +1,106 @@
|
|||
# .NET Desktop
|
||||
# Build and run tests for .NET Desktop or Windows classic desktop solutions.
|
||||
# Add steps that publish symbols, save build artifacts, and more:
|
||||
# https://docs.microsoft.com/azure/devops/pipelines/apps/windows/dot-net
|
||||
|
||||
trigger:
|
||||
batch: true
|
||||
branches:
|
||||
include:
|
||||
- 'release/1.*'
|
||||
exclude:
|
||||
- 'develop'
|
||||
|
||||
stages:
|
||||
- stage: Build
|
||||
jobs:
|
||||
- job: Build
|
||||
variables:
|
||||
- group: 'Plug-in Credentials'
|
||||
- name: solution
|
||||
value: 'src/Greenshot.sln'
|
||||
- name: buildPlatform
|
||||
value: 'Any CPU'
|
||||
- name: buildConfiguration
|
||||
value: 'Release'
|
||||
|
||||
pool:
|
||||
vmImage: 'Windows-latest'
|
||||
|
||||
steps:
|
||||
- task: MSBuild@1
|
||||
displayName: Restore nuget packages and generate credential templates
|
||||
inputs:
|
||||
solution: '$(solution)'
|
||||
platform: $(buildPlatform)
|
||||
configuration: $(buildConfiguration)
|
||||
msbuildArguments: '/restore /t:PrepareForBuild'
|
||||
|
||||
- task: MSBuild@1
|
||||
displayName: Build and package
|
||||
inputs:
|
||||
solution: '$(solution)'
|
||||
platform: $(buildPlatform)
|
||||
configuration: $(buildConfiguration)
|
||||
env:
|
||||
Box13_ClientId: $(Box13_ClientId)
|
||||
Box13_ClientSecret: $(Box13_ClientSecret)
|
||||
DropBox13_ClientId: $(DropBox13_ClientId)
|
||||
DropBox13_ClientSecret: $(DropBox13_ClientSecret)
|
||||
Flickr_ClientId: $(Flickr_ClientId)
|
||||
Flickr_ClientSecret: $(Flickr_ClientSecret)
|
||||
Imgur13_ClientId: $(Imgur13_ClientId)
|
||||
Imgur13_ClientSecret: $(Imgur13_ClientSecret)
|
||||
Photobucket_ClientId: $(Photobucket_ClientId)
|
||||
Photobucket_ClientSecret: $(Photobucket_ClientSecret)
|
||||
Picasa_ClientId: $(Picasa_ClientId)
|
||||
Picasa_ClientSecret: $(Picasa_ClientSecret)
|
||||
|
||||
- task: CopyFiles@2
|
||||
displayName: 'Copy Files to: $(build.artifactstagingdirectory)'
|
||||
inputs:
|
||||
SourceFolder: '$(Build.SourcesDirectory)\installer'
|
||||
Contents: Greenshot-INSTALLER-*.exe
|
||||
TargetFolder: '$(build.artifactstagingdirectory)'
|
||||
flattenFolders: true
|
||||
|
||||
- task: PublishBuildArtifacts@1
|
||||
displayName: 'Publish Artifact: drop'
|
||||
inputs:
|
||||
PathtoPublish: '$(build.artifactstagingdirectory)'
|
||||
|
||||
- stage: Deploy
|
||||
jobs:
|
||||
- deployment: GitHub_Release
|
||||
pool:
|
||||
vmImage: 'Windows-latest'
|
||||
|
||||
environment: 'GitHub Release'
|
||||
strategy:
|
||||
# default deployment strategy
|
||||
runOnce:
|
||||
deploy:
|
||||
steps:
|
||||
- download: current
|
||||
artifact: drop
|
||||
|
||||
# Create a GitHub release
|
||||
- task: GitHubRelease@0
|
||||
inputs:
|
||||
gitHubConnection: GitHub Release
|
||||
repositoryName: '$(Build.Repository.Name)'
|
||||
action: 'create' # Options: create, edit, delete
|
||||
target: '$(Build.SourceVersion)' # Required when action == Create || Action == Edit
|
||||
tagSource: 'manual' # Required when action == Create# Options: auto, manual
|
||||
tag: 'v$(Build.BuildNumber)' # Required when action == Edit || Action == Delete || TagSource == Manual
|
||||
title: Greenshot $(Build.BuildNumber) unstable # Optional
|
||||
#releaseNotesSource: 'file' # Optional. Options: file, input
|
||||
#releaseNotesFile: # Optional
|
||||
#releaseNotes: # Optional
|
||||
assets: '$(Pipeline.Workspace)/drop/*.exe'
|
||||
#assetUploadMode: 'delete' # Optional. Options: delete, replace
|
||||
isDraft: true # Optional
|
||||
isPreRelease: true # Optional
|
||||
addChangeLog: true # Optional
|
||||
#compareWith: 'lastFullRelease' # Required when addChangeLog == True. Options: lastFullRelease, lastRelease, lastReleaseByTag
|
||||
#releaseTag: # Required when compareWith == LastReleaseByTag
|
|
@ -1,149 +0,0 @@
|
|||
# USAGE
|
||||
# * Enable script execution in Powershell: 'Set-ExecutionPolicy RemoteSigned'
|
||||
# * Create a GitHub personal access token (PAT) for greenshot repository
|
||||
# * user must be owner of the repository
|
||||
# * token needs read and write permissions ""for Contents"" and ""Pages""
|
||||
# * Execute the script and paste your token
|
||||
|
||||
# Prompt the user to securely input the Github token
|
||||
$SecureToken = Read-Host "Please enter your GitHub personal access token" -AsSecureString
|
||||
$ReleaseToken = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto([System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($SecureToken))
|
||||
|
||||
# Variables
|
||||
$RepoPath = "." # Replace with your local repo path
|
||||
$ArtifactsPath = "$RepoPath\artifacts"
|
||||
$SolutionFile = "$RepoPath\src\Greenshot.sln"
|
||||
|
||||
# Step 0: Update Local Repository
|
||||
git pull
|
||||
|
||||
# Step 1: Restore NuGet Packages
|
||||
Write-Host "Restoring NuGet packages..."
|
||||
msbuild "$SolutionFile" /p:Configuration=Release /restore /t:PrepareForBuild
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Write-Error "Failed to restore NuGet packages."
|
||||
exit $LASTEXITCODE
|
||||
}
|
||||
|
||||
# Step 2: Build and Package
|
||||
Write-Host "Building and packaging the solution..."
|
||||
msbuild "$SolutionFile" /p:Configuration=Release /t:Rebuild /v:normal
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Write-Error "Build failed."
|
||||
exit $LASTEXITCODE
|
||||
}
|
||||
|
||||
# Step 3: Copy Installer Files
|
||||
Write-Host "Copying installer files..."
|
||||
if (-not (Test-Path $ArtifactsPath)) {
|
||||
New-Item -ItemType Directory -Force -Path $ArtifactsPath
|
||||
}
|
||||
Copy-Item "$RepoPath\installer\Greenshot-INSTALLER-*.exe" -Destination $ArtifactsPath -Force
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Write-Error "Failed to copy installer files."
|
||||
exit $LASTEXITCODE
|
||||
}
|
||||
|
||||
# Step 4: Extract Version from File Name
|
||||
Write-Host "Extracting version from installer file name..."
|
||||
$InstallerFile = Get-ChildItem $ArtifactsPath -Filter "Greenshot-INSTALLER-*.exe" | Select-Object -Last 1
|
||||
if (-not $InstallerFile) {
|
||||
Write-Error "No matching installer file found in '$ArtifactsPath'."
|
||||
exit 1
|
||||
}
|
||||
|
||||
if ($InstallerFile.Name -match "Greenshot-INSTALLER-([\d\.]+).*\.exe") {
|
||||
$Version = $matches[1]
|
||||
Write-Host "Extracted version: $Version"
|
||||
} else {
|
||||
Write-Error "Version number could not be extracted from file name: $($InstallerFile.Name)"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Step 5: Create Git Tag
|
||||
Write-Host "Creating Git tag..."
|
||||
cd $RepoPath
|
||||
#git config user.name "local-script"
|
||||
#git config user.email "local-script@example.com"
|
||||
git tag -a "v$Version" -m "v$Version"
|
||||
git push origin "v$Version"
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Write-Error "Failed to create Git tag."
|
||||
exit $LASTEXITCODE
|
||||
}
|
||||
|
||||
# Step 6: Create GitHub Release
|
||||
Write-Host "Creating GitHub release..."
|
||||
$Headers = @{
|
||||
Authorization = "Bearer $ReleaseToken"
|
||||
Accept = "application/vnd.github+json"
|
||||
}
|
||||
$ReleaseData = @{
|
||||
tag_name = "v$Version"
|
||||
name = "Greenshot $Version unstable"
|
||||
body = "Pre-release of Greenshot $Version."
|
||||
draft = $true
|
||||
prerelease = $true
|
||||
generate_release_notes = $true
|
||||
}
|
||||
$ReleaseResponse = Invoke-RestMethod `
|
||||
-Uri "https://api.github.com/repos/greenshot/greenshot/releases" `
|
||||
-Method POST `
|
||||
-Headers $Headers `
|
||||
-Body (ConvertTo-Json $ReleaseData -Depth 10)
|
||||
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Write-Error "Failed to create GitHub release."
|
||||
exit $LASTEXITCODE
|
||||
}
|
||||
|
||||
Write-Host "Release created successfully."
|
||||
|
||||
# Get the release ID from the response
|
||||
$ReleaseId = $ReleaseResponse.id
|
||||
Write-Host "Release ID: $ReleaseId"
|
||||
|
||||
# Step 7: Upload .exe File to Release
|
||||
Write-Host "Uploading .exe file to GitHub release..."
|
||||
$ExeFilePath = "$ArtifactsPath\$($InstallerFile.Name)"
|
||||
if (-Not (Test-Path $ExeFilePath)) {
|
||||
Write-Error "Built .exe file not found: $ExeFilePath"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# GitHub API for uploading release assets
|
||||
$UploadUrl = $ReleaseResponse.upload_url -replace "{.*}", ""
|
||||
|
||||
# Upload the file
|
||||
$FileHeaders = @{
|
||||
Authorization = "Bearer $ReleaseToken"
|
||||
ContentType = "application/octet-stream"
|
||||
}
|
||||
$FileName = [System.IO.Path]::GetFileName($ExeFilePath)
|
||||
|
||||
Invoke-RestMethod `
|
||||
-Uri "$($UploadUrl)?name=$FileName" `
|
||||
-Method POST `
|
||||
-Headers $FileHeaders `
|
||||
-InFile $ExeFilePath `
|
||||
-ContentType "application/octet-stream"
|
||||
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Write-Error "Failed to upload .exe file to release."
|
||||
exit $LASTEXITCODE
|
||||
}
|
||||
|
||||
Write-Host "File uploaded successfully: $FileName"
|
||||
|
||||
# Step 7: Trigger GitHub Pages Rebuild
|
||||
#Write-Host "Triggering GitHub Pages rebuild..."
|
||||
#Invoke-RestMethod `
|
||||
# -Uri "https://api.github.com/repos/greenshot/greenshot/pages/builds" `
|
||||
# -Method POST `
|
||||
# -Headers $Headers
|
||||
#if ($LASTEXITCODE -ne 0) {
|
||||
# Write-Error "Failed to trigger GitHub Pages rebuild."
|
||||
# exit $LASTEXITCODE
|
||||
#}
|
||||
#
|
||||
#Write-Host "GitHub Pages rebuild triggered successfully."
|
|
@ -7,29 +7,7 @@ CHANGE LOG:
|
|||
|
||||
All details to our tickets can be found here: https://greenshot.atlassian.net
|
||||
|
||||
# Greenshot 1.3.xxx
|
||||
|
||||
Bugs fixed:
|
||||
* greenshot.ini: Exclude Plugins and Include Plugins setting broken [#648](https://github.com/greenshot/greenshot/issues/648) [#642](https://github.com/greenshot/greenshot/issues/642) thanks to @Christian-Schulz for providing the fix
|
||||
|
||||
Features added:
|
||||
|
||||
# Greenshot 1.3.296
|
||||
|
||||
Bugs fixed
|
||||
* Fix Administrative installation via user interface [#546](https://github.com/greenshot/greenshot/issues/546) [#611](https://github.com/greenshot/greenshot/issues/611) [#598](https://github.com/greenshot/greenshot/issues/598)
|
||||
|
||||
Features added:
|
||||
* Installer: Allow Choice between All-Users (Administrative) and Current-User Installation [#625](https://github.com/greenshot/greenshot/pull/625)
|
||||
|
||||
# Greenshot 1.3.292
|
||||
|
||||
Bugs fixed:
|
||||
* Fix Administrative installation via command line using /ALLUSERS [#601](https://github.com/greenshot/greenshot/issues/601) [#619](https://github.com/greenshot/greenshot/issues/619)
|
||||
|
||||
# Greenshot 1.3.290
|
||||
|
||||
Note: the version information for the first 1.3 release is outdated/incomplete. Due to the long timespan and large amount of changes between 1.2 and 1.3 we lost track. Sorry.
|
||||
# Release notes for Greenshot 1.3
|
||||
|
||||
Greenshot 1.3 is the first Greenshot which targets .NET 4.7.2 which just by doing to solves some general issues in the area of Internet Explorer capturing, TLS communication and some other minor issues.
|
||||
|
||||
|
@ -668,5 +646,3 @@ Features added:
|
|||
* when clicking two overlapping elements, the one created later gets selected [ 1725175 ]
|
||||
* created textboxes can now be edited with a doubleclick [ 1704408 ]
|
||||
* selected font is now stored in the application config file [ 1704411 ]
|
||||
|
||||
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
#define BinDir "bin\Release\net472"
|
||||
#define ReleaseDir "..\..\src\Greenshot\bin\Release\net472"
|
||||
#define PluginDir "..\..\src\Greenshot\bin\Release\net472\Plugins"
|
||||
#define CertumThumbprint GetEnv('CertumThumbprint')
|
||||
|
||||
; Include the scripts to install .NET Framework
|
||||
; See https://www.codeproject.com/KB/install/dotnetfx_innosetup_instal.aspx
|
||||
|
@ -83,34 +82,33 @@ Source: {#LanguagesDir}\*zh-CN*; Excludes: "*installer*,*website*"; DestDir: {ap
|
|||
Source: {#LanguagesDir}\*zh-TW*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\zhTW; Flags: overwritereadonly ignoreversion replacesameversion;
|
||||
|
||||
;Office Plugin
|
||||
Source: {#PluginDir}\Greenshot.Plugin.Office\Greenshot.Plugin.Office.dll; DestDir: {app}\Plugins\Office; Components: plugins\office; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion;
|
||||
Source: {#PluginDir}\Greenshot.Plugin.Office\*.dll; DestDir: {app}\Plugins\Office; Components: plugins\office; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion;
|
||||
;JIRA Plugin
|
||||
Source: {#PluginDir}\Greenshot.Plugin.Jira\*Jira*.dll; DestDir: {app}\Plugins\Jira; Components: plugins\jira; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion;
|
||||
Source: {#PluginDir}\Greenshot.Plugin.Jira\*.dll; DestDir: {app}\Plugins\Jira; Components: plugins\jira; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion;
|
||||
Source: {#BaseDir}\Greenshot.Plugin.Jira\Languages\language_jira*.xml; DestDir: {app}\Languages\Plugins\Jira; Components: plugins\jira; Flags: overwritereadonly ignoreversion replacesameversion;
|
||||
;Imgur Plugin
|
||||
Source: {#PluginDir}\Greenshot.Plugin.Imgur\Greenshot.Plugin.Imgur.dll; DestDir: {app}\Plugins\Imgur; Components: plugins\imgur; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion;
|
||||
Source: {#PluginDir}\Greenshot.Plugin.Imgur\*.dll; DestDir: {app}\Plugins\Imgur; Components: plugins\imgur; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion;
|
||||
Source: {#BaseDir}\Greenshot.Plugin.Imgur\Languages\language_imgur*.xml; DestDir: {app}\Languages\Plugins\Imgur; Components: plugins\imgur; Flags: overwritereadonly ignoreversion replacesameversion;
|
||||
;Box Plugin
|
||||
Source: {#PluginDir}\Greenshot.Plugin.Box\Greenshot.Plugin.Box.dll; DestDir: {app}\Plugins\Box; Components: plugins\box; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion;
|
||||
Source: {#PluginDir}\Greenshot.Plugin.Box\*.dll; DestDir: {app}\Plugins\Box; Components: plugins\box; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion;
|
||||
Source: {#BaseDir}\Greenshot.Plugin.Box\Languages\language_box*.xml; DestDir: {app}\Languages\Plugins\Box; Components: plugins\box; Flags: overwritereadonly ignoreversion replacesameversion;
|
||||
;DropBox Plugin
|
||||
Source: {#PluginDir}\Greenshot.Plugin.DropBox\Greenshot.Plugin.DropBox.dll; DestDir: {app}\Plugins\DropBox; Components: plugins\dropbox; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion;
|
||||
Source: {#PluginDir}\Greenshot.Plugin.DropBox\*.dll; DestDir: {app}\Plugins\DropBox; Components: plugins\dropbox; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion;
|
||||
Source: {#BaseDir}\Greenshot.Plugin.DropBox\Languages\language_dropbox*.xml; DestDir: {app}\Languages\Plugins\DropBox; Components: plugins\dropbox; Flags: overwritereadonly ignoreversion replacesameversion;
|
||||
;Flickr Plugin
|
||||
Source: {#PluginDir}\Greenshot.Plugin.Flickr\Greenshot.Plugin.Flickr.dll; DestDir: {app}\Plugins\Flickr; Components: plugins\flickr; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion;
|
||||
Source: {#PluginDir}\Greenshot.Plugin.Flickr\*.dll; DestDir: {app}\Plugins\Flickr; Components: plugins\flickr; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion;
|
||||
Source: {#BaseDir}\Greenshot.Plugin.Flickr\Languages\language_flickr*.xml; DestDir: {app}\Languages\Plugins\Flickr; Components: plugins\flickr; Flags: overwritereadonly ignoreversion replacesameversion;
|
||||
;Photobucket Plugin
|
||||
Source: {#PluginDir}\Greenshot.Plugin.Photobucket\Greenshot.Plugin.Photobucket.dll; DestDir: {app}\Plugins\Photobucket; Components: plugins\photobucket; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion;
|
||||
Source: {#PluginDir}\Greenshot.Plugin.Photobucket\*.dll; DestDir: {app}\Plugins\Photobucket; Components: plugins\photobucket; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion;
|
||||
Source: {#BaseDir}\Greenshot.Plugin.Photobucket\Languages\language_photo*.xml; DestDir: {app}\Languages\Plugins\Photobucket; Components: plugins\photobucket; Flags: overwritereadonly ignoreversion replacesameversion;
|
||||
;Confluence Plugin
|
||||
Source: {#PluginDir}\Greenshot.Plugin.Confluence\Greenshot.Plugin.Confluence.dll; DestDir: {app}\Plugins\Confluence; Components: plugins\confluence; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion;
|
||||
Source: {#PluginDir}\Greenshot.Plugin.Confluence\*.dll; DestDir: {app}\Plugins\Confluence; Components: plugins\confluence; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion;
|
||||
Source: {#BaseDir}\Greenshot.Plugin.Confluence\Languages\language_confluence*.xml; DestDir: {app}\Languages\Plugins\Confluence; Components: plugins\confluence; Flags: overwritereadonly ignoreversion replacesameversion;
|
||||
;ExternalCommand Plugin
|
||||
Source: {#PluginDir}\Greenshot.Plugin.ExternalCommand\Greenshot.Plugin.ExternalCommand.dll; DestDir: {app}\Plugins\ExternalCommand; Components: plugins\externalcommand; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion;
|
||||
Source: {#PluginDir}\Greenshot.Plugin.ExternalCommand\*.dll; DestDir: {app}\Plugins\ExternalCommand; Components: plugins\externalcommand; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion;
|
||||
Source: {#BaseDir}\Greenshot.Plugin.ExternalCommand\Languages\language_externalcommand*.xml; DestDir: {app}\Languages\Plugins\ExternalCommand; Components: plugins\externalcommand; Flags: overwritereadonly ignoreversion replacesameversion;
|
||||
;Win 10 Plugin
|
||||
Source: {#PluginDir}\Greenshot.Plugin.Win10\Greenshot.Plugin.Win10.dll; DestDir: {app}\Plugins\Win10; Components: plugins\win10; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion;
|
||||
Source: {#PluginDir}\Greenshot.Plugin.Win10\Microsoft.Toolkit.Uwp.Notifications.dll; DestDir: {app}\Plugins\Win10; Components: plugins\win10; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion;
|
||||
Source: {#PluginDir}\Greenshot.Plugin.Win10\*.dll; DestDir: {app}\Plugins\Win10; Components: plugins\win10; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion;
|
||||
|
||||
[Setup]
|
||||
; changes associations is used when the installer installs new extensions, it clears the explorer icon cache
|
||||
|
@ -127,27 +125,21 @@ AppVersion={#Version}
|
|||
ArchitecturesInstallIn64BitMode=x64
|
||||
Compression=lzma2/ultra64
|
||||
SolidCompression=yes
|
||||
DefaultDirName={autopf}\{#ExeName}
|
||||
DefaultDirName={code:DefDirRoot}\{#ExeName}
|
||||
DefaultGroupName={#ExeName}
|
||||
InfoBeforeFile=..\additional_files\readme.txt
|
||||
LicenseFile=..\additional_files\license.txt
|
||||
LanguageDetectionMethod=uilanguage
|
||||
MinVersion=6.1sp1
|
||||
OutputBaseFilename={#ExeName}-INSTALLER-{#Version}-UNSTABLE
|
||||
OutputDir=..\
|
||||
; user may choose between all-users vs. current-user installation in a dialog or by using the /ALLUSERS flag (on the command line)
|
||||
; in registry section, HKA will take care of the appropriate root key (HKLM vs. HKCU), see https://jrsoftware.org/ishelp/index.php?topic=admininstallmode
|
||||
PrivilegesRequiredOverridesAllowed=dialog
|
||||
; admin privileges not required, unless user chooses all-users installation
|
||||
; the installer will ask for elevation if needed
|
||||
PrivilegesRequired=lowest
|
||||
SetupIconFile=..\..\src\Greenshot\icons\applicationIcon\icon.ico
|
||||
#if CertumThumbprint != ""
|
||||
OutputBaseFilename={#ExeName}-INSTALLER-{#Version}-UNSTABLE
|
||||
SignTool=SignTool sign /sha1 "{#CertumThumbprint}" /tr http://time.certum.pl /td sha256 /fd sha256 /v $f
|
||||
SignedUninstaller=yes
|
||||
#else
|
||||
OutputBaseFilename={#ExeName}-INSTALLER-{#Version}-UNSTABLE-UNSIGNED
|
||||
#endif
|
||||
; Create a SHA1 signature
|
||||
; SignTool=SignTool sign /debug /fd sha1 /tr https://time.certum.pl /td sha1 $f
|
||||
; Append a SHA256 to the previous SHA1 signature (this is what as does)
|
||||
; SignTool=SignTool sign /debug /as /fd sha256 /tr https://time.certum.pl /td sha256 $f
|
||||
; SignedUninstaller=yes
|
||||
UninstallDisplayIcon={app}\{#ExeName}.exe
|
||||
Uninstallable=true
|
||||
VersionInfoCompany={#ExeName}
|
||||
|
@ -159,7 +151,6 @@ VersionInfoVersion={#Version}
|
|||
WizardImageFile=installer-large.bmp
|
||||
; Reference a bitmap, max size 55x58
|
||||
WizardSmallImageFile=installer-small.bmp
|
||||
|
||||
[Registry]
|
||||
; Delete all startup entries, so we don't have leftover values
|
||||
Root: HKCU; Subkey: Software\Microsoft\Windows\CurrentVersion\Run; ValueType: none; ValueName: {#ExeName}; Flags: deletevalue noerror;
|
||||
|
@ -178,16 +169,22 @@ Root: HKLM; Subkey: Software\Classes\.greenshot; ValueType: none; ValueName: {#E
|
|||
Root: HKLM; Subkey: Software\Classes\Greenshot; ValueType: none; ValueName: {#ExeName}; Flags: deletevalue noerror;
|
||||
|
||||
; Create the startup entries if requested to do so
|
||||
Root: HKA; Subkey: Software\Microsoft\Windows\CurrentVersion\Run; ValueType: string; ValueName: {#ExeName}; ValueData: """{app}\{#ExeName}.exe"""; Flags: uninsdeletevalue noerror; Tasks: startup
|
||||
; HKEY_LOCAL_USER - for current user only
|
||||
Root: HKCU; Subkey: Software\Microsoft\Windows\CurrentVersion\Run; ValueType: string; ValueName: {#ExeName}; ValueData: """{app}\{#ExeName}.exe"""; Permissions: users-modify; Flags: uninsdeletevalue noerror; Tasks: startup; Check: IsRegularUser
|
||||
; HKEY_LOCAL_MACHINE - for all users when admin
|
||||
Root: HKLM; Subkey: Software\Microsoft\Windows\CurrentVersion\Run; ValueType: string; ValueName: {#ExeName}; ValueData: """{app}\{#ExeName}.exe"""; Permissions: admins-modify; Flags: uninsdeletevalue noerror; Tasks: startup; Check: not IsRegularUser
|
||||
|
||||
; Register our own filetype for all users
|
||||
Root: HKA; Subkey: Software\Classes\.greenshot; ValueType: string; ValueName: ""; ValueData: "Greenshot"; Flags: uninsdeletevalue noerror
|
||||
Root: HKA; Subkey: Software\Classes\Greenshot; ValueType: string; ValueName: ""; ValueData: "Greenshot File"; Flags: uninsdeletevalue noerror
|
||||
Root: HKA; Subkey: Software\Classes\Greenshot\DefaultIcon; ValueType: string; ValueName: ""; ValueData: """{app}\Greenshot.EXE,0"""; Flags: uninsdeletevalue noerror
|
||||
Root: HKA; Subkey: Software\Classes\Greenshot\shell\open\command; ValueType: string; ValueName: ""; ValueData: """{app}\Greenshot.EXE"" --openfile ""%1"""; Flags: uninsdeletevalue noerror
|
||||
|
||||
; Disable the default PRTSCR Snipping Tool in Windows 11
|
||||
Root: HKCU; Subkey: Control Panel\Keyboard; ValueType: dword; ValueName: "PrintScreenKeyForSnippingEnabled"; ValueData: "0"; Flags: uninsdeletevalue; Check: ShouldDisableSnippingTool
|
||||
; HKEY_LOCAL_USER - for current user only
|
||||
Root: HKCU; Subkey: Software\Classes\.greenshot; ValueType: string; ValueName: ""; ValueData: "Greenshot"; Permissions: users-modify; Flags: uninsdeletevalue noerror; Check: IsRegularUser
|
||||
Root: HKCU; Subkey: Software\Classes\Greenshot; ValueType: string; ValueName: ""; ValueData: "Greenshot File"; Permissions: users-modify; Flags: uninsdeletevalue noerror; Check: IsRegularUser
|
||||
Root: HKCU; Subkey: Software\Classes\Greenshot\DefaultIcon; ValueType: string; ValueName: ""; ValueData: """{app}\Greenshot.EXE,0"""; Permissions: users-modify; Flags: uninsdeletevalue noerror; Check: IsRegularUser
|
||||
Root: HKCU; Subkey: Software\Classes\Greenshot\shell\open\command; ValueType: string; ValueName: ""; ValueData: """{app}\Greenshot.EXE"" --openfile ""%1"""; Permissions: users-modify; Flags: uninsdeletevalue noerror; Check: IsRegularUser
|
||||
; HKEY_LOCAL_MACHINE - for all users when admin
|
||||
Root: HKLM; Subkey: Software\Classes\.greenshot; ValueType: string; ValueName: ""; ValueData: "Greenshot"; Permissions: admins-modify; Flags: uninsdeletevalue noerror; Check: not IsRegularUser
|
||||
Root: HKLM; Subkey: Software\Classes\Greenshot; ValueType: string; ValueName: ""; ValueData: "Greenshot File"; Permissions: admins-modify; Flags: uninsdeletevalue noerror; Check: not IsRegularUser
|
||||
Root: HKLM; Subkey: Software\Classes\Greenshot\DefaultIcon; ValueType: string; ValueName: ""; ValueData: """{app}\Greenshot.EXE,0"""; Permissions: admins-modify; Flags: uninsdeletevalue noerror; Check: not IsRegularUser
|
||||
Root: HKLM; Subkey: Software\Classes\Greenshot\shell\open\command; ValueType: string; ValueName: ""; ValueData: """{app}\Greenshot.EXE"" --openfile ""%1"""; Permissions: admins-modify; Flags: uninsdeletevalue noerror; Check: not IsRegularUser
|
||||
|
||||
[Icons]
|
||||
Name: {group}\{#ExeName}; Filename: {app}\{#ExeName}.exe; WorkingDir: {app}; AppUserModelID: "{#ExeName}"
|
||||
|
@ -271,7 +268,6 @@ en.win10=Windows 10 plug-in
|
|||
en.UninstallIconDescription=Uninstall
|
||||
en.ShowLicense=Show license
|
||||
en.ShowReadme=Show Readme
|
||||
en.disablewin11snippingtool=Disable Win11 default PrtScr snipping tool
|
||||
|
||||
de.confluence=Confluence Plug-in
|
||||
de.default=Standard installation
|
||||
|
@ -284,7 +280,6 @@ de.optimize=Optimierung der Leistung, kann etwas dauern.
|
|||
de.startgreenshot={#ExeName} starten
|
||||
de.startup={#ExeName} starten wenn Windows hochfährt
|
||||
de.win10=Windows 10 Plug-in
|
||||
de.disablewin11snippingtool=Deaktiviere das Standard Windows 11 Snipping Tool auf "Druck"
|
||||
|
||||
es.confluence=Extensión para Confluence
|
||||
es.default=${default}
|
||||
|
@ -486,7 +481,6 @@ Name: "compact"; Description: "{code:CompactInstall}"
|
|||
Name: "custom"; Description: "{code:CustomInstall}"; Flags: iscustom
|
||||
|
||||
[Components]
|
||||
Name: "disablesnippingtool"; Description: {cm:disablewin11snippingtool}; Flags: disablenouninstallwarning; Types: default full custom; Check: IsWindows11OrNewer()
|
||||
Name: "greenshot"; Description: "Greenshot"; Types: default full compact custom; Flags: fixed
|
||||
;Name: "plugins\networkimport"; Description: "Network Import Plugin"; Types: full
|
||||
Name: "plugins\box"; Description: {cm:box}; Types: full custom; Flags: disablenouninstallwarning
|
||||
|
@ -536,8 +530,23 @@ Name: "languages\ukUA"; Description: {cm:ukUA}; Types: full custom; Flags: disab
|
|||
Name: "languages\viVN"; Description: {cm:viVN}; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('e')
|
||||
Name: "languages\zhCN"; Description: {cm:zhCN}; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('a')
|
||||
Name: "languages\zhTW"; Description: {cm:zhTW}; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('9')
|
||||
|
||||
[Code]
|
||||
// Do we have a regular user trying to install this?
|
||||
function IsRegularUser(): Boolean;
|
||||
begin
|
||||
Result := not (IsAdmin or IsAdminInstallMode);
|
||||
end;
|
||||
|
||||
// The following code is used to select the installation path, this is localappdata if non poweruser
|
||||
function DefDirRoot(Param: String): String;
|
||||
begin
|
||||
if IsRegularUser then
|
||||
Result := ExpandConstant('{localappdata}')
|
||||
else
|
||||
Result := ExpandConstant('{pf}')
|
||||
end;
|
||||
|
||||
|
||||
function FullInstall(Param : String) : String;
|
||||
begin
|
||||
result := SetupMessage(msgFullInstallation);
|
||||
|
@ -735,19 +744,6 @@ begin
|
|||
Result := IsWindowsVersionOrNewer(10, 0);
|
||||
end;
|
||||
|
||||
function IsWindows11OrNewer: Boolean;
|
||||
var
|
||||
WindowsVersion: TWindowsVersion;
|
||||
begin
|
||||
GetWindowsVersionEx(WindowsVersion);
|
||||
Result := (WindowsVersion.Major >= 10) and (WindowsVersion.Build >= 22000);
|
||||
end;
|
||||
|
||||
function ShouldDisableSnippingTool: Boolean;
|
||||
begin
|
||||
Result := IsComponentSelected('disablesnippingtool');
|
||||
end;
|
||||
|
||||
[Run]
|
||||
Filename: "{app}\{#ExeName}.exe"; Description: "{cm:startgreenshot}"; Parameters: "{code:GetParamsForGS}"; WorkingDir: "{app}"; Flags: nowait postinstall runasoriginaluser
|
||||
Filename: "https://getgreenshot.org/thank-you/?language={language}&version={#Version}"; Flags: shellexec runasoriginaluser
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<packageSources>
|
||||
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" />
|
||||
</packageSources>
|
||||
</configuration>
|
|
@ -1,13 +1,13 @@
|
|||
<Project>
|
||||
<PropertyGroup>
|
||||
<Copyright>Copyright © Greenshot 2004-2022</Copyright>
|
||||
<Copyright>Copyright © Greenshot 2004-2021</Copyright>
|
||||
<Authors>Greenshot</Authors>
|
||||
<PackageIconUrl>https://getgreenshot.org/favicon.ico</PackageIconUrl>
|
||||
<RepositoryUrl>https://github.com/greenshot/greenshot</RepositoryUrl>
|
||||
<RepositoryType>git</RepositoryType>
|
||||
<PackageProjectUrl>https://github.com/greenshot/greenshot</PackageProjectUrl>
|
||||
<PackageLicenseExpression>GPL-3.0-only</PackageLicenseExpression>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<LangVersion>9</LangVersion>
|
||||
<UseWPF>true</UseWPF>
|
||||
<UseWindowsForms>true</UseWindowsForms>
|
||||
<RuntimeIdentifiers>win10-x64;win10-x86;win-x64;win-x86</RuntimeIdentifiers>
|
||||
|
@ -46,7 +46,7 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<ItemGroup Condition="!$(MSBuildProjectName.Contains('Tests')) And $(MSBuildProjectName.StartsWith('Greenshot'))">
|
||||
<PackageReference Include="Nerdbank.GitVersioning" Version="3.5.113">
|
||||
<PackageReference Include="Nerdbank.GitVersioning" Version="3.4.255">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
|
||||
</PackageReference>
|
||||
|
|
|
@ -1,65 +1,13 @@
|
|||
<Project>
|
||||
<UsingTask TaskName="ApplyTokenReplacements" TaskFactory="CodeTaskFactory" AssemblyName="Microsoft.Build.Tasks.Core">
|
||||
<ParameterGroup>
|
||||
<InputLines ParameterType="Microsoft.Build.Framework.ITaskItem[]" Required="true" />
|
||||
<Tokens ParameterType="Microsoft.Build.Framework.ITaskItem[]" Required="true" />
|
||||
<OutputLines ParameterType="Microsoft.Build.Framework.ITaskItem[]" Output="true" />
|
||||
</ParameterGroup>
|
||||
<Task>
|
||||
<Reference Include="System.Text.RegularExpressions" />
|
||||
<Code Type="Fragment" Language="cs">
|
||||
<![CDATA[
|
||||
var output = new List<ITaskItem>();
|
||||
foreach (var line in InputLines)
|
||||
{
|
||||
string text = line.ItemSpec;
|
||||
foreach (var token in Tokens)
|
||||
{
|
||||
string tokenName = token.ItemSpec;
|
||||
// Skip if tokenName is null or empty
|
||||
if (string.IsNullOrEmpty(tokenName))
|
||||
continue;
|
||||
|
||||
string replacementValue = token.GetMetadata("ReplacementValue");
|
||||
if (!string.IsNullOrEmpty(replacementValue))
|
||||
{
|
||||
string placeholder = "$"+ "{"+tokenName+"}"; // Token-Format wie $(Box13_ClientId)
|
||||
text = text.Replace(placeholder, replacementValue);
|
||||
}
|
||||
}
|
||||
output.Add(new Microsoft.Build.Utilities.TaskItem(text));
|
||||
}
|
||||
OutputLines = output.ToArray();
|
||||
]]>
|
||||
</Code>
|
||||
</Task>
|
||||
</UsingTask>
|
||||
|
||||
<PropertyGroup Condition="Exists('$(ProjectDir)$(ProjectName).Credentials.template')">
|
||||
<MSBuildCommunityTasksPath>$(NuGetPackageRoot)msbuildtasks/1.5.0.235/tools/</MSBuildCommunityTasksPath>
|
||||
<MSBuildCommunityTasksPath>$(PkgMSBuildTasks)\tools\</MSBuildCommunityTasksPath>
|
||||
</PropertyGroup>
|
||||
|
||||
<Import Project="$(MSBuildCommunityTasksPath)MSBuild.Community.Tasks.Targets" Condition="Exists('$(ProjectDir)$(ProjectName).Credentials.template')" />
|
||||
<Import Project="$(MSBuildCommunityTasksPath)MSBuild.Community.Tasks.Targets" Condition="Exists('$(ProjectDir)$(ProjectName).Credentials.template')"/>
|
||||
|
||||
<Target Name="ProcessTemplates" BeforeTargets="PrepareForBuild" Condition="Exists('$(ProjectDir)$(ProjectName).Credentials.template')">
|
||||
<Message Text="Processing: $(ProjectDir)$(ProjectName).Credentials.template" Importance="high"/>
|
||||
|
||||
|
||||
<ReadLinesFromFile File="$(ProjectDir)$(ProjectName).Credentials.template">
|
||||
<Output TaskParameter="Lines" ItemName="TemplateLines" />
|
||||
</ReadLinesFromFile>
|
||||
|
||||
<ApplyTokenReplacements InputLines="@(TemplateLines)" Tokens="@(Tokens)">
|
||||
<Output TaskParameter="OutputLines" ItemName="ProcessedLines" />
|
||||
</ApplyTokenReplacements>
|
||||
|
||||
<WriteLinesToFile
|
||||
File="$(ProjectDir)$(ProjectName).Credentials.cs"
|
||||
Lines="@(ProcessedLines)"
|
||||
Overwrite="true" />
|
||||
<TemplateFile Template="$(ProjectDir)$(ProjectName).Credentials.template" OutputFilename="$(ProjectDir)$(ProjectName).Credentials.cs" Tokens="@(Tokens)" />
|
||||
</Target>
|
||||
</Project>
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -102,20 +102,6 @@ namespace Greenshot.Base.Controls
|
|||
/// </summary>
|
||||
protected bool ToFront { get; set; }
|
||||
|
||||
protected GreenshotForm()
|
||||
{
|
||||
DpiChanged += (sender, dpiChangedEventArgs) => DpiChangedHandler(dpiChangedEventArgs.DeviceDpiOld, dpiChangedEventArgs.DeviceDpiNew);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This is the basic DpiChangedHandler responsible for all the DPI relative changes
|
||||
/// </summary>
|
||||
/// <param name="oldDpi"></param>
|
||||
/// <param name="newDpi"></param>
|
||||
protected virtual void DpiChangedHandler(int oldDpi, int newDpi)
|
||||
{
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
/// <summary>
|
||||
/// Code to initialize the language etc during design time
|
||||
|
@ -364,7 +350,7 @@ namespace Greenshot.Base.Controls
|
|||
{
|
||||
if (!Language.TryGetString(languageKey, out langString))
|
||||
{
|
||||
LOG.DebugFormat("Unknown language key '{0}' configured for control '{1}', this might be okay.", languageKey, applyTo.Name);
|
||||
LOG.WarnFormat("Unknown language key '{0}' configured for control '{1}', this might be okay.", languageKey, applyTo.Name);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -396,10 +382,10 @@ namespace Greenshot.Base.Controls
|
|||
|
||||
protected void ApplyLanguage(Control applyTo)
|
||||
{
|
||||
if (applyTo is not IGreenshotLanguageBindable languageBindable)
|
||||
if (!(applyTo is IGreenshotLanguageBindable languageBindable))
|
||||
{
|
||||
// check if it's a menu!
|
||||
if (applyTo is not ToolStrip toolStrip)
|
||||
if (!(applyTo is ToolStrip toolStrip))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
@ -416,14 +402,20 @@ namespace Greenshot.Base.Controls
|
|||
ApplyLanguage(applyTo, languageBindable.LanguageKey);
|
||||
|
||||
// Repopulate the combox boxes
|
||||
if (applyTo is not (IGreenshotConfigBindable configBindable and GreenshotComboBox comboxBox)) return;
|
||||
if (string.IsNullOrEmpty(configBindable.SectionName) || string.IsNullOrEmpty(configBindable.PropertyName)) return;
|
||||
IniSection section = IniConfig.GetIniSection(configBindable.SectionName);
|
||||
if (section == null) return;
|
||||
// Only update the language, so get the actual value and than repopulate
|
||||
Enum currentValue = comboxBox.GetSelectedEnum();
|
||||
comboxBox.Populate(section.Values[configBindable.PropertyName].ValueType);
|
||||
comboxBox.SetValue(currentValue);
|
||||
if (applyTo is IGreenshotConfigBindable configBindable && applyTo is GreenshotComboBox comboxBox)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(configBindable.SectionName) && !string.IsNullOrEmpty(configBindable.PropertyName))
|
||||
{
|
||||
IniSection section = IniConfig.GetIniSection(configBindable.SectionName);
|
||||
if (section != null)
|
||||
{
|
||||
// Only update the language, so get the actual value and than repopulate
|
||||
Enum currentValue = comboxBox.GetSelectedEnum();
|
||||
comboxBox.Populate(section.Values[configBindable.PropertyName].ValueType);
|
||||
comboxBox.SetValue(currentValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -466,9 +458,10 @@ namespace Greenshot.Base.Controls
|
|||
continue;
|
||||
}
|
||||
|
||||
if (controlObject is not Control applyToControl)
|
||||
if (!(controlObject is Control applyToControl))
|
||||
{
|
||||
if (controlObject is not ToolStripItem applyToItem)
|
||||
ToolStripItem applyToItem = controlObject as ToolStripItem;
|
||||
if (applyToItem == null)
|
||||
{
|
||||
LOG.DebugFormat("No Control or ToolStripItem: {0}", field.Name);
|
||||
continue;
|
||||
|
@ -537,7 +530,7 @@ namespace Greenshot.Base.Controls
|
|||
/// <summary>
|
||||
/// Fill all GreenshotControls with the values from the configuration
|
||||
/// </summary>
|
||||
private void FillFields()
|
||||
protected void FillFields()
|
||||
{
|
||||
foreach (FieldInfo field in GetCachedFields(GetType()))
|
||||
{
|
||||
|
|
|
@ -120,7 +120,6 @@ namespace Greenshot.Base.Controls
|
|||
|
||||
private void PrepareFilterOptions()
|
||||
{
|
||||
// TODO: Change to the FileFormatHandlerRegistry to look for all the supported extensions
|
||||
OutputFormat[] supportedImageFormats = (OutputFormat[]) Enum.GetValues(typeof(OutputFormat));
|
||||
_filterOptions = new FilterOption[supportedImageFormats.Length];
|
||||
for (int i = 0; i < _filterOptions.Length; i++)
|
||||
|
@ -167,7 +166,7 @@ namespace Greenshot.Base.Controls
|
|||
// if the filename contains a valid extension, which is the same like the selected filter item's extension, the filename is okay
|
||||
if (fn.EndsWith(Extension, StringComparison.CurrentCultureIgnoreCase)) return fn;
|
||||
// otherwise we just add the selected filter item's extension
|
||||
return fn + "." + Extension;
|
||||
else return fn + "." + Extension;
|
||||
}
|
||||
set
|
||||
{
|
||||
|
|
|
@ -22,15 +22,12 @@
|
|||
using System;
|
||||
using System.Drawing;
|
||||
using System.Windows.Forms;
|
||||
using Dapplo.Windows.Common.Extensions;
|
||||
using Dapplo.Windows.Common.Structs;
|
||||
using Dapplo.Windows.DesktopWindowsManager;
|
||||
using Dapplo.Windows.DesktopWindowsManager.Structs;
|
||||
using Dapplo.Windows.User32;
|
||||
using Dapplo.Windows.User32.Enums;
|
||||
using Greenshot.Base.Core;
|
||||
using Greenshot.Base.Core.Enums;
|
||||
using Greenshot.Base.IniFile;
|
||||
using Greenshot.Base.UnmanagedHelpers;
|
||||
using Greenshot.Base.UnmanagedHelpers.Enums;
|
||||
using Greenshot.Base.UnmanagedHelpers.Structs;
|
||||
|
||||
namespace Greenshot.Base.Controls
|
||||
{
|
||||
|
@ -73,7 +70,7 @@ namespace Greenshot.Base.Controls
|
|||
{
|
||||
if (_thumbnailHandle == IntPtr.Zero) return;
|
||||
|
||||
DwmApi.DwmUnregisterThumbnail(_thumbnailHandle);
|
||||
DWM.DwmUnregisterThumbnail(_thumbnailHandle);
|
||||
_thumbnailHandle = IntPtr.Zero;
|
||||
}
|
||||
|
||||
|
@ -86,19 +83,19 @@ namespace Greenshot.Base.Controls
|
|||
{
|
||||
UnregisterThumbnail();
|
||||
|
||||
DwmApi.DwmRegisterThumbnail(Handle, window.Handle, out _thumbnailHandle);
|
||||
DWM.DwmRegisterThumbnail(Handle, window.Handle, out _thumbnailHandle);
|
||||
if (_thumbnailHandle == IntPtr.Zero) return;
|
||||
|
||||
var result = DwmApi.DwmQueryThumbnailSourceSize(_thumbnailHandle, out var sourceSize);
|
||||
var result = DWM.DwmQueryThumbnailSourceSize(_thumbnailHandle, out var sourceSize);
|
||||
if (result.Failed())
|
||||
{
|
||||
DwmApi.DwmUnregisterThumbnail(_thumbnailHandle);
|
||||
DWM.DwmUnregisterThumbnail(_thumbnailHandle);
|
||||
return;
|
||||
}
|
||||
|
||||
if (sourceSize.IsEmpty)
|
||||
{
|
||||
DwmApi.DwmUnregisterThumbnail(_thumbnailHandle);
|
||||
DWM.DwmUnregisterThumbnail(_thumbnailHandle);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -113,17 +110,17 @@ namespace Greenshot.Base.Controls
|
|||
Width = thumbnailWidth;
|
||||
Height = thumbnailHeight;
|
||||
// Prepare the displaying of the Thumbnail
|
||||
var dwmThumbnailProperties = new DwmThumbnailProperties()
|
||||
var dwmThumbnailProperties = new DWM_THUMBNAIL_PROPERTIES
|
||||
{
|
||||
Opacity = 255,
|
||||
Visible = true,
|
||||
SourceClientAreaOnly = false,
|
||||
Destination = new NativeRect(0, 0, thumbnailWidth, thumbnailHeight)
|
||||
Destination = new RECT(0, 0, thumbnailWidth, thumbnailHeight)
|
||||
};
|
||||
result = DwmApi.DwmUpdateThumbnailProperties(_thumbnailHandle, ref dwmThumbnailProperties);
|
||||
result = DWM.DwmUpdateThumbnailProperties(_thumbnailHandle, ref dwmThumbnailProperties);
|
||||
if (result.Failed())
|
||||
{
|
||||
DwmApi.DwmUnregisterThumbnail(_thumbnailHandle);
|
||||
DWM.DwmUnregisterThumbnail(_thumbnailHandle);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -140,13 +137,13 @@ namespace Greenshot.Base.Controls
|
|||
// Make sure it's on "top"!
|
||||
if (parentControl != null)
|
||||
{
|
||||
User32Api.SetWindowPos(Handle, parentControl.Handle, 0, 0, 0, 0, WindowPos.SWP_NOMOVE | WindowPos.SWP_NOSIZE | WindowPos.SWP_NOACTIVATE);
|
||||
User32.SetWindowPos(Handle, parentControl.Handle, 0, 0, 0, 0, WindowPos.SWP_NOMOVE | WindowPos.SWP_NOSIZE | WindowPos.SWP_NOACTIVATE);
|
||||
}
|
||||
}
|
||||
|
||||
public void AlignToControl(Control alignTo)
|
||||
{
|
||||
var screenBounds = DisplayInfo.ScreenBounds;
|
||||
var screenBounds = WindowCapture.GetScreenBounds();
|
||||
if (screenBounds.Contains(alignTo.Left, alignTo.Top - Height))
|
||||
{
|
||||
Location = new Point(alignTo.Left + (alignTo.Width / 2) - (Width / 2), alignTo.Top - Height);
|
||||
|
|
|
@ -24,18 +24,15 @@ using System.Collections.Generic;
|
|||
using System.Drawing;
|
||||
using System.Threading;
|
||||
using System.Windows.Forms;
|
||||
using Dapplo.Windows.Common.Extensions;
|
||||
using Dapplo.Windows.Common.Structs;
|
||||
using Dapplo.Windows.Dpi;
|
||||
using Dapplo.Windows.User32;
|
||||
using Greenshot.Base.IniFile;
|
||||
using Greenshot.Base.Interfaces;
|
||||
using Greenshot.Base.UnmanagedHelpers;
|
||||
using log4net;
|
||||
|
||||
namespace Greenshot.Base.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// The AbstractDestination is a default implementation of IDestination
|
||||
/// Description of AbstractDestination.
|
||||
/// </summary>
|
||||
public abstract class AbstractDestination : IDestination
|
||||
{
|
||||
|
@ -44,7 +41,7 @@ namespace Greenshot.Base.Core
|
|||
|
||||
public virtual int CompareTo(object obj)
|
||||
{
|
||||
if (obj is not IDestination other)
|
||||
if (!(obj is IDestination other))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
@ -179,7 +176,7 @@ namespace Greenshot.Base.Core
|
|||
ExportInformation exportInformation = new ExportInformation(Designation, Language.GetString("settings_destination_picker"));
|
||||
var menu = new ContextMenuStrip
|
||||
{
|
||||
ImageScalingSize = CoreConfig.IconSize,
|
||||
ImageScalingSize = CoreConfig.ScaledIconSize,
|
||||
Tag = null,
|
||||
TopLevel = true
|
||||
};
|
||||
|
@ -187,10 +184,10 @@ namespace Greenshot.Base.Core
|
|||
menu.Opening += (sender, args) =>
|
||||
{
|
||||
// find the DPI settings for the screen where this is going to land
|
||||
var screenDpi = NativeDpiMethods.GetDpi(menu.Location);
|
||||
var scaledIconSize = DpiCalculator.ScaleWithDpi(CoreConfig.IconSize, screenDpi);
|
||||
var screenDpi = DpiHelper.GetDpi(menu.Location);
|
||||
var scaledIconSize = DpiHelper.ScaleWithDpi(CoreConfig.IconSize, screenDpi);
|
||||
menu.SuspendLayout();
|
||||
var fontSize = DpiCalculator.ScaleWithDpi(12f, screenDpi);
|
||||
var fontSize = DpiHelper.ScaleWithDpi(12f, screenDpi);
|
||||
menu.Font = new Font(FontFamily.GenericSansSerif, fontSize, FontStyle.Regular, GraphicsUnit.Pixel);
|
||||
menu.ImageScalingSize = scaledIconSize;
|
||||
menu.ResumeLayout();
|
||||
|
@ -315,21 +312,21 @@ namespace Greenshot.Base.Core
|
|||
private static void ShowMenuAtCursor(ContextMenuStrip menu)
|
||||
{
|
||||
// find a suitable location
|
||||
NativePoint location = Cursor.Position;
|
||||
var menuRectangle = new NativeRect(location, menu.Size);
|
||||
Point location = Cursor.Position;
|
||||
Rectangle menuRectangle = new Rectangle(location, menu.Size);
|
||||
|
||||
menuRectangle = menuRectangle.Intersect(DisplayInfo.ScreenBounds);
|
||||
menuRectangle.Intersect(WindowCapture.GetScreenBounds());
|
||||
if (menuRectangle.Height < menu.Height)
|
||||
{
|
||||
location = location.Offset(-40, -(menuRectangle.Height - menu.Height));
|
||||
location.Offset(-40, -(menuRectangle.Height - menu.Height));
|
||||
}
|
||||
else
|
||||
{
|
||||
location = location.Offset(-40, -10);
|
||||
location.Offset(-40, -10);
|
||||
}
|
||||
|
||||
// This prevents the problem that the context menu shows in the task-bar
|
||||
User32Api.SetForegroundWindow(SimpleServiceProvider.Current.GetInstance<NotifyIcon>().ContextMenuStrip.Handle);
|
||||
User32.SetForegroundWindow(SimpleServiceProvider.Current.GetInstance<NotifyIcon>().ContextMenuStrip.Handle);
|
||||
menu.Show(location);
|
||||
menu.Focus();
|
||||
|
||||
|
|
|
@ -22,7 +22,6 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using Dapplo.Windows.Common.Structs;
|
||||
|
||||
namespace Greenshot.Base.Core
|
||||
{
|
||||
|
@ -281,19 +280,19 @@ namespace Greenshot.Base.Core
|
|||
/// <summary>
|
||||
/// Implementation of the RectangleAnimator
|
||||
/// </summary>
|
||||
public class RectangleAnimator : AnimatorBase<NativeRect>
|
||||
public class RectangleAnimator : AnimatorBase<Rectangle>
|
||||
{
|
||||
public RectangleAnimator(NativeRect first, NativeRect last, int frames)
|
||||
public RectangleAnimator(Rectangle first, Rectangle last, int frames)
|
||||
: base(first, last, frames, EasingType.Linear, EasingMode.EaseIn)
|
||||
{
|
||||
}
|
||||
|
||||
public RectangleAnimator(NativeRect first, NativeRect last, int frames, EasingType easingType)
|
||||
public RectangleAnimator(Rectangle first, Rectangle last, int frames, EasingType easingType)
|
||||
: base(first, last, frames, easingType, EasingMode.EaseIn)
|
||||
{
|
||||
}
|
||||
|
||||
public RectangleAnimator(NativeRect first, NativeRect last, int frames, EasingType easingType, EasingMode easingMode)
|
||||
public RectangleAnimator(Rectangle first, Rectangle last, int frames, EasingType easingType, EasingMode easingMode)
|
||||
: base(first, last, frames, easingType, easingMode)
|
||||
{
|
||||
}
|
||||
|
@ -301,8 +300,8 @@ namespace Greenshot.Base.Core
|
|||
/// <summary>
|
||||
/// Calculate the next frame object
|
||||
/// </summary>
|
||||
/// <returns>NativeRect</returns>
|
||||
public override NativeRect Next()
|
||||
/// <returns>Rectangle</returns>
|
||||
public override Rectangle Next()
|
||||
{
|
||||
if (!NextFrame)
|
||||
{
|
||||
|
@ -318,7 +317,7 @@ namespace Greenshot.Base.Core
|
|||
double dh = Last.Height - First.Height;
|
||||
int width = First.Width + (int) (easingValue * dw);
|
||||
int height = First.Height + (int) (easingValue * dh);
|
||||
Current = new NativeRect(x, y, width, height);
|
||||
Current = new Rectangle(x, y, width, height);
|
||||
|
||||
return Current;
|
||||
}
|
||||
|
@ -327,19 +326,19 @@ namespace Greenshot.Base.Core
|
|||
/// <summary>
|
||||
/// Implementation of the PointAnimator
|
||||
/// </summary>
|
||||
public class PointAnimator : AnimatorBase<NativePoint>
|
||||
public class PointAnimator : AnimatorBase<Point>
|
||||
{
|
||||
public PointAnimator(NativePoint first, NativePoint last, int frames)
|
||||
public PointAnimator(Point first, Point last, int frames)
|
||||
: base(first, last, frames, EasingType.Linear, EasingMode.EaseIn)
|
||||
{
|
||||
}
|
||||
|
||||
public PointAnimator(NativePoint first, NativePoint last, int frames, EasingType easingType)
|
||||
public PointAnimator(Point first, Point last, int frames, EasingType easingType)
|
||||
: base(first, last, frames, easingType, EasingMode.EaseIn)
|
||||
{
|
||||
}
|
||||
|
||||
public PointAnimator(NativePoint first, NativePoint last, int frames, EasingType easingType, EasingMode easingMode)
|
||||
public PointAnimator(Point first, Point last, int frames, EasingType easingType, EasingMode easingMode)
|
||||
: base(first, last, frames, easingType, easingMode)
|
||||
{
|
||||
}
|
||||
|
@ -348,7 +347,7 @@ namespace Greenshot.Base.Core
|
|||
/// Calculate the next frame value
|
||||
/// </summary>
|
||||
/// <returns>Point</returns>
|
||||
public override NativePoint Next()
|
||||
public override Point Next()
|
||||
{
|
||||
if (NextFrame)
|
||||
{
|
||||
|
@ -358,7 +357,7 @@ namespace Greenshot.Base.Core
|
|||
|
||||
int x = First.X + (int) (easingValue * dx);
|
||||
int y = First.Y + (int) (easingValue * dy);
|
||||
Current = new NativePoint(x, y);
|
||||
Current = new Point(x, y);
|
||||
}
|
||||
|
||||
return Current;
|
||||
|
@ -368,19 +367,19 @@ namespace Greenshot.Base.Core
|
|||
/// <summary>
|
||||
/// Implementation of the SizeAnimator
|
||||
/// </summary>
|
||||
public class SizeAnimator : AnimatorBase<NativeSize>
|
||||
public class SizeAnimator : AnimatorBase<Size>
|
||||
{
|
||||
public SizeAnimator(NativeSize first, NativeSize last, int frames)
|
||||
public SizeAnimator(Size first, Size last, int frames)
|
||||
: base(first, last, frames, EasingType.Linear, EasingMode.EaseIn)
|
||||
{
|
||||
}
|
||||
|
||||
public SizeAnimator(NativeSize first, NativeSize last, int frames, EasingType easingType)
|
||||
public SizeAnimator(Size first, Size last, int frames, EasingType easingType)
|
||||
: base(first, last, frames, easingType, EasingMode.EaseIn)
|
||||
{
|
||||
}
|
||||
|
||||
public SizeAnimator(NativeSize first, NativeSize last, int frames, EasingType easingType, EasingMode easingMode)
|
||||
public SizeAnimator(Size first, Size last, int frames, EasingType easingType, EasingMode easingMode)
|
||||
: base(first, last, frames, easingType, easingMode)
|
||||
{
|
||||
}
|
||||
|
@ -389,7 +388,7 @@ namespace Greenshot.Base.Core
|
|||
/// Calculate the next frame values
|
||||
/// </summary>
|
||||
/// <returns>Size</returns>
|
||||
public override NativeSize Next()
|
||||
public override Size Next()
|
||||
{
|
||||
if (NextFrame)
|
||||
{
|
||||
|
@ -398,7 +397,7 @@ namespace Greenshot.Base.Core
|
|||
double dh = Last.Height - First.Height;
|
||||
int width = First.Width + (int) (easingValue * dw);
|
||||
int height = First.Height + (int) (easingValue * dh);
|
||||
Current = new NativeSize(width, height);
|
||||
Current = new Size(width, height);
|
||||
}
|
||||
|
||||
return Current;
|
||||
|
|
|
@ -22,9 +22,6 @@
|
|||
using System;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using Dapplo.Windows.Common.Extensions;
|
||||
using Dapplo.Windows.Common.Structs;
|
||||
using Dapplo.Windows.User32;
|
||||
using Greenshot.Base.Interfaces;
|
||||
using Greenshot.Base.Interfaces.Ocr;
|
||||
using log4net;
|
||||
|
@ -39,18 +36,18 @@ namespace Greenshot.Base.Core
|
|||
{
|
||||
private static readonly ILog Log = LogManager.GetLogger(typeof(Capture));
|
||||
|
||||
private NativeRect _screenBounds;
|
||||
private Rectangle _screenBounds;
|
||||
|
||||
/// <summary>
|
||||
/// Get/Set the screen bounds
|
||||
/// </summary>
|
||||
public NativeRect ScreenBounds
|
||||
public Rectangle ScreenBounds
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_screenBounds.IsEmpty)
|
||||
if (_screenBounds == Rectangle.Empty)
|
||||
{
|
||||
_screenBounds = DisplayInfo.ScreenBounds;
|
||||
_screenBounds = WindowCapture.GetScreenBounds();
|
||||
}
|
||||
|
||||
return _screenBounds;
|
||||
|
@ -127,23 +124,23 @@ namespace Greenshot.Base.Core
|
|||
/// </summary>
|
||||
public bool CursorVisible { get; set; }
|
||||
|
||||
private NativePoint _cursorLocation = NativePoint.Empty;
|
||||
private Point _cursorLocation = Point.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Get/Set the CursorLocation
|
||||
/// </summary>
|
||||
public NativePoint CursorLocation
|
||||
public Point CursorLocation
|
||||
{
|
||||
get => _cursorLocation;
|
||||
set => _cursorLocation = value;
|
||||
}
|
||||
|
||||
private NativePoint _location = NativePoint.Empty;
|
||||
private Point _location = Point.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Get/set the Location
|
||||
/// </summary>
|
||||
public NativePoint Location
|
||||
public Point Location
|
||||
{
|
||||
get => _location;
|
||||
set => _location = value;
|
||||
|
@ -165,7 +162,7 @@ namespace Greenshot.Base.Core
|
|||
/// </summary>
|
||||
public Capture()
|
||||
{
|
||||
_screenBounds = DisplayInfo.ScreenBounds;
|
||||
_screenBounds = WindowCapture.GetScreenBounds();
|
||||
_captureDetails = new CaptureDetails();
|
||||
}
|
||||
|
||||
|
@ -217,8 +214,8 @@ namespace Greenshot.Base.Core
|
|||
/// <summary>
|
||||
/// Crops the capture to the specified rectangle (with Bitmap coordinates!)
|
||||
/// </summary>
|
||||
/// <param name="cropRectangle">NativeRect with bitmap coordinates</param>
|
||||
public bool Crop(NativeRect cropRectangle)
|
||||
/// <param name="cropRectangle">Rectangle with bitmap coordinates</param>
|
||||
public bool Crop(Rectangle cropRectangle)
|
||||
{
|
||||
Log.Debug("Cropping to: " + cropRectangle);
|
||||
if (!ImageHelper.Crop(ref _image, ref cropRectangle))
|
||||
|
@ -248,7 +245,7 @@ namespace Greenshot.Base.Core
|
|||
/// <param name="y">y coordinates to move the mouse</param>
|
||||
public void MoveMouseLocation(int x, int y)
|
||||
{
|
||||
_cursorLocation = _cursorLocation.Offset(x, y);
|
||||
_cursorLocation.Offset(x, y);
|
||||
}
|
||||
|
||||
// TODO: Enable when the elements are usable again.
|
||||
|
@ -264,7 +261,7 @@ namespace Greenshot.Base.Core
|
|||
|
||||
//private void MoveElements(List<ICaptureElement> listOfElements, int x, int y) {
|
||||
// foreach(ICaptureElement childElement in listOfElements) {
|
||||
// NativeRect bounds = childElement.Bounds;
|
||||
// Rectangle bounds = childElement.Bounds;
|
||||
// bounds.Offset(x, y);
|
||||
// childElement.Bounds = bounds;
|
||||
// MoveElements(childElement.Children, x, y);
|
||||
|
|
|
@ -20,16 +20,15 @@
|
|||
*/
|
||||
|
||||
using System.Drawing;
|
||||
using Dapplo.Windows.Common.Structs;
|
||||
|
||||
namespace Greenshot.Base.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// This is the method signature which is used to capture a rectangle from the screen.
|
||||
/// </summary>
|
||||
/// <param name="captureBounds">NativeRect</param>
|
||||
/// <param name="captureBounds"></param>
|
||||
/// <returns>Captured Bitmap</returns>
|
||||
public delegate Bitmap CaptureScreenRectangleHandler(NativeRect captureBounds);
|
||||
public delegate Bitmap CaptureScreenRectangleHandler(Rectangle captureBounds);
|
||||
|
||||
/// <summary>
|
||||
/// This is a hack to experiment with different screen capture routines
|
||||
|
|
|
@ -30,17 +30,11 @@ using System.Runtime.InteropServices;
|
|||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Windows.Forms;
|
||||
using Dapplo.Windows.Clipboard;
|
||||
using Dapplo.Windows.Common.Structs;
|
||||
using Dapplo.Windows.Gdi32.Enums;
|
||||
using Dapplo.Windows.Gdi32.Structs;
|
||||
using Dapplo.Windows.User32;
|
||||
using Greenshot.Base.Core.Enums;
|
||||
using Greenshot.Base.Core.FileFormatHandlers;
|
||||
using Greenshot.Base.IniFile;
|
||||
using Greenshot.Base.Interfaces;
|
||||
using Greenshot.Base.Interfaces.Drawing;
|
||||
using Greenshot.Base.Interfaces.Plugin;
|
||||
using Greenshot.Base.UnmanagedHelpers;
|
||||
using log4net;
|
||||
using HtmlDocument = HtmlAgilityPack.HtmlDocument;
|
||||
|
||||
|
@ -69,8 +63,7 @@ namespace Greenshot.Base.Core
|
|||
//private static readonly string FORMAT_HTML = "HTML Format";
|
||||
|
||||
// Template for the HTML Text on the clipboard
|
||||
// see: https://msdn.microsoft.com/en-us/library/ms649015%28v=v
|
||||
// s.85%29.aspx
|
||||
// see: https://msdn.microsoft.com/en-us/library/ms649015%28v=vs.85%29.aspx
|
||||
// or: https://msdn.microsoft.com/en-us/library/Aa767917.aspx
|
||||
private const string HtmlClipboardString = @"Version:0.9
|
||||
StartHTML:<<<<<<<1
|
||||
|
@ -119,12 +112,12 @@ EndSelection:<<<<<<<4
|
|||
string owner = null;
|
||||
try
|
||||
{
|
||||
IntPtr hWnd = ClipboardNative.CurrentOwner;
|
||||
IntPtr hWnd = User32.GetClipboardOwner();
|
||||
if (hWnd != IntPtr.Zero)
|
||||
{
|
||||
try
|
||||
{
|
||||
User32Api.GetWindowThreadProcessId(hWnd, out var pid);
|
||||
User32.GetWindowThreadProcessId(hWnd, out var pid);
|
||||
using Process me = Process.GetCurrentProcess();
|
||||
using Process ownerProcess = Process.GetProcessById(pid);
|
||||
// Exclude myself
|
||||
|
@ -146,7 +139,9 @@ EndSelection:<<<<<<<4
|
|||
catch (Exception e)
|
||||
{
|
||||
Log.Warn("Non critical error: Couldn't get clipboard process, trying to use the title.", e);
|
||||
owner = User32Api.GetText(hWnd);
|
||||
var title = new StringBuilder(260, 260);
|
||||
User32.GetWindowText(hWnd, title, title.Capacity);
|
||||
owner = title.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -284,9 +279,6 @@ EndSelection:<<<<<<<4
|
|||
{
|
||||
if (dataObject == null) return false;
|
||||
|
||||
IList<string> formats = GetFormats(dataObject);
|
||||
Log.DebugFormat("Found formats: {0}", string.Join(",", formats));
|
||||
|
||||
if (dataObject.GetDataPresent(DataFormats.Bitmap)
|
||||
|| dataObject.GetDataPresent(DataFormats.Dib)
|
||||
|| dataObject.GetDataPresent(DataFormats.Tiff)
|
||||
|
@ -306,15 +298,14 @@ EndSelection:<<<<<<<4
|
|||
{
|
||||
return true;
|
||||
}
|
||||
var fileFormatHandlers = SimpleServiceProvider.Current.GetAllInstances<IFileFormatHandler>();
|
||||
var supportedExtensions = fileFormatHandlers.ExtensionsFor(FileFormatHandlerActions.LoadDrawableFromStream).ToList();
|
||||
foreach (var (stream, filename) in IterateClipboardContent(dataObject))
|
||||
|
||||
foreach (var fileData in IterateClipboardContent(dataObject))
|
||||
{
|
||||
try
|
||||
{
|
||||
var extension = Path.GetExtension(filename)?.ToLowerInvariant();
|
||||
if (supportedExtensions.Contains(extension))
|
||||
using (ImageHelper.FromStream(fileData))
|
||||
{
|
||||
// If we get here, there is an image
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -324,7 +315,7 @@ EndSelection:<<<<<<<4
|
|||
}
|
||||
finally
|
||||
{
|
||||
stream?.Dispose();
|
||||
fileData?.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -336,8 +327,7 @@ EndSelection:<<<<<<<4
|
|||
var imageStream = clipboardContent as MemoryStream;
|
||||
if (IsValidStream(imageStream))
|
||||
{
|
||||
// TODO: How to check if we support "just a stream"?
|
||||
using (ImageIO.FromStream(imageStream))
|
||||
using (ImageHelper.FromStream(imageStream))
|
||||
{
|
||||
// If we get here, there is an image
|
||||
return true;
|
||||
|
@ -383,10 +373,9 @@ EndSelection:<<<<<<<4
|
|||
/// Iterate the clipboard content
|
||||
/// </summary>
|
||||
/// <param name="dataObject">IDataObject</param>
|
||||
/// <returns>IEnumerable{(MemoryStream,string)}</returns>
|
||||
private static IEnumerable<(MemoryStream stream,string filename)> IterateClipboardContent(IDataObject dataObject)
|
||||
/// <returns>IEnumerable{MemoryStream}</returns>
|
||||
private static IEnumerable<MemoryStream> IterateClipboardContent(IDataObject dataObject)
|
||||
{
|
||||
if (dataObject == null) yield break;
|
||||
var fileDescriptors = AvailableFileDescriptors(dataObject);
|
||||
if (fileDescriptors == null) yield break;
|
||||
|
||||
|
@ -424,8 +413,8 @@ EndSelection:<<<<<<<4
|
|||
/// </summary>
|
||||
/// <param name="fileDescriptors">IEnumerable{FileDescriptor}</param>
|
||||
/// <param name="dataObject">IDataObject</param>
|
||||
/// <returns>IEnumerable{(MemoryStream stream, string filename)}</returns>
|
||||
private static IEnumerable<(MemoryStream stream, string filename)> IterateFileDescriptors(IEnumerable<FileDescriptor> fileDescriptors, IDataObject dataObject)
|
||||
/// <returns>IEnumerable{MemoryStream}</returns>
|
||||
private static IEnumerable<MemoryStream> IterateFileDescriptors(IEnumerable<FileDescriptor> fileDescriptors, IDataObject dataObject)
|
||||
{
|
||||
if (fileDescriptors == null)
|
||||
{
|
||||
|
@ -456,7 +445,7 @@ EndSelection:<<<<<<<4
|
|||
if (fileData?.Length > 0)
|
||||
{
|
||||
fileData.Position = 0;
|
||||
yield return (fileData, fileDescriptor.FileName);
|
||||
yield return fileData;
|
||||
}
|
||||
|
||||
fileIndex++;
|
||||
|
@ -500,12 +489,8 @@ EndSelection:<<<<<<<4
|
|||
public static Image GetImage()
|
||||
{
|
||||
IDataObject clipboardData = GetDataObject();
|
||||
if (clipboardData == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
// Return the first image
|
||||
foreach (var clipboardImage in GetImages(clipboardData))
|
||||
foreach (Image clipboardImage in GetImages(clipboardData))
|
||||
{
|
||||
return clipboardImage;
|
||||
}
|
||||
|
@ -518,151 +503,56 @@ EndSelection:<<<<<<<4
|
|||
/// Returned images must be disposed by the calling code!
|
||||
/// </summary>
|
||||
/// <param name="dataObject"></param>
|
||||
/// <returns>IEnumerable of Bitmap</returns>
|
||||
public static IEnumerable<Bitmap> GetImages(IDataObject dataObject)
|
||||
/// <returns>IEnumerable of Image</returns>
|
||||
public static IEnumerable<Image> GetImages(IDataObject dataObject)
|
||||
{
|
||||
// Get single image, this takes the "best" match
|
||||
Bitmap singleImage = GetImage(dataObject);
|
||||
Image singleImage = GetImage(dataObject);
|
||||
if (singleImage != null)
|
||||
{
|
||||
Log.Info($"Got {singleImage.GetType()} from clipboard with size {singleImage.Size}");
|
||||
Log.InfoFormat("Got image from clipboard with size {0} and format {1}", singleImage.Size, singleImage.PixelFormat);
|
||||
yield return singleImage;
|
||||
yield break;
|
||||
}
|
||||
|
||||
var fileFormatHandlers = SimpleServiceProvider.Current.GetAllInstances<IFileFormatHandler>();
|
||||
var supportedExtensions = fileFormatHandlers.ExtensionsFor(FileFormatHandlerActions.LoadDrawableFromStream).ToList();
|
||||
|
||||
foreach (var (stream, filename) in IterateClipboardContent(dataObject))
|
||||
else
|
||||
{
|
||||
var extension = Path.GetExtension(filename)?.ToLowerInvariant();
|
||||
if (!supportedExtensions.Contains(extension))
|
||||
foreach (var fileData in IterateClipboardContent(dataObject))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
Bitmap bitmap = null;
|
||||
|
||||
try
|
||||
{
|
||||
if (!fileFormatHandlers.TryLoadFromStream(stream, extension, out bitmap))
|
||||
Image image;
|
||||
try
|
||||
{
|
||||
image = ImageHelper.FromStream(fileData);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error("Couldn't read file contents", ex);
|
||||
continue;
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error("Couldn't read file contents", ex);
|
||||
continue;
|
||||
}
|
||||
finally
|
||||
{
|
||||
stream?.Dispose();
|
||||
}
|
||||
// If we get here, there is an image
|
||||
yield return bitmap;
|
||||
}
|
||||
|
||||
// check if files are supplied
|
||||
foreach (string imageFile in GetImageFilenames(dataObject))
|
||||
{
|
||||
var extension = Path.GetExtension(imageFile)?.ToLowerInvariant();
|
||||
if (!supportedExtensions.Contains(extension))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
Bitmap bitmap = null;
|
||||
using FileStream fileStream = new FileStream(imageFile, FileMode.Open, FileAccess.Read, FileShare.Read);
|
||||
try
|
||||
{
|
||||
if (!fileFormatHandlers.TryLoadFromStream(fileStream, extension, out bitmap))
|
||||
finally
|
||||
{
|
||||
continue;
|
||||
fileData?.Dispose();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error("Couldn't read file contents", ex);
|
||||
continue;
|
||||
}
|
||||
// If we get here, there is an image
|
||||
yield return bitmap;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get all images (multiple if file names are available) from the dataObject
|
||||
/// Returned images must be disposed by the calling code!
|
||||
/// </summary>
|
||||
/// <param name="dataObject"></param>
|
||||
/// <returns>IEnumerable of IDrawableContainer</returns>
|
||||
public static IEnumerable<IDrawableContainer> GetDrawables(IDataObject dataObject)
|
||||
{
|
||||
// Get single image, this takes the "best" match
|
||||
IDrawableContainer singleImage = GetDrawable(dataObject);
|
||||
if (singleImage != null)
|
||||
{
|
||||
Log.InfoFormat($"Got {singleImage.GetType()} from clipboard with size {singleImage.Size}");
|
||||
yield return singleImage;
|
||||
yield break;
|
||||
}
|
||||
var fileFormatHandlers = SimpleServiceProvider.Current.GetAllInstances<IFileFormatHandler>();
|
||||
var supportedExtensions = fileFormatHandlers.ExtensionsFor(FileFormatHandlerActions.LoadDrawableFromStream).ToList();
|
||||
|
||||
foreach (var (stream, filename) in IterateClipboardContent(dataObject))
|
||||
{
|
||||
var extension = Path.GetExtension(filename)?.ToLowerInvariant();
|
||||
if (!supportedExtensions.Contains(extension))
|
||||
{
|
||||
continue;
|
||||
// If we get here, there is an image
|
||||
yield return image;
|
||||
}
|
||||
|
||||
IEnumerable<IDrawableContainer> drawableContainers;
|
||||
try
|
||||
// check if files are supplied
|
||||
foreach (string imageFile in GetImageFilenames(dataObject))
|
||||
{
|
||||
drawableContainers = fileFormatHandlers.LoadDrawablesFromStream(stream, extension);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error("Couldn't read file contents", ex);
|
||||
continue;
|
||||
}
|
||||
finally
|
||||
{
|
||||
stream?.Dispose();
|
||||
}
|
||||
// If we get here, there is an image
|
||||
foreach (var container in drawableContainers)
|
||||
{
|
||||
yield return container;
|
||||
}
|
||||
}
|
||||
Image returnImage = null;
|
||||
try
|
||||
{
|
||||
returnImage = ImageHelper.LoadImage(imageFile);
|
||||
}
|
||||
catch (Exception streamImageEx)
|
||||
{
|
||||
Log.Error("Problem retrieving Image from clipboard.", streamImageEx);
|
||||
}
|
||||
|
||||
// check if files are supplied
|
||||
foreach (string imageFile in GetImageFilenames(dataObject))
|
||||
{
|
||||
var extension = Path.GetExtension(imageFile)?.ToLowerInvariant();
|
||||
if (!supportedExtensions.Contains(extension))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
using FileStream fileStream = new FileStream(imageFile, FileMode.Open, FileAccess.Read, FileShare.Read);
|
||||
IEnumerable<IDrawableContainer> drawableContainers;
|
||||
try
|
||||
{
|
||||
drawableContainers = fileFormatHandlers.LoadDrawablesFromStream(fileStream, extension);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error("Couldn't read file contents", ex);
|
||||
continue;
|
||||
}
|
||||
// If we get here, there is an image
|
||||
foreach (var container in drawableContainers)
|
||||
{
|
||||
yield return container;
|
||||
if (returnImage != null)
|
||||
{
|
||||
Log.InfoFormat("Got image from clipboard with size {0} and format {1}", returnImage.Size, returnImage.PixelFormat);
|
||||
yield return returnImage;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -672,226 +562,201 @@ EndSelection:<<<<<<<4
|
|||
/// </summary>
|
||||
/// <param name="dataObject"></param>
|
||||
/// <returns>Image or null</returns>
|
||||
private static Bitmap GetImage(IDataObject dataObject)
|
||||
private static Image GetImage(IDataObject dataObject)
|
||||
{
|
||||
if (dataObject == null) return null;
|
||||
|
||||
Bitmap returnImage = null;
|
||||
IList<string> formats = GetFormats(dataObject);
|
||||
string[] retrieveFormats;
|
||||
|
||||
// Found a weird bug, where PNG's from Outlook 2010 are clipped
|
||||
// So I build some special logic to get the best format:
|
||||
if (formats != null && formats.Contains(FORMAT_PNG_OFFICEART) && formats.Contains(DataFormats.Dib))
|
||||
Image returnImage = null;
|
||||
if (dataObject != null)
|
||||
{
|
||||
// Outlook ??
|
||||
Log.Info("Most likely the current clipboard contents come from Outlook, as this has a problem with PNG and others we place the DIB format to the front...");
|
||||
retrieveFormats = new[]
|
||||
{
|
||||
DataFormats.Dib, FORMAT_BITMAP, FORMAT_FILECONTENTS, FORMAT_PNG_OFFICEART, FORMAT_PNG, FORMAT_JFIF_OFFICEART, FORMAT_JPG, FORMAT_JPEG, FORMAT_JFIF,
|
||||
DataFormats.Tiff, FORMAT_GIF, FORMAT_HTML
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
retrieveFormats = new[]
|
||||
{
|
||||
FORMAT_PNG_OFFICEART, FORMAT_PNG, FORMAT_17, FORMAT_JFIF_OFFICEART, FORMAT_JPG, FORMAT_JPEG, FORMAT_JFIF, DataFormats.Tiff, DataFormats.Dib, FORMAT_BITMAP,
|
||||
FORMAT_FILECONTENTS, FORMAT_GIF, FORMAT_HTML
|
||||
};
|
||||
}
|
||||
IList<string> formats = GetFormats(dataObject);
|
||||
string[] retrieveFormats;
|
||||
|
||||
foreach (string currentFormat in retrieveFormats)
|
||||
{
|
||||
if (formats != null && formats.Contains(currentFormat))
|
||||
// Found a weird bug, where PNG's from Outlook 2010 are clipped
|
||||
// So I build some special logic to get the best format:
|
||||
if (formats != null && formats.Contains(FORMAT_PNG_OFFICEART) && formats.Contains(DataFormats.Dib))
|
||||
{
|
||||
Log.InfoFormat("Found {0}, trying to retrieve.", currentFormat);
|
||||
returnImage = GetImageForFormat(currentFormat, dataObject);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.DebugFormat("Couldn't find format {0}.", currentFormat);
|
||||
}
|
||||
|
||||
if (returnImage != null)
|
||||
{
|
||||
return returnImage;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get an IDrawableContainer from the IDataObject, don't check for FileDrop
|
||||
/// </summary>
|
||||
/// <param name="dataObject"></param>
|
||||
/// <returns>Image or null</returns>
|
||||
private static IDrawableContainer GetDrawable(IDataObject dataObject)
|
||||
{
|
||||
if (dataObject == null) return null;
|
||||
|
||||
IDrawableContainer returnImage = null;
|
||||
IList<string> formats = GetFormats(dataObject);
|
||||
string[] retrieveFormats;
|
||||
|
||||
// Found a weird bug, where PNG's from Outlook 2010 are clipped
|
||||
// So I build some special logic to get the best format:
|
||||
if (formats != null && formats.Contains(FORMAT_PNG_OFFICEART) && formats.Contains(DataFormats.Dib))
|
||||
{
|
||||
// Outlook ??
|
||||
Log.Info("Most likely the current clipboard contents come from Outlook, as this has a problem with PNG and others we place the DIB format to the front...");
|
||||
retrieveFormats = new[]
|
||||
{
|
||||
DataFormats.Dib, FORMAT_BITMAP, FORMAT_FILECONTENTS, FORMAT_PNG_OFFICEART, FORMAT_PNG, FORMAT_JFIF_OFFICEART, FORMAT_JPG, FORMAT_JPEG, FORMAT_JFIF,
|
||||
DataFormats.Tiff, FORMAT_GIF, FORMAT_HTML
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
retrieveFormats = new[]
|
||||
{
|
||||
FORMAT_PNG_OFFICEART, FORMAT_PNG, FORMAT_17, FORMAT_JFIF_OFFICEART, FORMAT_JPG, FORMAT_JPEG, FORMAT_JFIF, DataFormats.Tiff, DataFormats.Dib, FORMAT_BITMAP,
|
||||
FORMAT_FILECONTENTS, FORMAT_GIF, FORMAT_HTML
|
||||
};
|
||||
}
|
||||
|
||||
foreach (string currentFormat in retrieveFormats)
|
||||
{
|
||||
if (formats != null && formats.Contains(currentFormat))
|
||||
{
|
||||
Log.InfoFormat("Found {0}, trying to retrieve.", currentFormat);
|
||||
returnImage = GetDrawableForFormat(currentFormat, dataObject);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.DebugFormat("Couldn't find format {0}.", currentFormat);
|
||||
}
|
||||
|
||||
if (returnImage != null)
|
||||
{
|
||||
return returnImage;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper method to try to get an Bitmap in the specified format from the dataObject
|
||||
/// the DIB reader should solve some issues
|
||||
/// It also supports Format17/DibV5, by using the following information: https://stackoverflow.com/a/14335591
|
||||
/// </summary>
|
||||
/// <param name="format">string with the format</param>
|
||||
/// <param name="dataObject">IDataObject</param>
|
||||
/// <returns>Bitmap or null</returns>
|
||||
private static Bitmap GetImageForFormat(string format, IDataObject dataObject)
|
||||
{
|
||||
Bitmap bitmap = null;
|
||||
|
||||
if (format == FORMAT_HTML)
|
||||
{
|
||||
var textObject = ContentAsString(dataObject, FORMAT_HTML, Encoding.UTF8);
|
||||
if (textObject != null)
|
||||
{
|
||||
var doc = new HtmlDocument();
|
||||
doc.LoadHtml(textObject);
|
||||
var imgNodes = doc.DocumentNode.SelectNodes("//img");
|
||||
if (imgNodes != null)
|
||||
// Outlook ??
|
||||
Log.Info("Most likely the current clipboard contents come from Outlook, as this has a problem with PNG and others we place the DIB format to the front...");
|
||||
retrieveFormats = new[]
|
||||
{
|
||||
foreach (var imgNode in imgNodes)
|
||||
{
|
||||
var srcAttribute = imgNode.Attributes["src"];
|
||||
var imageUrl = srcAttribute.Value;
|
||||
Log.Debug(imageUrl);
|
||||
bitmap = NetworkHelper.DownloadImage(imageUrl);
|
||||
if (bitmap != null)
|
||||
{
|
||||
return bitmap;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
object clipboardObject = GetFromDataObject(dataObject, format);
|
||||
var imageStream = clipboardObject as MemoryStream;
|
||||
if (!IsValidStream(imageStream))
|
||||
{
|
||||
return clipboardObject as Bitmap;
|
||||
}
|
||||
var fileFormatHandlers = SimpleServiceProvider.Current.GetAllInstances<IFileFormatHandler>();
|
||||
|
||||
// From here, imageStream is a valid stream
|
||||
if (fileFormatHandlers.TryLoadFromStream(imageStream, format, out bitmap))
|
||||
{
|
||||
return bitmap;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper method to try to get an IDrawableContainer in the specified format from the dataObject
|
||||
/// the DIB reader should solve some issues
|
||||
/// It also supports Format17/DibV5, by using the following information: https://stackoverflow.com/a/14335591
|
||||
/// </summary>
|
||||
/// <param name="format">string with the format</param>
|
||||
/// <param name="dataObject">IDataObject</param>
|
||||
/// <returns>IDrawableContainer or null</returns>
|
||||
private static IDrawableContainer GetDrawableForFormat(string format, IDataObject dataObject)
|
||||
{
|
||||
IDrawableContainer drawableContainer = null;
|
||||
|
||||
if (format == FORMAT_HTML)
|
||||
{
|
||||
var textObject = ContentAsString(dataObject, FORMAT_HTML, Encoding.UTF8);
|
||||
if (textObject != null)
|
||||
{
|
||||
var doc = new HtmlDocument();
|
||||
doc.LoadHtml(textObject);
|
||||
var imgNodes = doc.DocumentNode.SelectNodes("//img");
|
||||
if (imgNodes != null)
|
||||
{
|
||||
foreach (var imgNode in imgNodes)
|
||||
{
|
||||
var srcAttribute = imgNode.Attributes["src"];
|
||||
var imageUrl = srcAttribute.Value;
|
||||
Log.Debug(imageUrl);
|
||||
drawableContainer = NetworkHelper.DownloadImageAsDrawableContainer(imageUrl);
|
||||
if (drawableContainer != null)
|
||||
{
|
||||
return drawableContainer;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
object clipboardObject = GetFromDataObject(dataObject, format);
|
||||
var imageStream = clipboardObject as MemoryStream;
|
||||
if (!IsValidStream(imageStream))
|
||||
{
|
||||
// TODO: add text based, like "HTML Format" support here...
|
||||
// TODO: solve the issue that we do not have a factory for the ImageContainer
|
||||
/*var image = clipboardObject as Image;
|
||||
if (image != null)
|
||||
{
|
||||
return new ImageContainer(this)
|
||||
{
|
||||
Image = image,
|
||||
Left = x,
|
||||
Top = y
|
||||
DataFormats.Dib, FORMAT_BITMAP, FORMAT_FILECONTENTS, FORMAT_PNG_OFFICEART, FORMAT_PNG, FORMAT_JFIF_OFFICEART, FORMAT_JPG, FORMAT_JPEG, FORMAT_JFIF,
|
||||
DataFormats.Tiff, FORMAT_GIF, FORMAT_HTML
|
||||
};
|
||||
}
|
||||
return clipboardObject as Image;
|
||||
*/
|
||||
return null;
|
||||
else
|
||||
{
|
||||
retrieveFormats = new[]
|
||||
{
|
||||
FORMAT_PNG_OFFICEART, FORMAT_PNG, FORMAT_17, FORMAT_JFIF_OFFICEART, FORMAT_JPG, FORMAT_JPEG, FORMAT_JFIF, DataFormats.Tiff, DataFormats.Dib, FORMAT_BITMAP,
|
||||
FORMAT_FILECONTENTS, FORMAT_GIF, FORMAT_HTML
|
||||
};
|
||||
}
|
||||
|
||||
foreach (string currentFormat in retrieveFormats)
|
||||
{
|
||||
if (formats != null && formats.Contains(currentFormat))
|
||||
{
|
||||
Log.InfoFormat("Found {0}, trying to retrieve.", currentFormat);
|
||||
returnImage = GetImageForFormat(currentFormat, dataObject);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.DebugFormat("Couldn't find format {0}.", currentFormat);
|
||||
}
|
||||
|
||||
if (returnImage != null)
|
||||
{
|
||||
return returnImage;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// From here, imageStream is a valid stream
|
||||
var fileFormatHandlers = SimpleServiceProvider.Current.GetAllInstances<IFileFormatHandler>();
|
||||
return null;
|
||||
}
|
||||
|
||||
return fileFormatHandlers.LoadDrawablesFromStream(imageStream, format).FirstOrDefault();
|
||||
/// <summary>
|
||||
/// Helper method to try to get an image in the specified format from the dataObject
|
||||
/// the DIB reader should solve some issues
|
||||
/// It also supports Format17/DibV5, by using the following information: https://stackoverflow.com/a/14335591
|
||||
/// </summary>
|
||||
/// <param name="format">string with the format</param>
|
||||
/// <param name="dataObject">IDataObject</param>
|
||||
/// <returns>Image or null</returns>
|
||||
private static Image GetImageForFormat(string format, IDataObject dataObject)
|
||||
{
|
||||
if (format == FORMAT_HTML)
|
||||
{
|
||||
var textObject = ContentAsString(dataObject, FORMAT_HTML, Encoding.UTF8);
|
||||
if (textObject != null)
|
||||
{
|
||||
var doc = new HtmlDocument();
|
||||
doc.LoadHtml(textObject);
|
||||
var imgNodes = doc.DocumentNode.SelectNodes("//img");
|
||||
if (imgNodes != null)
|
||||
{
|
||||
foreach (var imgNode in imgNodes)
|
||||
{
|
||||
var srcAttribute = imgNode.Attributes["src"];
|
||||
var imageUrl = srcAttribute.Value;
|
||||
Log.Debug(imageUrl);
|
||||
var image = NetworkHelper.DownloadImage(imageUrl);
|
||||
if (image != null)
|
||||
{
|
||||
return image;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
object clipboardObject = GetFromDataObject(dataObject, format);
|
||||
var imageStream = clipboardObject as MemoryStream;
|
||||
if (!IsValidStream(imageStream))
|
||||
{
|
||||
// TODO: add "HTML Format" support here...
|
||||
return clipboardObject as Image;
|
||||
}
|
||||
|
||||
if (CoreConfig.EnableSpecialDIBClipboardReader)
|
||||
{
|
||||
if (format == FORMAT_17 || format == DataFormats.Dib)
|
||||
{
|
||||
Log.Info("Found DIB stream, trying to process it.");
|
||||
try
|
||||
{
|
||||
if (imageStream != null)
|
||||
{
|
||||
byte[] dibBuffer = new byte[imageStream.Length];
|
||||
_ = imageStream.Read(dibBuffer, 0, dibBuffer.Length);
|
||||
var infoHeader = BinaryStructHelper.FromByteArray<BITMAPINFOHEADERV5>(dibBuffer);
|
||||
if (!infoHeader.IsDibV5)
|
||||
{
|
||||
Log.InfoFormat("Using special DIB <v5 format reader with biCompression {0}", infoHeader.biCompression);
|
||||
int fileHeaderSize = Marshal.SizeOf(typeof(BITMAPFILEHEADER));
|
||||
uint infoHeaderSize = infoHeader.biSize;
|
||||
int fileSize = (int) (fileHeaderSize + infoHeader.biSize + infoHeader.biSizeImage);
|
||||
|
||||
var fileHeader = new BITMAPFILEHEADER
|
||||
{
|
||||
bfType = BITMAPFILEHEADER.BM,
|
||||
bfSize = fileSize,
|
||||
bfReserved1 = 0,
|
||||
bfReserved2 = 0,
|
||||
bfOffBits = (int) (fileHeaderSize + infoHeaderSize + infoHeader.biClrUsed * 4)
|
||||
};
|
||||
|
||||
byte[] fileHeaderBytes = BinaryStructHelper.ToByteArray(fileHeader);
|
||||
|
||||
using var bitmapStream = new MemoryStream();
|
||||
bitmapStream.Write(fileHeaderBytes, 0, fileHeaderSize);
|
||||
bitmapStream.Write(dibBuffer, 0, dibBuffer.Length);
|
||||
bitmapStream.Seek(0, SeekOrigin.Begin);
|
||||
var image = ImageHelper.FromStream(bitmapStream);
|
||||
if (image != null)
|
||||
{
|
||||
return image;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.Info("Using special DIBV5 / Format17 format reader");
|
||||
// CF_DIBV5
|
||||
IntPtr gcHandle = IntPtr.Zero;
|
||||
try
|
||||
{
|
||||
GCHandle handle = GCHandle.Alloc(dibBuffer, GCHandleType.Pinned);
|
||||
gcHandle = GCHandle.ToIntPtr(handle);
|
||||
return
|
||||
new Bitmap(infoHeader.biWidth, infoHeader.biHeight,
|
||||
-(int) (infoHeader.biSizeImage / infoHeader.biHeight),
|
||||
infoHeader.biBitCount == 32 ? PixelFormat.Format32bppArgb : PixelFormat.Format24bppRgb,
|
||||
new IntPtr(handle.AddrOfPinnedObject().ToInt32() + infoHeader.OffsetToPixels +
|
||||
(infoHeader.biHeight - 1) * (int) (infoHeader.biSizeImage / infoHeader.biHeight))
|
||||
);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error("Problem retrieving Format17 from clipboard.", ex);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (gcHandle == IntPtr.Zero)
|
||||
{
|
||||
GCHandle.FromIntPtr(gcHandle).Free();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception dibEx)
|
||||
{
|
||||
Log.Error("Problem retrieving DIB from clipboard.", dibEx);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.Info("Skipping special DIB format reader as it's disabled in the configuration.");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (imageStream != null)
|
||||
{
|
||||
imageStream.Seek(0, SeekOrigin.Begin);
|
||||
var tmpImage = ImageHelper.FromStream(imageStream);
|
||||
if (tmpImage != null)
|
||||
{
|
||||
Log.InfoFormat("Got image with clipboard format {0} from the clipboard.", format);
|
||||
return tmpImage;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception streamImageEx)
|
||||
{
|
||||
Log.Error($"Problem retrieving {format} from clipboard.", streamImageEx);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -975,7 +840,7 @@ EndSelection:<<<<<<<4
|
|||
{
|
||||
SurfaceOutputSettings outputSettings = new SurfaceOutputSettings(OutputFormat.png, 100, false);
|
||||
// Create the image which is going to be saved so we don't create it multiple times
|
||||
disposeImage = ImageIO.CreateImageFromSurface(surface, outputSettings, out imageToSave);
|
||||
disposeImage = ImageOutput.CreateImageFromSurface(surface, outputSettings, out imageToSave);
|
||||
try
|
||||
{
|
||||
// Create PNG stream
|
||||
|
@ -984,7 +849,7 @@ EndSelection:<<<<<<<4
|
|||
pngStream = new MemoryStream();
|
||||
// PNG works for e.g. Powerpoint
|
||||
SurfaceOutputSettings pngOutputSettings = new SurfaceOutputSettings(OutputFormat.png, 100, false);
|
||||
ImageIO.SaveToStream(imageToSave, null, pngStream, pngOutputSettings);
|
||||
ImageOutput.SaveToStream(imageToSave, null, pngStream, pngOutputSettings);
|
||||
pngStream.Seek(0, SeekOrigin.Begin);
|
||||
// Set the PNG stream
|
||||
dataObject.SetData(FORMAT_PNG, false, pngStream);
|
||||
|
@ -1001,18 +866,11 @@ EndSelection:<<<<<<<4
|
|||
{
|
||||
// Create the stream for the clipboard
|
||||
dibStream = new MemoryStream();
|
||||
var fileFormatHandlers = SimpleServiceProvider.Current.GetAllInstances<IFileFormatHandler>();
|
||||
var dibBytes = ((Bitmap)imageToSave).ConvertToDib();
|
||||
dibStream.Write(dibBytes,0, dibBytes.Length);
|
||||
|
||||
if (!fileFormatHandlers.TrySaveToStream((Bitmap)imageToSave, dibStream, DataFormats.Dib))
|
||||
{
|
||||
dibStream.Dispose();
|
||||
dibStream = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Set the DIB to the clipboard DataObject
|
||||
dataObject.SetData(DataFormats.Dib, false, dibStream);
|
||||
}
|
||||
// Set the DIB to the clipboard DataObject
|
||||
dataObject.SetData(DataFormats.Dib, false, dibStream);
|
||||
}
|
||||
}
|
||||
catch (Exception dibEx)
|
||||
|
@ -1029,17 +887,20 @@ EndSelection:<<<<<<<4
|
|||
dibV5Stream = new MemoryStream();
|
||||
|
||||
// Create the BITMAPINFOHEADER
|
||||
var header = BitmapV5Header.Create(imageToSave.Width, imageToSave.Height, 32);
|
||||
// Make sure we have BI_BITFIELDS, this seems to be normal for Format17?
|
||||
header.Compression = BitmapCompressionMethods.BI_BITFIELDS;
|
||||
var header = new BITMAPINFOHEADERV5(imageToSave.Width, imageToSave.Height, 32)
|
||||
{
|
||||
// Make sure we have BI_BITFIELDS, this seems to be normal for Format17?
|
||||
biCompression = BI_COMPRESSION.BI_BITFIELDS
|
||||
};
|
||||
// Create a byte[] to write
|
||||
byte[] headerBytes = BinaryStructHelper.ToByteArray(header);
|
||||
// Write the BITMAPINFOHEADER to the stream
|
||||
dibV5Stream.Write(headerBytes, 0, headerBytes.Length);
|
||||
|
||||
// As we have specified BI_COMPRESSION.BI_BITFIELDS, the BitfieldColorMask needs to be added
|
||||
// This also makes sure the default values are set
|
||||
BitfieldColorMask colorMask = new BitfieldColorMask();
|
||||
// Make sure the values are set
|
||||
colorMask.InitValues();
|
||||
// Create the byte[] from the struct
|
||||
byte[] colorMaskBytes = BinaryStructHelper.ToByteArray(colorMask);
|
||||
Array.Reverse(colorMaskBytes);
|
||||
|
@ -1063,7 +924,7 @@ EndSelection:<<<<<<<4
|
|||
// Set the HTML
|
||||
if (CoreConfig.ClipboardFormats.Contains(ClipboardFormat.HTML))
|
||||
{
|
||||
string tmpFile = ImageIO.SaveToTmpFile(surface, new SurfaceOutputSettings(OutputFormat.png, 100, false), null);
|
||||
string tmpFile = ImageOutput.SaveToTmpFile(surface, new SurfaceOutputSettings(OutputFormat.png, 100, false), null);
|
||||
string html = GetHtmlString(surface, tmpFile);
|
||||
dataObject.SetText(html, TextDataFormat.Html);
|
||||
}
|
||||
|
@ -1081,11 +942,11 @@ EndSelection:<<<<<<<4
|
|||
// Check if we can use the previously used image
|
||||
if (imageToSave.PixelFormat != PixelFormat.Format8bppIndexed)
|
||||
{
|
||||
ImageIO.SaveToStream(imageToSave, surface, tmpPngStream, pngOutputSettings);
|
||||
ImageOutput.SaveToStream(imageToSave, surface, tmpPngStream, pngOutputSettings);
|
||||
}
|
||||
else
|
||||
{
|
||||
ImageIO.SaveToStream(surface, tmpPngStream, pngOutputSettings);
|
||||
ImageOutput.SaveToStream(surface, tmpPngStream, pngOutputSettings);
|
||||
}
|
||||
|
||||
html = GetHtmlDataUrlString(surface, tmpPngStream);
|
||||
|
@ -1130,7 +991,7 @@ EndSelection:<<<<<<<4
|
|||
private static byte[] BitmapToByteArray(Bitmap bitmap)
|
||||
{
|
||||
// Lock the bitmap's bits.
|
||||
var rect = new NativeRect(0, 0, bitmap.Width, bitmap.Height);
|
||||
Rectangle rect = new Rectangle(0, 0, bitmap.Width, bitmap.Height);
|
||||
BitmapData bmpData = bitmap.LockBits(rect, ImageLockMode.ReadOnly, bitmap.PixelFormat);
|
||||
|
||||
int absStride = Math.Abs(bmpData.Stride);
|
||||
|
@ -1264,15 +1125,15 @@ EndSelection:<<<<<<<4
|
|||
public static IEnumerable<string> GetImageFilenames(IDataObject dataObject)
|
||||
{
|
||||
string[] dropFileNames = (string[])dataObject.GetData(DataFormats.FileDrop);
|
||||
if (dropFileNames is not { Length: > 0 }) return Enumerable.Empty<string>();
|
||||
var fileFormatHandlers = SimpleServiceProvider.Current.GetAllInstances<IFileFormatHandler>();
|
||||
|
||||
var supportedExtensions = fileFormatHandlers.ExtensionsFor(FileFormatHandlerActions.LoadFromStream).ToList();
|
||||
return dropFileNames
|
||||
.Where(filename => !string.IsNullOrEmpty(filename))
|
||||
.Where(Path.HasExtension)
|
||||
.Where(filename => supportedExtensions.Contains(Path.GetExtension(filename)));
|
||||
if (dropFileNames != null && dropFileNames.Length > 0)
|
||||
{
|
||||
return dropFileNames
|
||||
.Where(filename => !string.IsNullOrEmpty(filename))
|
||||
.Where(Path.HasExtension)
|
||||
.Where(filename => ImageHelper.StreamConverters.Keys.Contains(Path.GetExtension(filename).ToLowerInvariant().Substring(1)));
|
||||
}
|
||||
|
||||
return Enumerable.Empty<string>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -24,9 +24,9 @@ using System.Collections.Generic;
|
|||
using System.ComponentModel;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Windows.Forms;
|
||||
using Dapplo.Windows.Common.Structs;
|
||||
using Greenshot.Base.Core.Enums;
|
||||
using Greenshot.Base.IniFile;
|
||||
using Greenshot.Base.Interfaces;
|
||||
|
@ -59,7 +59,7 @@ namespace Greenshot.Base.Core
|
|||
[IniProperty("IEHotkey", Description = "Hotkey for starting the IE capture", DefaultValue = "Shift + Ctrl + PrintScreen")]
|
||||
public string IEHotkey { get; set; }
|
||||
|
||||
[IniProperty("ClipboardHotkey", Description = "Hotkey for opening the clipboard contents into the editor", ExcludeIfNull = true)]
|
||||
[IniProperty("ClipboardHotkey", Description = "Hotkey for opening the clipboard contents into the editor")]
|
||||
public string ClipboardHotkey { get; set; }
|
||||
|
||||
[IniProperty("IsFirstLaunch", Description = "Is this the first time launch?", DefaultValue = "true")]
|
||||
|
@ -322,17 +322,17 @@ namespace Greenshot.Base.Core
|
|||
public bool ProcessEXIFOrientation { get; set; }
|
||||
|
||||
[IniProperty("LastCapturedRegion", Description = "The last used region, for reuse in the capture last region")]
|
||||
public NativeRect LastCapturedRegion { get; set; }
|
||||
public Rectangle LastCapturedRegion { get; set; }
|
||||
|
||||
[IniProperty("Win10BorderCrop", Description = "The capture is cropped with these settings, e.g. when you don't want to color around it -1,-1"), DefaultValue("0,0")]
|
||||
public NativeSize Win10BorderCrop { get; set; }
|
||||
public Size Win10BorderCrop { get; set; }
|
||||
|
||||
private NativeSize _iconSize;
|
||||
private Size _iconSize;
|
||||
|
||||
[IniProperty("BaseIconSize",
|
||||
Description = "Defines the base size of the icons (e.g. for the buttons in the editor), default value 16,16 and it's scaled to the current DPI",
|
||||
DefaultValue = "16,16")]
|
||||
public NativeSize IconSize
|
||||
public Size IconSize
|
||||
{
|
||||
get { return _iconSize; }
|
||||
set
|
||||
|
@ -370,10 +370,12 @@ namespace Greenshot.Base.Core
|
|||
}
|
||||
}
|
||||
|
||||
[IniProperty("WebRequestTimeout", Description = "The connect timeout value for web requests, these are seconds", DefaultValue = "100")]
|
||||
public Size ScaledIconSize => DpiHelper.ScaleWithCurrentDpi(_iconSize);
|
||||
|
||||
[IniProperty("WebRequestTimeout", Description = "The connect timeout value for webrequets, these are seconds", DefaultValue = "100")]
|
||||
public int WebRequestTimeout { get; set; }
|
||||
|
||||
[IniProperty("WebRequestReadWriteTimeout", Description = "The read/write timeout value for web requests, these are seconds", DefaultValue = "100")]
|
||||
[IniProperty("WebRequestReadWriteTimeout", Description = "The read/write timeout value for webrequets, these are seconds", DefaultValue = "100")]
|
||||
public int WebRequestReadWriteTimeout { get; set; }
|
||||
|
||||
public bool UseLargeIcons => IconSize.Width >= 32 || IconSize.Height >= 32;
|
||||
|
@ -388,63 +390,88 @@ namespace Greenshot.Base.Core
|
|||
return ExperimentalFeatures != null && ExperimentalFeatures.Contains(experimentalFeature);
|
||||
}
|
||||
|
||||
private string CreateOutputFilePath()
|
||||
{
|
||||
if (IniConfig.IsPortable)
|
||||
{
|
||||
string pafOutputFilePath = Path.Combine(Application.StartupPath, @"..\..\Documents\Pictures\Greenshots");
|
||||
if (!Directory.Exists(pafOutputFilePath))
|
||||
{
|
||||
try
|
||||
{
|
||||
Directory.CreateDirectory(pafOutputFilePath);
|
||||
return pafOutputFilePath;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// Problem creating directory, fallback to Desktop
|
||||
LOG.Warn(ex);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return pafOutputFilePath;
|
||||
}
|
||||
}
|
||||
|
||||
return Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Supply values we can't put as defaults
|
||||
/// </summary>
|
||||
/// <param name="property">The property to return a default for</param>
|
||||
/// <returns>object with the default value for the supplied property</returns>
|
||||
public override object GetDefault(string property) =>
|
||||
property switch
|
||||
public override object GetDefault(string property)
|
||||
{
|
||||
switch (property)
|
||||
{
|
||||
nameof(ExcludePlugins) => new List<string>(),
|
||||
nameof(IncludePlugins) => new List<string>(),
|
||||
nameof(OutputFileAsFullpath) => IniConfig.IsPortable ? Path.Combine(Application.StartupPath, @"..\..\Documents\Pictures\Greenshots\dummy.png") : Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "dummy.png"),
|
||||
nameof(OutputFilePath) => CreateOutputFilePath(),
|
||||
nameof(DWMBackgroundColor) => Color.Transparent,
|
||||
nameof(ActiveTitleFixes) => new List<string> {
|
||||
"Firefox",
|
||||
"IE",
|
||||
"Chrome"
|
||||
},
|
||||
nameof(TitleFixMatcher) => new Dictionary<string, string> {
|
||||
{ "Firefox", " - Mozilla Firefox.*" },
|
||||
{ "IE", " - (Microsoft|Windows) Internet Explorer.*" },
|
||||
{ "Chrome", " - Google Chrome.*" }
|
||||
},
|
||||
nameof(TitleFixReplacer) => new Dictionary<string, string> {
|
||||
{ "Firefox", string.Empty },
|
||||
{ "IE", string.Empty },
|
||||
{ "Chrome", string.Empty }
|
||||
},
|
||||
_ => null
|
||||
};
|
||||
case nameof(ExcludePlugins):
|
||||
case nameof(IncludePlugins):
|
||||
return new List<string>();
|
||||
case nameof(OutputFileAsFullpath):
|
||||
if (IniConfig.IsPortable)
|
||||
{
|
||||
return Path.Combine(Application.StartupPath, @"..\..\Documents\Pictures\Greenshots\dummy.png");
|
||||
}
|
||||
|
||||
return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "dummy.png");
|
||||
case nameof(OutputFilePath):
|
||||
if (IniConfig.IsPortable)
|
||||
{
|
||||
string pafOutputFilePath = Path.Combine(Application.StartupPath, @"..\..\Documents\Pictures\Greenshots");
|
||||
if (!Directory.Exists(pafOutputFilePath))
|
||||
{
|
||||
try
|
||||
{
|
||||
Directory.CreateDirectory(pafOutputFilePath);
|
||||
return pafOutputFilePath;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LOG.Warn(ex);
|
||||
// Problem creating directory, fallback to Desktop
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return pafOutputFilePath;
|
||||
}
|
||||
}
|
||||
|
||||
return Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
|
||||
case nameof(DWMBackgroundColor):
|
||||
return Color.Transparent;
|
||||
case nameof(ActiveTitleFixes):
|
||||
return new List<string>
|
||||
{
|
||||
"Firefox",
|
||||
"IE",
|
||||
"Chrome"
|
||||
};
|
||||
case nameof(TitleFixMatcher):
|
||||
return new Dictionary<string, string>
|
||||
{
|
||||
{
|
||||
"Firefox", " - Mozilla Firefox.*"
|
||||
},
|
||||
{
|
||||
"IE", " - (Microsoft|Windows) Internet Explorer.*"
|
||||
},
|
||||
{
|
||||
"Chrome", " - Google Chrome.*"
|
||||
}
|
||||
};
|
||||
case nameof(TitleFixReplacer):
|
||||
return new Dictionary<string, string>
|
||||
{
|
||||
{
|
||||
"Firefox", string.Empty
|
||||
},
|
||||
{
|
||||
"IE", string.Empty
|
||||
},
|
||||
{
|
||||
"Chrome", string.Empty
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This method will be called before converting the property, making to possible to correct a certain value
|
||||
|
@ -515,9 +542,8 @@ namespace Greenshot.Base.Core
|
|||
OutputFileAutoReduceColors = false;
|
||||
}
|
||||
|
||||
bool isUpgradeFrom12 = LastSaveWithVersion?.StartsWith("1.2") ?? false;
|
||||
// Fix for excessive feed checking
|
||||
if (UpdateCheckInterval != 0 && UpdateCheckInterval <= 7 && isUpgradeFrom12)
|
||||
if (UpdateCheckInterval != 0 && UpdateCheckInterval <= 7 && LastSaveWithVersion.StartsWith("1.2"))
|
||||
{
|
||||
UpdateCheckInterval = 14;
|
||||
}
|
||||
|
|
134
src/Greenshot.Base/Core/DibHelper.cs
Normal file
134
src/Greenshot.Base/Core/DibHelper.cs
Normal file
|
@ -0,0 +1,134 @@
|
|||
/*
|
||||
* Greenshot - a free and open source screenshot tool
|
||||
* Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
|
||||
*
|
||||
* For more information see: https://getgreenshot.org/
|
||||
* The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using System.Runtime.InteropServices;
|
||||
using Greenshot.Base.UnmanagedHelpers;
|
||||
|
||||
namespace Greenshot.Base.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Though Greenshot implements the specs for the DIB image format,
|
||||
/// it seems to cause a lot of issues when using the clipboard.
|
||||
/// There is some research done about the DIB on the clipboard, this code is based upon the information
|
||||
/// <a href="https://stackoverflow.com/questions/44177115/copying-from-and-to-clipboard-loses-image-transparency">here</a>
|
||||
/// </summary>
|
||||
internal static class DibHelper
|
||||
{
|
||||
private const double DpiToPelsPerMeter = 39.3701;
|
||||
|
||||
/// <summary>
|
||||
/// Converts the Bitmap to a Device Independent Bitmap format of type BITFIELDS.
|
||||
/// </summary>
|
||||
/// <param name="sourceBitmap">Bitmap to convert to DIB</param>
|
||||
/// <returns>byte{} with the image converted to DIB</returns>
|
||||
public static byte[] ConvertToDib(this Bitmap sourceBitmap)
|
||||
{
|
||||
if (sourceBitmap == null) throw new ArgumentNullException(nameof(sourceBitmap));
|
||||
|
||||
var area = new Rectangle(0, 0, sourceBitmap.Width, sourceBitmap.Height);
|
||||
|
||||
// If the supplied format doesn't match 32bpp, we need to convert it first, and dispose the new bitmap afterwards
|
||||
bool needsDisposal = false;
|
||||
if (sourceBitmap.PixelFormat != PixelFormat.Format32bppArgb)
|
||||
{
|
||||
needsDisposal = true;
|
||||
var clonedImage = ImageHelper.CreateEmptyLike(sourceBitmap, Color.Transparent, PixelFormat.Format32bppArgb);
|
||||
using (var graphics = Graphics.FromImage(clonedImage))
|
||||
{
|
||||
graphics.DrawImage(sourceBitmap, area);
|
||||
}
|
||||
sourceBitmap = clonedImage;
|
||||
}
|
||||
|
||||
// All the pixels take this many bytes:
|
||||
var bitmapSize = 4 * sourceBitmap.Width * sourceBitmap.Height;
|
||||
// The bitmap info hear takes this many bytes:
|
||||
var bitmapInfoHeaderSize = Marshal.SizeOf(typeof(BITMAPINFOHEADER));
|
||||
// The bitmap info size is the header + 3 RGBQUADs
|
||||
var bitmapInfoSize = bitmapInfoHeaderSize + 3 * Marshal.SizeOf(typeof(RGBQUAD));
|
||||
|
||||
// Create a byte [] to contain the complete DIB (with .NET 5 and upwards, we could write the pixels directly to a stream)
|
||||
var fullBmpBytes = new byte[bitmapInfoSize + bitmapSize];
|
||||
// Get a span for this, this simplifies the code a bit
|
||||
var fullBmpSpan = fullBmpBytes.AsSpan();
|
||||
// Cast the span to be of type BITMAPINFOHEADER so we can assign values
|
||||
// TODO: in .NET 6 we could do a AsRef, and even write to a stream directly
|
||||
var bitmapInfoHeader = MemoryMarshal.Cast<byte, BITMAPINFOHEADER>(fullBmpSpan);
|
||||
|
||||
// Fill up the bitmap info header
|
||||
bitmapInfoHeader[0].biSize = (uint)bitmapInfoHeaderSize;
|
||||
bitmapInfoHeader[0].biWidth = sourceBitmap.Width;
|
||||
bitmapInfoHeader[0].biHeight = sourceBitmap.Height;
|
||||
bitmapInfoHeader[0].biPlanes = 1;
|
||||
bitmapInfoHeader[0].biBitCount = 32;
|
||||
bitmapInfoHeader[0].biCompression = BI_COMPRESSION.BI_BITFIELDS;
|
||||
bitmapInfoHeader[0].biSizeImage = (uint)bitmapSize;
|
||||
bitmapInfoHeader[0].biXPelsPerMeter = (int)(sourceBitmap.HorizontalResolution * DpiToPelsPerMeter);
|
||||
bitmapInfoHeader[0].biYPelsPerMeter = (int)(sourceBitmap.VerticalResolution * DpiToPelsPerMeter);
|
||||
|
||||
// Specify the color masks applied to the Int32 pixel value to get the R, G and B values.
|
||||
var rgbQuads = MemoryMarshal.Cast<byte, RGBQUAD>(fullBmpSpan.Slice(Marshal.SizeOf(typeof(BITMAPINFOHEADER))));
|
||||
rgbQuads[0].rgbRed = 255;
|
||||
rgbQuads[1].rgbGreen = 255;
|
||||
rgbQuads[2].rgbBlue = 255;
|
||||
|
||||
// Now copy the lines, in reverse (bmp is upside down) to the byte array
|
||||
var sourceBitmapData = sourceBitmap.LockBits(area, ImageLockMode.ReadOnly, sourceBitmap.PixelFormat);
|
||||
try
|
||||
{
|
||||
// Get a span for the real bitmap bytes, which starts after the bitmapinfo (header + 3xRGBQuad)
|
||||
var bitmapSpan = fullBmpSpan.Slice(bitmapInfoSize);
|
||||
// Make sure we also have a span to copy from, by taking the pointer from the locked bitmap
|
||||
Span<byte> bitmapSourceSpan;
|
||||
unsafe
|
||||
{
|
||||
bitmapSourceSpan = new Span<byte>(sourceBitmapData.Scan0.ToPointer(), sourceBitmapData.Stride * sourceBitmapData.Height);
|
||||
}
|
||||
|
||||
// Loop over all the bitmap lines
|
||||
for (int destinationY = 0; destinationY < sourceBitmap.Height; destinationY++)
|
||||
{
|
||||
// Calculate the y coordinate for the bottom up. (flipping the image)
|
||||
var sourceY = (sourceBitmap.Height - 1) - destinationY;
|
||||
// Make a Span for the source bitmap pixels
|
||||
var sourceLine = bitmapSourceSpan.Slice(sourceBitmapData.Stride * sourceY, 4 * sourceBitmap.Width);
|
||||
// Make a Span for the destination dib pixels
|
||||
var destinationLine = bitmapSpan.Slice(destinationY * 4 * sourceBitmap.Width);
|
||||
sourceLine.CopyTo(destinationLine);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
sourceBitmap.UnlockBits(sourceBitmapData);
|
||||
}
|
||||
|
||||
// If we created a new bitmap, we need to dispose this
|
||||
if (needsDisposal)
|
||||
{
|
||||
sourceBitmap.Dispose();
|
||||
}
|
||||
return fullBmpBytes;
|
||||
}
|
||||
}
|
||||
}
|
203
src/Greenshot.Base/Core/DpiHelper.cs
Normal file
203
src/Greenshot.Base/Core/DpiHelper.cs
Normal file
|
@ -0,0 +1,203 @@
|
|||
/*
|
||||
* Greenshot - a free and open source screenshot tool
|
||||
* Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
|
||||
*
|
||||
* For more information see: https://getgreenshot.org/
|
||||
* The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Runtime.InteropServices;
|
||||
using Greenshot.Base.Core.Enums;
|
||||
using Greenshot.Base.UnmanagedHelpers;
|
||||
using Greenshot.Base.UnmanagedHelpers.Enums;
|
||||
using Greenshot.Base.UnmanagedHelpers.Structs;
|
||||
|
||||
namespace Greenshot.Base.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// This handles DPI changes see
|
||||
/// <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/dn469266.aspx">Writing DPI-Aware Desktop and Win32 Applications</a>
|
||||
/// </summary>
|
||||
public static class DpiHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// This is the default DPI for the screen
|
||||
/// </summary>
|
||||
public const uint DefaultScreenDpi = 96;
|
||||
|
||||
/// <summary>
|
||||
/// Retrieve the current DPI for the UI element which is related to this DpiHandler
|
||||
/// </summary>
|
||||
public static uint Dpi { get; private set; } = WindowsVersion.IsWindows10OrLater ? GetDpiForSystem() : DefaultScreenDpi;
|
||||
|
||||
/// <summary>
|
||||
/// Calculate a DPI scale factor
|
||||
/// </summary>
|
||||
/// <param name="dpi">uint</param>
|
||||
/// <returns>double</returns>
|
||||
public static float DpiScaleFactor(uint dpi)
|
||||
{
|
||||
if (dpi == 0)
|
||||
{
|
||||
dpi = Dpi;
|
||||
}
|
||||
|
||||
return (float) dpi / DefaultScreenDpi;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Scale the supplied number according to the supplied dpi
|
||||
/// </summary>
|
||||
/// <param name="someNumber">double with e.g. the width 16 for 16x16 images</param>
|
||||
/// <param name="dpi">current dpi, normal is 96.</param>
|
||||
/// <param name="scaleModifier">A function which can modify the scale factor</param>
|
||||
/// <returns>double with the scaled number</returns>
|
||||
public static float ScaleWithDpi(float someNumber, uint dpi, Func<float, float> scaleModifier = null)
|
||||
{
|
||||
var dpiScaleFactor = DpiScaleFactor(dpi);
|
||||
if (scaleModifier != null)
|
||||
{
|
||||
dpiScaleFactor = scaleModifier(dpiScaleFactor);
|
||||
}
|
||||
|
||||
return dpiScaleFactor * someNumber;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Scale the supplied Size according to the supplied dpi
|
||||
/// </summary>
|
||||
/// <param name="size">Size to resize</param>
|
||||
/// <param name="dpi">current dpi, normal is 96.</param>
|
||||
/// <param name="scaleModifier">A function which can modify the scale factor</param>
|
||||
/// <returns>NativeSize scaled</returns>
|
||||
public static Size ScaleWithDpi(Size size, uint dpi, Func<float, float> scaleModifier = null)
|
||||
{
|
||||
var dpiScaleFactor = DpiScaleFactor(dpi);
|
||||
if (scaleModifier != null)
|
||||
{
|
||||
dpiScaleFactor = scaleModifier(dpiScaleFactor);
|
||||
}
|
||||
|
||||
return new Size((int) (dpiScaleFactor * size.Width), (int) (dpiScaleFactor * size.Height));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Scale the supplied NativeSize to the current dpi
|
||||
/// </summary>
|
||||
/// <param name="size">NativeSize to scale</param>
|
||||
/// <param name="scaleModifier">A function which can modify the scale factor</param>
|
||||
/// <returns>NativeSize scaled</returns>
|
||||
public static Size ScaleWithCurrentDpi(Size size, Func<float, float> scaleModifier = null)
|
||||
{
|
||||
return ScaleWithDpi(size, Dpi, scaleModifier);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return the DPI for the screen which the location is located on
|
||||
/// </summary>
|
||||
/// <param name="location">POINT</param>
|
||||
/// <returns>uint</returns>
|
||||
public static uint GetDpi(POINT location)
|
||||
{
|
||||
if (!WindowsVersion.IsWindows81OrLater)
|
||||
{
|
||||
return DefaultScreenDpi;
|
||||
}
|
||||
RECT rect = new RECT(location.X, location.Y, 1, 1);
|
||||
IntPtr hMonitor = User32.MonitorFromRect(ref rect, User32.MONITOR_DEFAULTTONEAREST);
|
||||
var result = GetDpiForMonitor(hMonitor, MonitorDpiType.EffectiveDpi, out var dpiX, out var dpiY);
|
||||
if (result.Succeeded())
|
||||
{
|
||||
return dpiX;
|
||||
}
|
||||
|
||||
return DefaultScreenDpi;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Retrieve the DPI value for the supplied window handle
|
||||
/// </summary>
|
||||
/// <param name="hWnd">IntPtr</param>
|
||||
/// <returns>dpi value</returns>
|
||||
public static uint GetDpi(IntPtr hWnd)
|
||||
{
|
||||
if (!User32.IsWindow(hWnd))
|
||||
{
|
||||
return DefaultScreenDpi;
|
||||
}
|
||||
|
||||
// Use the easiest method, but this only works for Windows 10
|
||||
if (WindowsVersion.IsWindows10OrLater)
|
||||
{
|
||||
return GetDpiForWindow(hWnd);
|
||||
}
|
||||
|
||||
// Use the second easiest method, but this only works for Windows 8.1 or later
|
||||
if (WindowsVersion.IsWindows81OrLater)
|
||||
{
|
||||
var hMonitor = User32.MonitorFromWindow(hWnd, MonitorFrom.DefaultToNearest);
|
||||
// ReSharper disable once UnusedVariable
|
||||
var result = GetDpiForMonitor(hMonitor, MonitorDpiType.EffectiveDpi, out var dpiX, out var dpiY);
|
||||
if (result.Succeeded())
|
||||
{
|
||||
return dpiX;
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback to the global DPI settings
|
||||
using var hdc = SafeWindowDcHandle.FromWindow(hWnd);
|
||||
if (hdc == null)
|
||||
{
|
||||
return DefaultScreenDpi;
|
||||
}
|
||||
|
||||
return (uint) GDI32.GetDeviceCaps(hdc, DeviceCaps.LOGPIXELSX);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// See more at <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/mt748624(v=vs.85).aspx">GetDpiForWindow function</a>
|
||||
/// Returns the dots per inch (dpi) value for the associated window.
|
||||
/// </summary>
|
||||
/// <param name="hWnd">IntPtr</param>
|
||||
/// <returns>uint with dpi</returns>
|
||||
[DllImport("user32.dll")]
|
||||
private static extern uint GetDpiForWindow(IntPtr hWnd);
|
||||
|
||||
/// <summary>
|
||||
/// See
|
||||
/// <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/dn280510(v=vs.85).aspx">GetDpiForMonitor function</a>
|
||||
/// Queries the dots per inch (dpi) of a display.
|
||||
/// </summary>
|
||||
/// <param name="hMonitor">IntPtr</param>
|
||||
/// <param name="dpiType">MonitorDpiType</param>
|
||||
/// <param name="dpiX">out int for the horizontal dpi</param>
|
||||
/// <param name="dpiY">out int for the vertical dpi</param>
|
||||
/// <returns>true if all okay</returns>
|
||||
[DllImport("shcore.dll", SetLastError = true)]
|
||||
private static extern HResult GetDpiForMonitor(IntPtr hMonitor, MonitorDpiType dpiType, out uint dpiX, out uint dpiY);
|
||||
|
||||
/// <summary>
|
||||
/// See <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/mt748623(v=vs.85).aspx">GetDpiForSystem function</a>
|
||||
/// Returns the system DPI.
|
||||
/// </summary>
|
||||
/// <returns>uint with the system DPI</returns>
|
||||
[DllImport("user32.dll")]
|
||||
private static extern uint GetDpiForSystem();
|
||||
}
|
||||
}
|
|
@ -3,8 +3,6 @@ using System.ComponentModel;
|
|||
using System.Drawing;
|
||||
using System.Globalization;
|
||||
using System.Text;
|
||||
using Dapplo.Windows.Common.Extensions;
|
||||
using Dapplo.Windows.Common.Structs;
|
||||
using Greenshot.Base.Effects;
|
||||
|
||||
namespace Greenshot.Base.Core
|
||||
|
@ -138,16 +136,16 @@ namespace Greenshot.Base.Core
|
|||
|
||||
break;
|
||||
case "ShadowOffset":
|
||||
NativePoint shadowOffset = new NativePoint();
|
||||
Point shadowOffset = new Point();
|
||||
string[] coordinates = pair[1].Split(',');
|
||||
if (int.TryParse(coordinates[0], out var shadowOffsetX))
|
||||
{
|
||||
shadowOffset = shadowOffset.ChangeX(shadowOffsetX);
|
||||
shadowOffset.X = shadowOffsetX;
|
||||
}
|
||||
|
||||
if (int.TryParse(coordinates[1], out var shadowOffsetY))
|
||||
{
|
||||
shadowOffset = shadowOffset.ChangeY(shadowOffsetY);
|
||||
shadowOffset.Y = shadowOffsetY;
|
||||
}
|
||||
|
||||
effect.ShadowOffset = shadowOffset;
|
||||
|
|
33
src/Greenshot.Base/Core/Enums/HResult.cs
Normal file
33
src/Greenshot.Base/Core/Enums/HResult.cs
Normal file
|
@ -0,0 +1,33 @@
|
|||
// Greenshot - a free and open source screenshot tool
|
||||
// Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
|
||||
//
|
||||
// For more information see: https://getgreenshot.org/
|
||||
// The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 1 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace Greenshot.Base.Core.Enums
|
||||
{
|
||||
/// <summary>
|
||||
/// The HRESULT represents Windows error codes
|
||||
/// See <a href="https://en.wikipedia.org/wiki/HRESULT">wikipedia</a>
|
||||
/// </summary>
|
||||
[SuppressMessage("ReSharper", "InconsistentNaming")]
|
||||
public enum HResult
|
||||
{
|
||||
S_OK = 0,
|
||||
}
|
||||
}
|
41
src/Greenshot.Base/Core/Enums/MonitorDpiType.cs
Normal file
41
src/Greenshot.Base/Core/Enums/MonitorDpiType.cs
Normal file
|
@ -0,0 +1,41 @@
|
|||
// Copyright (c) Dapplo and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System;
|
||||
|
||||
namespace Greenshot.Base.Core.Enums
|
||||
{
|
||||
/// <summary>
|
||||
/// See
|
||||
/// <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/dn280511(v=vs.85).aspx">
|
||||
/// MONITOR_DPI_TYPE
|
||||
/// enumeration
|
||||
/// </a>
|
||||
/// </summary>
|
||||
[Flags]
|
||||
public enum MonitorDpiType
|
||||
{
|
||||
/// <summary>
|
||||
/// The effective DPI.
|
||||
/// This value should be used when determining the correct scale factor for scaling UI elements.
|
||||
/// This incorporates the scale factor set by the user for this specific display.
|
||||
/// </summary>
|
||||
EffectiveDpi = 0,
|
||||
|
||||
/// <summary>
|
||||
/// The angular DPI.
|
||||
/// This DPI ensures rendering at a compliant angular resolution on the screen.
|
||||
/// This does not include the scale factor set by the user for this specific display
|
||||
/// </summary>
|
||||
AngularDpi = 1,
|
||||
|
||||
/// <summary>
|
||||
/// The raw DPI.
|
||||
/// This value is the linear DPI of the screen as measured on the screen itself.
|
||||
/// Use this value when you want to read the pixel density and not the recommended scaling setting.
|
||||
/// This does not include the scale factor set by the user for this specific display and is not guaranteed to be a
|
||||
/// supported DPI value.
|
||||
/// </summary>
|
||||
RawDpi = 2
|
||||
}
|
||||
}
|
31
src/Greenshot.Base/Core/Enums/MonitorFrom.cs
Normal file
31
src/Greenshot.Base/Core/Enums/MonitorFrom.cs
Normal file
|
@ -0,0 +1,31 @@
|
|||
// Copyright (c) Dapplo and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System;
|
||||
|
||||
namespace Greenshot.Base.Core.Enums
|
||||
{
|
||||
/// <summary>
|
||||
/// Flags for the MonitorFromRect / MonitorFromWindow "flags" field
|
||||
/// see <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/dd145063(v=vs.85).aspx">MonitorFromRect function</a>
|
||||
/// or see <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/dd145064(v=vs.85).aspx">MonitorFromWindow function</a>
|
||||
/// </summary>
|
||||
[Flags]
|
||||
public enum MonitorFrom : uint
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns a handle to the display monitor that is nearest to the rectangle.
|
||||
/// </summary>
|
||||
DefaultToNearest = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Returns NULL. (why??)
|
||||
/// </summary>
|
||||
DefaultToNull = 1,
|
||||
|
||||
/// <summary>
|
||||
/// Returns a handle to the primary display monitor.
|
||||
/// </summary>
|
||||
DefaultToPrimary = 2
|
||||
}
|
||||
}
|
|
@ -31,7 +31,6 @@ namespace Greenshot.Base.Core.Enums
|
|||
jpg,
|
||||
png,
|
||||
tiff,
|
||||
jxr,
|
||||
greenshot,
|
||||
ico
|
||||
}
|
||||
|
|
38
src/Greenshot.Base/Core/Enums/PrintWindowFlags.cs
Normal file
38
src/Greenshot.Base/Core/Enums/PrintWindowFlags.cs
Normal file
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Greenshot - a free and open source screenshot tool
|
||||
* Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
|
||||
*
|
||||
* For more information see: https://getgreenshot.org/
|
||||
* The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using System;
|
||||
|
||||
namespace Greenshot.Base.Core.Enums
|
||||
{
|
||||
[Flags]
|
||||
public enum PrintWindowFlags : uint
|
||||
{
|
||||
/// <summary>Render the entire window.</summary>
|
||||
PW_ENTIREWINDOW = 0,
|
||||
|
||||
/// <summary>Only the client area of the window is copied to hdcBlt. By default, the entire window is copied.</summary>
|
||||
PW_CLIENTONLY = 1,
|
||||
|
||||
/// <summary>Undocumented</summary>
|
||||
PW_RENDERFULLCONTENT = 0x00000002,
|
||||
}
|
||||
}
|
|
@ -23,12 +23,8 @@ using System;
|
|||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using Dapplo.Windows.Kernel32;
|
||||
using Dapplo.Windows.Kernel32.Enums;
|
||||
using Dapplo.Windows.Kernel32.Structs;
|
||||
using Dapplo.Windows.User32;
|
||||
using Dapplo.Windows.Common.Extensions;
|
||||
using Greenshot.Base.IniFile;
|
||||
using Greenshot.Base.UnmanagedHelpers;
|
||||
using Microsoft.Win32;
|
||||
|
||||
namespace Greenshot.Base.Core
|
||||
|
@ -167,7 +163,7 @@ namespace Greenshot.Base.Core
|
|||
}
|
||||
|
||||
// Get some important information for fixing GDI related Problems
|
||||
environment.AppendFormat("GDI object count: {0}", User32Api.GetGuiResourcesGdiCount());
|
||||
environment.AppendFormat("GDI object count: {0}", User32.GetGuiResourcesGDICount());
|
||||
if (newline)
|
||||
{
|
||||
environment.AppendLine();
|
||||
|
@ -177,7 +173,7 @@ namespace Greenshot.Base.Core
|
|||
environment.Append(", ");
|
||||
}
|
||||
|
||||
environment.AppendFormat("User object count: {0}", User32Api.GetGuiResourcesUserCount());
|
||||
environment.AppendFormat("User object count: {0}", User32.GetGuiResourcesUserCount());
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -295,33 +291,33 @@ namespace Greenshot.Base.Core
|
|||
string edition = string.Empty;
|
||||
|
||||
OperatingSystem osVersion = Environment.OSVersion;
|
||||
var osVersionInfo = OsVersionInfoEx.Create();
|
||||
OSVERSIONINFOEX osVersionInfo = OSVERSIONINFOEX.Create();
|
||||
|
||||
if (Kernel32Api.GetVersionEx(ref osVersionInfo))
|
||||
if (GetVersionEx(ref osVersionInfo))
|
||||
{
|
||||
int majorVersion = osVersion.Version.Major;
|
||||
int minorVersion = osVersion.Version.Minor;
|
||||
var productType = osVersionInfo.ProductType;
|
||||
var suiteMask = osVersionInfo.SuiteMask;
|
||||
byte productType = osVersionInfo.ProductType;
|
||||
ushort suiteMask = osVersionInfo.SuiteMask;
|
||||
|
||||
if (majorVersion == 4)
|
||||
{
|
||||
if (productType == WindowsProductTypes.VER_NT_WORKSTATION)
|
||||
if (productType == VER_NT_WORKSTATION)
|
||||
{
|
||||
// Windows NT 4.0 Workstation
|
||||
edition = "Workstation";
|
||||
}
|
||||
else if (productType == WindowsProductTypes.VER_NT_SERVER)
|
||||
else if (productType == VER_NT_SERVER)
|
||||
{
|
||||
edition = (suiteMask & WindowsSuites.Enterprise) != 0 ? "Enterprise Server" : "Standard Server";
|
||||
edition = (suiteMask & VER_SUITE_ENTERPRISE) != 0 ? "Enterprise Server" : "Standard Server";
|
||||
}
|
||||
}
|
||||
|
||||
else if (majorVersion == 5)
|
||||
{
|
||||
if (productType == WindowsProductTypes.VER_NT_WORKSTATION)
|
||||
if (productType == VER_NT_WORKSTATION)
|
||||
{
|
||||
if ((suiteMask & WindowsSuites.Personal) != 0)
|
||||
if ((suiteMask & VER_SUITE_PERSONAL) != 0)
|
||||
{
|
||||
// Windows XP Home Edition
|
||||
edition = "Home";
|
||||
|
@ -332,16 +328,16 @@ namespace Greenshot.Base.Core
|
|||
edition = "Professional";
|
||||
}
|
||||
}
|
||||
else if (productType == WindowsProductTypes.VER_NT_SERVER)
|
||||
else if (productType == VER_NT_SERVER)
|
||||
{
|
||||
if (minorVersion == 0)
|
||||
{
|
||||
if ((suiteMask & WindowsSuites.DataCenter) != 0)
|
||||
if ((suiteMask & VER_SUITE_DATACENTER) != 0)
|
||||
{
|
||||
// Windows 2000 Datacenter Server
|
||||
edition = "Datacenter Server";
|
||||
}
|
||||
else if ((suiteMask & WindowsSuites.Enterprise) != 0)
|
||||
else if ((suiteMask & VER_SUITE_ENTERPRISE) != 0)
|
||||
{
|
||||
// Windows 2000 Advanced Server
|
||||
edition = "Advanced Server";
|
||||
|
@ -354,17 +350,17 @@ namespace Greenshot.Base.Core
|
|||
}
|
||||
else
|
||||
{
|
||||
if ((suiteMask & WindowsSuites.DataCenter) != 0)
|
||||
if ((suiteMask & VER_SUITE_DATACENTER) != 0)
|
||||
{
|
||||
// Windows Server 2003 Datacenter Edition
|
||||
edition = "Datacenter";
|
||||
}
|
||||
else if ((suiteMask & WindowsSuites.Enterprise) != 0)
|
||||
else if ((suiteMask & VER_SUITE_ENTERPRISE) != 0)
|
||||
{
|
||||
// Windows Server 2003 Enterprise Edition
|
||||
edition = "Enterprise";
|
||||
}
|
||||
else if ((suiteMask & WindowsSuites.Blade) != 0)
|
||||
else if ((suiteMask & VER_SUITE_BLADE) != 0)
|
||||
{
|
||||
// Windows Server 2003 Web Edition
|
||||
edition = "Web Edition";
|
||||
|
@ -380,9 +376,122 @@ namespace Greenshot.Base.Core
|
|||
|
||||
else if (majorVersion == 6)
|
||||
{
|
||||
if (Kernel32Api.GetProductInfo(majorVersion, minorVersion, osVersionInfo.ServicePackMajor, osVersionInfo.ServicePackMinor, out var windowsProduct))
|
||||
if (GetProductInfo(majorVersion, minorVersion, osVersionInfo.ServicePackMajor, osVersionInfo.ServicePackMinor, out var ed))
|
||||
{
|
||||
edition = windowsProduct.GetEnumDescription();
|
||||
switch (ed)
|
||||
{
|
||||
case PRODUCT_BUSINESS:
|
||||
edition = "Business";
|
||||
break;
|
||||
case PRODUCT_BUSINESS_N:
|
||||
edition = "Business N";
|
||||
break;
|
||||
case PRODUCT_CLUSTER_SERVER:
|
||||
edition = "HPC Edition";
|
||||
break;
|
||||
case PRODUCT_DATACENTER_SERVER:
|
||||
edition = "Datacenter Server";
|
||||
break;
|
||||
case PRODUCT_DATACENTER_SERVER_CORE:
|
||||
edition = "Datacenter Server (core installation)";
|
||||
break;
|
||||
case PRODUCT_ENTERPRISE:
|
||||
edition = "Enterprise";
|
||||
break;
|
||||
case PRODUCT_ENTERPRISE_N:
|
||||
edition = "Enterprise N";
|
||||
break;
|
||||
case PRODUCT_ENTERPRISE_SERVER:
|
||||
edition = "Enterprise Server";
|
||||
break;
|
||||
case PRODUCT_ENTERPRISE_SERVER_CORE:
|
||||
edition = "Enterprise Server (core installation)";
|
||||
break;
|
||||
case PRODUCT_ENTERPRISE_SERVER_CORE_V:
|
||||
edition = "Enterprise Server without Hyper-V (core installation)";
|
||||
break;
|
||||
case PRODUCT_ENTERPRISE_SERVER_IA64:
|
||||
edition = "Enterprise Server for Itanium-based Systems";
|
||||
break;
|
||||
case PRODUCT_ENTERPRISE_SERVER_V:
|
||||
edition = "Enterprise Server without Hyper-V";
|
||||
break;
|
||||
case PRODUCT_HOME_BASIC:
|
||||
edition = "Home Basic";
|
||||
break;
|
||||
case PRODUCT_HOME_BASIC_N:
|
||||
edition = "Home Basic N";
|
||||
break;
|
||||
case PRODUCT_HOME_PREMIUM:
|
||||
edition = "Home Premium";
|
||||
break;
|
||||
case PRODUCT_HOME_PREMIUM_N:
|
||||
edition = "Home Premium N";
|
||||
break;
|
||||
case PRODUCT_HYPERV:
|
||||
edition = "Microsoft Hyper-V Server";
|
||||
break;
|
||||
case PRODUCT_MEDIUMBUSINESS_SERVER_MANAGEMENT:
|
||||
edition = "Windows Essential Business Management Server";
|
||||
break;
|
||||
case PRODUCT_MEDIUMBUSINESS_SERVER_MESSAGING:
|
||||
edition = "Windows Essential Business Messaging Server";
|
||||
break;
|
||||
case PRODUCT_MEDIUMBUSINESS_SERVER_SECURITY:
|
||||
edition = "Windows Essential Business Security Server";
|
||||
break;
|
||||
case PRODUCT_SERVER_FOR_SMALLBUSINESS:
|
||||
edition = "Windows Essential Server Solutions";
|
||||
break;
|
||||
case PRODUCT_SERVER_FOR_SMALLBUSINESS_V:
|
||||
edition = "Windows Essential Server Solutions without Hyper-V";
|
||||
break;
|
||||
case PRODUCT_SMALLBUSINESS_SERVER:
|
||||
edition = "Windows Small Business Server";
|
||||
break;
|
||||
case PRODUCT_STANDARD_SERVER:
|
||||
edition = "Standard Server";
|
||||
break;
|
||||
case PRODUCT_STANDARD_SERVER_CORE:
|
||||
edition = "Standard Server (core installation)";
|
||||
break;
|
||||
case PRODUCT_STANDARD_SERVER_CORE_V:
|
||||
edition = "Standard Server without Hyper-V (core installation)";
|
||||
break;
|
||||
case PRODUCT_STANDARD_SERVER_V:
|
||||
edition = "Standard Server without Hyper-V";
|
||||
break;
|
||||
case PRODUCT_STARTER:
|
||||
edition = "Starter";
|
||||
break;
|
||||
case PRODUCT_STORAGE_ENTERPRISE_SERVER:
|
||||
edition = "Enterprise Storage Server";
|
||||
break;
|
||||
case PRODUCT_STORAGE_EXPRESS_SERVER:
|
||||
edition = "Express Storage Server";
|
||||
break;
|
||||
case PRODUCT_STORAGE_STANDARD_SERVER:
|
||||
edition = "Standard Storage Server";
|
||||
break;
|
||||
case PRODUCT_STORAGE_WORKGROUP_SERVER:
|
||||
edition = "Workgroup Storage Server";
|
||||
break;
|
||||
case PRODUCT_UNDEFINED:
|
||||
edition = "Unknown product";
|
||||
break;
|
||||
case PRODUCT_ULTIMATE:
|
||||
edition = "Ultimate";
|
||||
break;
|
||||
case PRODUCT_ULTIMATE_N:
|
||||
edition = "Ultimate N";
|
||||
break;
|
||||
case PRODUCT_WEB_SERVER:
|
||||
edition = "Web Server";
|
||||
break;
|
||||
case PRODUCT_WEB_SERVER_CORE:
|
||||
edition = "Web Server (core installation)";
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -409,13 +518,13 @@ namespace Greenshot.Base.Core
|
|||
string name = "unknown";
|
||||
|
||||
OperatingSystem osVersion = Environment.OSVersion;
|
||||
var osVersionInfo = OsVersionInfoEx.Create();
|
||||
if (Kernel32Api.GetVersionEx(ref osVersionInfo))
|
||||
OSVERSIONINFOEX osVersionInfo = OSVERSIONINFOEX.Create();
|
||||
if (GetVersionEx(ref osVersionInfo))
|
||||
{
|
||||
int majorVersion = osVersion.Version.Major;
|
||||
int minorVersion = osVersion.Version.Minor;
|
||||
var productType = osVersionInfo.ProductType;
|
||||
var suiteMask = osVersionInfo.SuiteMask;
|
||||
byte productType = osVersionInfo.ProductType;
|
||||
ushort suiteMask = osVersionInfo.SuiteMask;
|
||||
switch (osVersion.Platform)
|
||||
{
|
||||
case PlatformID.Win32Windows:
|
||||
|
@ -454,10 +563,10 @@ namespace Greenshot.Base.Core
|
|||
case 4:
|
||||
switch (productType)
|
||||
{
|
||||
case WindowsProductTypes.VER_NT_WORKSTATION:
|
||||
case 1:
|
||||
name = "Windows NT 4.0";
|
||||
break;
|
||||
case WindowsProductTypes.VER_NT_SERVER:
|
||||
case 3:
|
||||
name = "Windows NT 4.0 Server";
|
||||
break;
|
||||
}
|
||||
|
@ -472,18 +581,18 @@ namespace Greenshot.Base.Core
|
|||
case 1:
|
||||
name = suiteMask switch
|
||||
{
|
||||
WindowsSuites.Personal => "Windows XP Professional",
|
||||
0x0200 => "Windows XP Professional",
|
||||
_ => "Windows XP"
|
||||
};
|
||||
break;
|
||||
case 2:
|
||||
name = suiteMask switch
|
||||
{
|
||||
WindowsSuites.Personal => "Windows XP Professional x64",
|
||||
WindowsSuites.Enterprise => "Windows Server 2003 Enterprise",
|
||||
WindowsSuites.DataCenter => "Windows Server 2003 Data Center",
|
||||
WindowsSuites.Blade => "Windows Server 2003 Web Edition",
|
||||
WindowsSuites.WHServer => "Windows Home Server",
|
||||
0x0200 => "Windows XP Professional x64",
|
||||
0x0002 => "Windows Server 2003 Enterprise",
|
||||
0x0080 => "Windows Server 2003 Data Center",
|
||||
0x0400 => "Windows Server 2003 Web Edition",
|
||||
0x8000 => "Windows Home Server",
|
||||
_ => "Windows Server 2003"
|
||||
};
|
||||
break;
|
||||
|
@ -496,14 +605,14 @@ namespace Greenshot.Base.Core
|
|||
case 0:
|
||||
name = productType switch
|
||||
{
|
||||
WindowsProductTypes.VER_NT_SERVER => "Windows Server 2008",
|
||||
3 => "Windows Server 2008",
|
||||
_ => "Windows Vista"
|
||||
};
|
||||
break;
|
||||
case 1:
|
||||
name = productType switch
|
||||
{
|
||||
WindowsProductTypes.VER_NT_SERVER => "Windows Server 2008 R2",
|
||||
3 => "Windows Server 2008 R2",
|
||||
_ => "Windows 7"
|
||||
};
|
||||
break;
|
||||
|
@ -531,6 +640,134 @@ namespace Greenshot.Base.Core
|
|||
}
|
||||
}
|
||||
|
||||
[DllImport("Kernel32.dll")]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
internal static extern bool GetProductInfo(
|
||||
int osMajorVersion,
|
||||
int osMinorVersion,
|
||||
int spMajorVersion,
|
||||
int spMinorVersion,
|
||||
out int edition);
|
||||
|
||||
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
private static extern bool GetVersionEx(ref OSVERSIONINFOEX osVersionInfo);
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
|
||||
private unsafe struct OSVERSIONINFOEX
|
||||
{
|
||||
/// <summary>
|
||||
/// The size of this data structure, in bytes. Set this member to sizeof(OSVERSIONINFOEX).
|
||||
/// </summary>
|
||||
private int _dwOSVersionInfoSize;
|
||||
|
||||
private readonly int _dwMajorVersion;
|
||||
private readonly int _dwMinorVersion;
|
||||
private readonly int _dwBuildNumber;
|
||||
private readonly int _dwPlatformId;
|
||||
private fixed char _szCSDVersion[128];
|
||||
private readonly short _wServicePackMajor;
|
||||
private readonly short _wServicePackMinor;
|
||||
private readonly ushort _wSuiteMask;
|
||||
private readonly byte _wProductType;
|
||||
private readonly byte _wReserved;
|
||||
|
||||
/// A null-terminated string, such as "Service Pack 3", that indicates the latest Service Pack installed on the system.
|
||||
/// If no Service Pack has been installed, the string is empty.
|
||||
/// </summary>
|
||||
public string ServicePackVersion
|
||||
{
|
||||
get
|
||||
{
|
||||
fixed (char* servicePackVersion = _szCSDVersion)
|
||||
{
|
||||
return new string(servicePackVersion);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The major version number of the latest Service Pack installed on the system. For example, for Service Pack 3, the
|
||||
/// major version number is 3.
|
||||
/// If no Service Pack has been installed, the value is zero.
|
||||
/// </summary>
|
||||
public short ServicePackMajor => _wServicePackMajor;
|
||||
|
||||
/// <summary>
|
||||
/// The minor version number of the latest Service Pack installed on the system. For example, for Service Pack 3, the
|
||||
/// minor version number is 0.
|
||||
/// </summary>
|
||||
public short ServicePackMinor => _wServicePackMinor;
|
||||
|
||||
/// <summary>
|
||||
/// A bit mask that identifies the product suites available on the system. This member can be a combination of the
|
||||
/// following values.
|
||||
/// </summary>
|
||||
public ushort SuiteMask => _wSuiteMask;
|
||||
|
||||
/// <summary>
|
||||
/// Any additional information about the system.
|
||||
/// </summary>
|
||||
public byte ProductType => _wProductType;
|
||||
|
||||
/// <summary>
|
||||
/// Factory for an empty OsVersionInfoEx
|
||||
/// </summary>
|
||||
/// <returns>OSVERSIONINFOEX</returns>
|
||||
public static OSVERSIONINFOEX Create()
|
||||
{
|
||||
return new OSVERSIONINFOEX
|
||||
{
|
||||
_dwOSVersionInfoSize = Marshal.SizeOf(typeof(OSVERSIONINFOEX))
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private const int PRODUCT_UNDEFINED = 0x00000000;
|
||||
private const int PRODUCT_ULTIMATE = 0x00000001;
|
||||
private const int PRODUCT_HOME_BASIC = 0x00000002;
|
||||
private const int PRODUCT_HOME_PREMIUM = 0x00000003;
|
||||
private const int PRODUCT_ENTERPRISE = 0x00000004;
|
||||
private const int PRODUCT_HOME_BASIC_N = 0x00000005;
|
||||
private const int PRODUCT_BUSINESS = 0x00000006;
|
||||
private const int PRODUCT_STANDARD_SERVER = 0x00000007;
|
||||
private const int PRODUCT_DATACENTER_SERVER = 0x00000008;
|
||||
private const int PRODUCT_SMALLBUSINESS_SERVER = 0x00000009;
|
||||
private const int PRODUCT_ENTERPRISE_SERVER = 0x0000000A;
|
||||
private const int PRODUCT_STARTER = 0x0000000B;
|
||||
private const int PRODUCT_DATACENTER_SERVER_CORE = 0x0000000C;
|
||||
private const int PRODUCT_STANDARD_SERVER_CORE = 0x0000000D;
|
||||
private const int PRODUCT_ENTERPRISE_SERVER_CORE = 0x0000000E;
|
||||
private const int PRODUCT_ENTERPRISE_SERVER_IA64 = 0x0000000F;
|
||||
private const int PRODUCT_BUSINESS_N = 0x00000010;
|
||||
private const int PRODUCT_WEB_SERVER = 0x00000011;
|
||||
private const int PRODUCT_CLUSTER_SERVER = 0x00000012;
|
||||
private const int PRODUCT_STORAGE_EXPRESS_SERVER = 0x00000014;
|
||||
private const int PRODUCT_STORAGE_STANDARD_SERVER = 0x00000015;
|
||||
private const int PRODUCT_STORAGE_WORKGROUP_SERVER = 0x00000016;
|
||||
private const int PRODUCT_STORAGE_ENTERPRISE_SERVER = 0x00000017;
|
||||
private const int PRODUCT_SERVER_FOR_SMALLBUSINESS = 0x00000018;
|
||||
private const int PRODUCT_HOME_PREMIUM_N = 0x0000001A;
|
||||
private const int PRODUCT_ENTERPRISE_N = 0x0000001B;
|
||||
private const int PRODUCT_ULTIMATE_N = 0x0000001C;
|
||||
private const int PRODUCT_WEB_SERVER_CORE = 0x0000001D;
|
||||
private const int PRODUCT_MEDIUMBUSINESS_SERVER_MANAGEMENT = 0x0000001E;
|
||||
private const int PRODUCT_MEDIUMBUSINESS_SERVER_SECURITY = 0x0000001F;
|
||||
private const int PRODUCT_MEDIUMBUSINESS_SERVER_MESSAGING = 0x00000020;
|
||||
private const int PRODUCT_SERVER_FOR_SMALLBUSINESS_V = 0x00000023;
|
||||
private const int PRODUCT_STANDARD_SERVER_V = 0x00000024;
|
||||
private const int PRODUCT_ENTERPRISE_SERVER_V = 0x00000026;
|
||||
private const int PRODUCT_STANDARD_SERVER_CORE_V = 0x00000028;
|
||||
private const int PRODUCT_ENTERPRISE_SERVER_CORE_V = 0x00000029;
|
||||
private const int PRODUCT_HYPERV = 0x0000002A;
|
||||
|
||||
private const int VER_NT_WORKSTATION = 1;
|
||||
private const int VER_NT_SERVER = 3;
|
||||
private const int VER_SUITE_ENTERPRISE = 2;
|
||||
private const int VER_SUITE_DATACENTER = 128;
|
||||
private const int VER_SUITE_PERSONAL = 512;
|
||||
private const int VER_SUITE_BLADE = 1024;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the service pack information of the operating system running on this computer.
|
||||
/// </summary>
|
||||
|
@ -539,9 +776,9 @@ namespace Greenshot.Base.Core
|
|||
get
|
||||
{
|
||||
string servicePack = string.Empty;
|
||||
OsVersionInfoEx osVersionInfo = OsVersionInfoEx.Create();
|
||||
OSVERSIONINFOEX osVersionInfo = OSVERSIONINFOEX.Create();
|
||||
|
||||
if (Kernel32Api.GetVersionEx(ref osVersionInfo))
|
||||
if (GetVersionEx(ref osVersionInfo))
|
||||
{
|
||||
servicePack = osVersionInfo.ServicePackVersion;
|
||||
}
|
||||
|
@ -550,7 +787,6 @@ namespace Greenshot.Base.Core
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the full version string of the operating system running on this computer.
|
||||
/// </summary>
|
||||
public static string VersionString
|
||||
|
|
|
@ -23,8 +23,6 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using Dapplo.Windows.Common.Extensions;
|
||||
using Dapplo.Windows.Common.Structs;
|
||||
|
||||
namespace Greenshot.Base.Core
|
||||
{
|
||||
|
@ -86,7 +84,7 @@ namespace Greenshot.Base.Core
|
|||
/// <summary>
|
||||
/// Size of the underlying image
|
||||
/// </summary>
|
||||
NativeSize Size { get; }
|
||||
Size Size { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Height of the image area that this fastbitmap covers
|
||||
|
@ -129,19 +127,19 @@ namespace Greenshot.Base.Core
|
|||
bool HasAlphaChannel { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Draw the stored bitmap to the destination bitmap at the supplied point
|
||||
/// Draw the stored bitmap to the destionation bitmap at the supplied point
|
||||
/// </summary>
|
||||
/// <param name="graphics">Graphics</param>
|
||||
/// <param name="destination">NativePoint with location</param>
|
||||
void DrawTo(Graphics graphics, NativePoint destination);
|
||||
/// <param name="destination">Point with location</param>
|
||||
void DrawTo(Graphics graphics, Point destination);
|
||||
|
||||
/// <summary>
|
||||
/// Draw the stored Bitmap on the Destination bitmap with the specified rectangle
|
||||
/// Be aware that the stored bitmap will be resized to the specified rectangle!!
|
||||
/// </summary>
|
||||
/// <param name="graphics">Graphics</param>
|
||||
/// <param name="destinationRect">NativeRect with destination</param>
|
||||
void DrawTo(Graphics graphics, NativeRect destinationRect);
|
||||
/// <param name="destinationRect">Rectangle with destination</param>
|
||||
void DrawTo(Graphics graphics, Rectangle destinationRect);
|
||||
|
||||
/// <summary>
|
||||
/// Return true if the coordinates are inside the FastBitmap
|
||||
|
@ -216,7 +214,7 @@ namespace Greenshot.Base.Core
|
|||
/// </summary>
|
||||
public interface IFastBitmapWithClip : IFastBitmap
|
||||
{
|
||||
NativeRect Clip { get; set; }
|
||||
Rectangle Clip { get; set; }
|
||||
|
||||
bool InvertClip { get; set; }
|
||||
|
||||
|
@ -269,14 +267,14 @@ namespace Greenshot.Base.Core
|
|||
public const int ColorIndexB = 2;
|
||||
public const int ColorIndexA = 3;
|
||||
|
||||
protected NativeRect Area;
|
||||
protected Rectangle Area;
|
||||
|
||||
/// <summary>
|
||||
/// If this is set to true, the bitmap will be disposed when disposing the IFastBitmap
|
||||
/// </summary>
|
||||
public bool NeedsDispose { get; set; }
|
||||
|
||||
public NativeRect Clip { get; set; }
|
||||
public Rectangle Clip { get; set; }
|
||||
|
||||
public bool InvertClip { get; set; }
|
||||
|
||||
|
@ -292,7 +290,7 @@ namespace Greenshot.Base.Core
|
|||
|
||||
public static IFastBitmap Create(Bitmap source)
|
||||
{
|
||||
return Create(source, NativeRect.Empty);
|
||||
return Create(source, Rectangle.Empty);
|
||||
}
|
||||
|
||||
public void SetResolution(float horizontal, float vertical)
|
||||
|
@ -305,37 +303,44 @@ namespace Greenshot.Base.Core
|
|||
/// The supplied rectangle specifies the area for which the FastBitmap does its thing
|
||||
/// </summary>
|
||||
/// <param name="source">Bitmap to access</param>
|
||||
/// <param name="area">NativeRect which specifies the area to have access to, can be NativeRect.Empty for the whole image</param>
|
||||
/// <param name="area">Rectangle which specifies the area to have access to, can be Rectangle.Empty for the whole image</param>
|
||||
/// <returns>IFastBitmap</returns>
|
||||
public static IFastBitmap Create(Bitmap source, NativeRect area) =>
|
||||
source.PixelFormat switch
|
||||
{
|
||||
PixelFormat.Format8bppIndexed => new FastChunkyBitmap(source, area),
|
||||
PixelFormat.Format24bppRgb => new Fast24RgbBitmap(source, area),
|
||||
PixelFormat.Format32bppRgb => new Fast32RgbBitmap(source, area),
|
||||
PixelFormat.Format32bppArgb => new Fast32ArgbBitmap(source, area),
|
||||
PixelFormat.Format32bppPArgb => new Fast32ArgbBitmap(source, area),
|
||||
_ => throw new NotSupportedException($"Not supported PixelFormat {source.PixelFormat}")
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Factory for creating a FastBitmap as a destination for the source
|
||||
/// </summary>
|
||||
/// <param name="source">Bitmap to clone</param>
|
||||
/// <param name="pixelFormat">new PixelFormat</param>
|
||||
/// <returns>IFastBitmap</returns>
|
||||
public static IFastBitmap CreateCloneOf(Image source, PixelFormat pixelFormat)
|
||||
public static IFastBitmap Create(Bitmap source, Rectangle area)
|
||||
{
|
||||
return CreateCloneOf(source, pixelFormat, NativeRect.Empty);
|
||||
switch (source.PixelFormat)
|
||||
{
|
||||
case PixelFormat.Format8bppIndexed:
|
||||
return new FastChunkyBitmap(source, area);
|
||||
case PixelFormat.Format24bppRgb:
|
||||
return new Fast24RgbBitmap(source, area);
|
||||
case PixelFormat.Format32bppRgb:
|
||||
return new Fast32RgbBitmap(source, area);
|
||||
case PixelFormat.Format32bppArgb:
|
||||
case PixelFormat.Format32bppPArgb:
|
||||
return new Fast32ArgbBitmap(source, area);
|
||||
default:
|
||||
throw new NotSupportedException($"Not supported Pixelformat {source.PixelFormat}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Factory for creating a FastBitmap as a destination for the source
|
||||
/// </summary>
|
||||
/// <param name="source">Bitmap to clone</param>
|
||||
/// <param name="area">Area of the bitmap to access, can be NativeRect.Empty for the whole</param>
|
||||
/// <param name="pixelFormat">new Pixelformat</param>
|
||||
/// <returns>IFastBitmap</returns>
|
||||
public static IFastBitmap CreateCloneOf(Image source, NativeRect area)
|
||||
public static IFastBitmap CreateCloneOf(Image source, PixelFormat pixelFormat)
|
||||
{
|
||||
return CreateCloneOf(source, pixelFormat, Rectangle.Empty);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Factory for creating a FastBitmap as a destination for the source
|
||||
/// </summary>
|
||||
/// <param name="source">Bitmap to clone</param>
|
||||
/// <param name="area">Area of the bitmap to access, can be Rectangle.Empty for the whole</param>
|
||||
/// <returns>IFastBitmap</returns>
|
||||
public static IFastBitmap CreateCloneOf(Image source, Rectangle area)
|
||||
{
|
||||
return CreateCloneOf(source, PixelFormat.DontCare, area);
|
||||
}
|
||||
|
@ -345,9 +350,9 @@ namespace Greenshot.Base.Core
|
|||
/// </summary>
|
||||
/// <param name="source">Bitmap to clone</param>
|
||||
/// <param name="pixelFormat">Pixelformat of the cloned bitmap</param>
|
||||
/// <param name="area">Area of the bitmap to access, can be NativeRect.Empty for the whole</param>
|
||||
/// <param name="area">Area of the bitmap to access, can be Rectangle.Empty for the whole</param>
|
||||
/// <returns>IFastBitmap</returns>
|
||||
public static IFastBitmap CreateCloneOf(Image source, PixelFormat pixelFormat, NativeRect area)
|
||||
public static IFastBitmap CreateCloneOf(Image source, PixelFormat pixelFormat, Rectangle area)
|
||||
{
|
||||
Bitmap destination = ImageHelper.CloneArea(source, area, pixelFormat);
|
||||
FastBitmap fastBitmap = Create(destination) as FastBitmap;
|
||||
|
@ -364,11 +369,11 @@ namespace Greenshot.Base.Core
|
|||
/// <summary>
|
||||
/// Factory for creating a FastBitmap as a destination
|
||||
/// </summary>
|
||||
/// <param name="newSize">NativeSize</param>
|
||||
/// <param name="pixelFormat">PixelFormat</param>
|
||||
/// <param name="backgroundColor">Color</param>
|
||||
/// <param name="newSize"></param>
|
||||
/// <param name="pixelFormat"></param>
|
||||
/// <param name="backgroundColor"></param>
|
||||
/// <returns>IFastBitmap</returns>
|
||||
public static IFastBitmap CreateEmpty(NativeSize newSize, PixelFormat pixelFormat, Color backgroundColor)
|
||||
public static IFastBitmap CreateEmpty(Size newSize, PixelFormat pixelFormat, Color backgroundColor)
|
||||
{
|
||||
Bitmap destination = ImageHelper.CreateEmpty(newSize.Width, newSize.Height, pixelFormat, backgroundColor, 96f, 96f);
|
||||
IFastBitmap fastBitmap = Create(destination);
|
||||
|
@ -380,14 +385,14 @@ namespace Greenshot.Base.Core
|
|||
/// Constructor which stores the image and locks it when called
|
||||
/// </summary>
|
||||
/// <param name="bitmap">Bitmap</param>
|
||||
/// <param name="area">NativeRect</param>
|
||||
protected FastBitmap(Bitmap bitmap, NativeRect area)
|
||||
/// <param name="area">Rectangle</param>
|
||||
protected FastBitmap(Bitmap bitmap, Rectangle area)
|
||||
{
|
||||
Bitmap = bitmap;
|
||||
var bitmapArea = new NativeRect(NativePoint.Empty, bitmap.Size);
|
||||
if (area != NativeRect.Empty)
|
||||
Rectangle bitmapArea = new Rectangle(Point.Empty, bitmap.Size);
|
||||
if (area != Rectangle.Empty)
|
||||
{
|
||||
area = area.Intersect(bitmapArea);
|
||||
area.Intersect(bitmapArea);
|
||||
Area = area;
|
||||
}
|
||||
else
|
||||
|
@ -408,11 +413,11 @@ namespace Greenshot.Base.Core
|
|||
/// <summary>
|
||||
/// Return the size of the image
|
||||
/// </summary>
|
||||
public NativeSize Size
|
||||
public Size Size
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Area == NativeRect.Empty)
|
||||
if (Area == Rectangle.Empty)
|
||||
{
|
||||
return Bitmap.Size;
|
||||
}
|
||||
|
@ -428,7 +433,7 @@ namespace Greenshot.Base.Core
|
|||
{
|
||||
get
|
||||
{
|
||||
if (Area == NativeRect.Empty)
|
||||
if (Area == Rectangle.Empty)
|
||||
{
|
||||
return Bitmap.Width;
|
||||
}
|
||||
|
@ -444,7 +449,7 @@ namespace Greenshot.Base.Core
|
|||
{
|
||||
get
|
||||
{
|
||||
if (Area == NativeRect.Empty)
|
||||
if (Area == Rectangle.Empty)
|
||||
{
|
||||
return Bitmap.Height;
|
||||
}
|
||||
|
@ -591,13 +596,13 @@ namespace Greenshot.Base.Core
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Draw the stored bitmap to the destination bitmap at the supplied point
|
||||
/// Draw the stored bitmap to the destionation bitmap at the supplied point
|
||||
/// </summary>
|
||||
/// <param name="graphics"></param>
|
||||
/// <param name="destination"></param>
|
||||
public void DrawTo(Graphics graphics, NativePoint destination)
|
||||
public void DrawTo(Graphics graphics, Point destination)
|
||||
{
|
||||
DrawTo(graphics, new NativeRect(destination, Area.Size));
|
||||
DrawTo(graphics, new Rectangle(destination, Area.Size));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -605,8 +610,8 @@ namespace Greenshot.Base.Core
|
|||
/// Be aware that the stored bitmap will be resized to the specified rectangle!!
|
||||
/// </summary>
|
||||
/// <param name="graphics"></param>
|
||||
/// <param name="destinationRect">NativeRect</param>
|
||||
public void DrawTo(Graphics graphics, NativeRect destinationRect)
|
||||
/// <param name="destinationRect"></param>
|
||||
public void DrawTo(Graphics graphics, Rectangle destinationRect)
|
||||
{
|
||||
// Make sure this.bitmap is unlocked, if it was locked
|
||||
bool isLocked = BitsLocked;
|
||||
|
@ -710,7 +715,7 @@ namespace Greenshot.Base.Core
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// This is the implementation of the FastBitmap for the 8BPP pixelformat
|
||||
/// This is the implementation of the FastBitmat for the 8BPP pixelformat
|
||||
/// </summary>
|
||||
public unsafe class FastChunkyBitmap : FastBitmap
|
||||
{
|
||||
|
@ -718,7 +723,7 @@ namespace Greenshot.Base.Core
|
|||
private readonly Color[] _colorEntries;
|
||||
private readonly Dictionary<Color, byte> _colorCache = new Dictionary<Color, byte>();
|
||||
|
||||
public FastChunkyBitmap(Bitmap source, NativeRect area) : base(source, area)
|
||||
public FastChunkyBitmap(Bitmap source, Rectangle area) : base(source, area)
|
||||
{
|
||||
_colorEntries = Bitmap.Palette.Entries;
|
||||
}
|
||||
|
@ -820,7 +825,7 @@ namespace Greenshot.Base.Core
|
|||
/// </summary>
|
||||
public unsafe class Fast24RgbBitmap : FastBitmap
|
||||
{
|
||||
public Fast24RgbBitmap(Bitmap source, NativeRect area) : base(source, area)
|
||||
public Fast24RgbBitmap(Bitmap source, Rectangle area) : base(source, area)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -886,7 +891,7 @@ namespace Greenshot.Base.Core
|
|||
/// </summary>
|
||||
public unsafe class Fast32RgbBitmap : FastBitmap
|
||||
{
|
||||
public Fast32RgbBitmap(Bitmap source, NativeRect area) : base(source, area)
|
||||
public Fast32RgbBitmap(Bitmap source, Rectangle area) : base(source, area)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -956,7 +961,7 @@ namespace Greenshot.Base.Core
|
|||
|
||||
public Color BackgroundBlendColor { get; set; }
|
||||
|
||||
public Fast32ArgbBitmap(Bitmap source, NativeRect area) : base(source, area)
|
||||
public Fast32ArgbBitmap(Bitmap source, Rectangle area) : base(source, area)
|
||||
{
|
||||
BackgroundBlendColor = Color.White;
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using Dapplo.Windows.Common.Structs;
|
||||
using Greenshot.Base.UnmanagedHelpers.Structs;
|
||||
|
||||
namespace Greenshot.Base.Core
|
||||
{
|
||||
|
@ -30,8 +30,8 @@ namespace Greenshot.Base.Core
|
|||
{
|
||||
public FileDescriptorFlags Flags { get; set; }
|
||||
public Guid ClassId { get; set; }
|
||||
public NativeSize Size { get; set; }
|
||||
public NativePoint Point { get; set; }
|
||||
public SIZE Size { get; set; }
|
||||
public POINT Point { get; set; }
|
||||
public FileAttributes FileAttributes { get; set; }
|
||||
public DateTime CreationTime { get; set; }
|
||||
public DateTime LastAccessTime { get; set; }
|
||||
|
@ -46,9 +46,9 @@ namespace Greenshot.Base.Core
|
|||
//ClassID
|
||||
ClassId = new Guid(reader.ReadBytes(16));
|
||||
//Size
|
||||
Size = new NativeSize(reader.ReadInt32(), reader.ReadInt32());
|
||||
Size = new SIZE(reader.ReadInt32(), reader.ReadInt32());
|
||||
//Point
|
||||
Point = new NativePoint(reader.ReadInt32(), reader.ReadInt32());
|
||||
Point = new POINT(reader.ReadInt32(), reader.ReadInt32());
|
||||
//FileAttributes
|
||||
FileAttributes = (FileAttributes)reader.ReadUInt32();
|
||||
//CreationTime
|
||||
|
|
|
@ -1,163 +0,0 @@
|
|||
/*
|
||||
* Greenshot - a free and open source screenshot tool
|
||||
* Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
|
||||
*
|
||||
* For more information see: https://getgreenshot.org/
|
||||
* The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Greenshot.Base.Interfaces;
|
||||
using Greenshot.Base.Interfaces.Drawing;
|
||||
using Greenshot.Base.Interfaces.Plugin;
|
||||
|
||||
namespace Greenshot.Base.Core.FileFormatHandlers
|
||||
{
|
||||
/// <summary>
|
||||
/// This is the registry where all IFileFormatHandler are registered and can be used
|
||||
/// </summary>
|
||||
public static class FileFormatHandlerExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Make sure we handle the input extension always the same, by "normalizing" it
|
||||
/// </summary>
|
||||
/// <param name="extension">string</param>
|
||||
/// <returns>string</returns>
|
||||
public static string NormalizeExtension(string extension)
|
||||
{
|
||||
if (string.IsNullOrEmpty(extension))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
extension = extension.ToLowerInvariant();
|
||||
return !extension.StartsWith(".") ? $".{extension}" : extension;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return the extensions that the provided IFileFormatHandlers can accept for the specified action
|
||||
/// </summary>
|
||||
/// <param name="fileFormatHandlers">IEnumerable{IFileFormatHandler}</param>
|
||||
/// <param name="fileFormatHandlerAction"></param>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<string> ExtensionsFor(this IEnumerable<IFileFormatHandler> fileFormatHandlers, FileFormatHandlerActions fileFormatHandlerAction)
|
||||
{
|
||||
return fileFormatHandlers.Where(ffh => ffh.SupportedExtensions.ContainsKey(fileFormatHandlerAction)).SelectMany(ffh => ffh.SupportedExtensions[fileFormatHandlerAction]).Distinct().OrderBy(e => e);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Extension method to check if a certain IFileFormatHandler supports a certain action with a specific extension
|
||||
/// </summary>
|
||||
/// <param name="fileFormatHandler">IFileFormatHandler</param>
|
||||
/// <param name="fileFormatHandlerAction">FileFormatHandlerActions</param>
|
||||
/// <param name="extension">string</param>
|
||||
/// <returns>bool</returns>
|
||||
public static bool Supports(this IFileFormatHandler fileFormatHandler, FileFormatHandlerActions fileFormatHandlerAction, string extension)
|
||||
{
|
||||
extension = NormalizeExtension(extension);
|
||||
return fileFormatHandler.SupportedExtensions.ContainsKey(fileFormatHandlerAction) && fileFormatHandler.SupportedExtensions[fileFormatHandlerAction].Contains(extension);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This wrapper method for TrySaveToStream will do:
|
||||
/// Find all the IFileFormatHandler which support the action for the supplied extension.
|
||||
/// Take the first, to call the TrySaveToStream on.
|
||||
/// </summary>
|
||||
/// <param name="fileFormatHandlers">IEnumerable{IFileFormatHandler}</param>
|
||||
/// <param name="bitmap">Bitmap</param>
|
||||
/// <param name="destination">Stream</param>
|
||||
/// <param name="extension">string</param>
|
||||
/// <param name="surface">ISurface</param>
|
||||
/// <returns>bool</returns>
|
||||
public static bool TrySaveToStream(this IEnumerable<IFileFormatHandler> fileFormatHandlers, Bitmap bitmap, Stream destination, string extension, ISurface surface = null, SurfaceOutputSettings surfaceOutputSettings = null)
|
||||
{
|
||||
extension = NormalizeExtension(extension);
|
||||
|
||||
var saveFileFormatHandlers = fileFormatHandlers
|
||||
.Where(ffh => ffh.Supports(FileFormatHandlerActions.LoadFromStream, extension))
|
||||
.OrderBy(ffh => ffh.PriorityFor(FileFormatHandlerActions.LoadFromStream, extension)).ToList();
|
||||
|
||||
if (!saveFileFormatHandlers.Any())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach (var fileFormatHandler in saveFileFormatHandlers)
|
||||
{
|
||||
if (fileFormatHandler.TrySaveToStream(bitmap, destination, extension, surface))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Try to load a drawable container from the stream
|
||||
/// </summary>
|
||||
/// <param name="fileFormatHandlers">IEnumerable{IFileFormatHandler}</param>
|
||||
/// <param name="stream">Stream</param>
|
||||
/// <param name="extension">string</param>
|
||||
/// <param name="parentSurface">ISurface</param>
|
||||
/// <returns>IEnumerable{IDrawableContainer}</returns>
|
||||
public static IEnumerable<IDrawableContainer> LoadDrawablesFromStream(this IEnumerable<IFileFormatHandler> fileFormatHandlers, Stream stream, string extension, ISurface parentSurface = null)
|
||||
{
|
||||
extension = NormalizeExtension(extension);
|
||||
|
||||
var loadfileFormatHandler = fileFormatHandlers
|
||||
.Where(ffh => ffh.Supports(FileFormatHandlerActions.LoadDrawableFromStream, extension))
|
||||
.OrderBy(ffh => ffh.PriorityFor(FileFormatHandlerActions.LoadDrawableFromStream, extension))
|
||||
.FirstOrDefault();
|
||||
|
||||
if (loadfileFormatHandler != null)
|
||||
{
|
||||
return loadfileFormatHandler.LoadDrawablesFromStream(stream, extension, parentSurface);
|
||||
}
|
||||
|
||||
return Enumerable.Empty<IDrawableContainer>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Try to load a Bitmap from the stream
|
||||
/// </summary>
|
||||
/// <param name="fileFormatHandlers">IEnumerable{IFileFormatHandler}</param>
|
||||
/// <param name="stream">Stream</param>
|
||||
/// <param name="extension">string</param>
|
||||
/// <param name="bitmap">Bitmap out</param>
|
||||
/// <returns>bool true if it was successful</returns>
|
||||
public static bool TryLoadFromStream(this IEnumerable<IFileFormatHandler> fileFormatHandlers, Stream stream, string extension, out Bitmap bitmap)
|
||||
{
|
||||
extension = NormalizeExtension(extension);
|
||||
|
||||
var loadFileFormatHandler = fileFormatHandlers
|
||||
.Where(ffh => ffh.Supports(FileFormatHandlerActions.LoadFromStream, extension))
|
||||
.OrderBy(ffh => ffh.PriorityFor(FileFormatHandlerActions.LoadFromStream, extension))
|
||||
.FirstOrDefault();
|
||||
|
||||
if (loadFileFormatHandler == null)
|
||||
{
|
||||
bitmap = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
return loadFileFormatHandler.TryLoadFromStream(stream, extension, out bitmap);
|
||||
}
|
||||
}
|
||||
}
|
52
src/Greenshot.Base/Core/HResultExtensions.cs
Normal file
52
src/Greenshot.Base/Core/HResultExtensions.cs
Normal file
|
@ -0,0 +1,52 @@
|
|||
// Greenshot - a free and open source screenshot tool
|
||||
// Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
|
||||
//
|
||||
// For more information see: https://getgreenshot.org/
|
||||
// The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 1 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
using System.Diagnostics.Contracts;
|
||||
using Greenshot.Base.Core.Enums;
|
||||
|
||||
namespace Greenshot.Base.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Extensions to handle the HResult
|
||||
/// </summary>
|
||||
public static class HResultExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Test if the HResult represents a fail
|
||||
/// </summary>
|
||||
/// <param name="hResult">HResult</param>
|
||||
/// <returns>bool</returns>
|
||||
[Pure]
|
||||
public static bool Failed(this HResult hResult)
|
||||
{
|
||||
return hResult < 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test if the HResult represents a success
|
||||
/// </summary>
|
||||
/// <param name="hResult">HResult</param>
|
||||
/// <returns>bool</returns>
|
||||
[Pure]
|
||||
public static bool Succeeded(this HResult hResult)
|
||||
{
|
||||
return hResult >= HResult.S_OK;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -61,7 +61,7 @@ namespace Greenshot.Base.Core
|
|||
float HorizontalResolution { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Underlying image, or an on demand rendered version with different attributes as the original
|
||||
/// Unterlying image, or an on demand rendered version with different attributes as the original
|
||||
/// </summary>
|
||||
Image Image { get; }
|
||||
}
|
||||
|
|
|
@ -24,24 +24,28 @@ using System.Collections.Generic;
|
|||
using System.Drawing;
|
||||
using System.Drawing.Drawing2D;
|
||||
using System.Drawing.Imaging;
|
||||
using System.Windows;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using Dapplo.Windows.Common.Extensions;
|
||||
using Dapplo.Windows.Common.Structs;
|
||||
using Dapplo.Windows.Gdi32;
|
||||
using Greenshot.Base.Core.Enums;
|
||||
using System.IO;
|
||||
using Greenshot.Base.Effects;
|
||||
using Greenshot.Base.IniFile;
|
||||
using Greenshot.Base.Interfaces;
|
||||
using Greenshot.Base.UnmanagedHelpers;
|
||||
using log4net;
|
||||
using Brush = System.Drawing.Brush;
|
||||
using Color = System.Drawing.Color;
|
||||
using Matrix = System.Drawing.Drawing2D.Matrix;
|
||||
using Pen = System.Drawing.Pen;
|
||||
using PixelFormat = System.Drawing.Imaging.PixelFormat;
|
||||
|
||||
namespace Greenshot.Base.Core
|
||||
{
|
||||
internal enum ExifOrientations : byte
|
||||
{
|
||||
Unknown = 0,
|
||||
TopLeft = 1,
|
||||
TopRight = 2,
|
||||
BottomRight = 3,
|
||||
BottomLeft = 4,
|
||||
LeftTop = 5,
|
||||
RightTop = 6,
|
||||
RightBottom = 7,
|
||||
LeftBottom = 8,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Description of ImageHelper.
|
||||
/// </summary>
|
||||
|
@ -51,6 +55,83 @@ namespace Greenshot.Base.Core
|
|||
private static readonly CoreConfiguration CoreConfig = IniConfig.GetIniSection<CoreConfiguration>();
|
||||
private const int ExifOrientationId = 0x0112;
|
||||
|
||||
static ImageHelper()
|
||||
{
|
||||
StreamConverters["greenshot"] = (stream, s) =>
|
||||
{
|
||||
var surface = SimpleServiceProvider.Current.GetInstance<Func<ISurface>>().Invoke();
|
||||
return surface.GetImageForExport();
|
||||
};
|
||||
|
||||
// Add a SVG converter
|
||||
StreamConverters["svg"] = (stream, s) =>
|
||||
{
|
||||
stream.Position = 0;
|
||||
try
|
||||
{
|
||||
return SvgImage.FromStream(stream).Image;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error("Can't load SVG", ex);
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
static Image DefaultConverter(Stream stream, string s)
|
||||
{
|
||||
stream.Position = 0;
|
||||
using var tmpImage = Image.FromStream(stream, true, true);
|
||||
Log.DebugFormat("Loaded bitmap with Size {0}x{1} and PixelFormat {2}", tmpImage.Width, tmpImage.Height, tmpImage.PixelFormat);
|
||||
return Clone(tmpImage, PixelFormat.Format32bppArgb);
|
||||
}
|
||||
|
||||
// Fallback
|
||||
StreamConverters[string.Empty] = DefaultConverter;
|
||||
StreamConverters["gif"] = DefaultConverter;
|
||||
StreamConverters["bmp"] = DefaultConverter;
|
||||
StreamConverters["jpg"] = DefaultConverter;
|
||||
StreamConverters["jpeg"] = DefaultConverter;
|
||||
StreamConverters["png"] = DefaultConverter;
|
||||
StreamConverters["wmf"] = DefaultConverter;
|
||||
|
||||
StreamConverters["ico"] = (stream, extension) =>
|
||||
{
|
||||
// Icon logic, try to get the Vista icon, else the biggest possible
|
||||
try
|
||||
{
|
||||
using Image tmpImage = ExtractVistaIcon(stream);
|
||||
if (tmpImage != null)
|
||||
{
|
||||
return Clone(tmpImage, PixelFormat.Format32bppArgb);
|
||||
}
|
||||
}
|
||||
catch (Exception vistaIconException)
|
||||
{
|
||||
Log.Warn("Can't read icon", vistaIconException);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// No vista icon, try normal icon
|
||||
stream.Position = 0;
|
||||
// We create a copy of the bitmap, so everything else can be disposed
|
||||
using Icon tmpIcon = new Icon(stream, new Size(1024, 1024));
|
||||
using Image tmpImage = tmpIcon.ToBitmap();
|
||||
return Clone(tmpImage, PixelFormat.Format32bppArgb);
|
||||
}
|
||||
catch (Exception iconException)
|
||||
{
|
||||
Log.Warn("Can't read icon", iconException);
|
||||
}
|
||||
|
||||
stream.Position = 0;
|
||||
return DefaultConverter(stream, extension);
|
||||
};
|
||||
}
|
||||
|
||||
public static IDictionary<string, Func<Stream, string, Image>> StreamConverters { get; } = new Dictionary<string, Func<Stream, string, Image>>();
|
||||
|
||||
/// <summary>
|
||||
/// Make sure the image is orientated correctly
|
||||
|
@ -157,7 +238,7 @@ namespace Greenshot.Base.Core
|
|||
graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
|
||||
graphics.CompositingQuality = CompositingQuality.HighQuality;
|
||||
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
|
||||
NativeRect rectDestination = new NativeRect(0, 0, thumbWidth, thumbHeight);
|
||||
Rectangle rectDestination = new Rectangle(0, 0, thumbWidth, thumbHeight);
|
||||
graphics.DrawImage(image, rectDestination, 0, 0, srcWidth, srcHeight, GraphicsUnit.Pixel);
|
||||
}
|
||||
|
||||
|
@ -165,18 +246,18 @@ namespace Greenshot.Base.Core
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Crops the image to the specified NativeRect
|
||||
/// Crops the image to the specified rectangle
|
||||
/// </summary>
|
||||
/// <param name="image">Image to crop</param>
|
||||
/// <param name="cropNativeRect">NativeRect with bitmap coordinates, will be "intersected" to the bitmap</param>
|
||||
public static bool Crop(ref Image image, ref NativeRect cropNativeRect)
|
||||
/// <param name="cropRectangle">Rectangle with bitmap coordinates, will be "intersected" to the bitmap</param>
|
||||
public static bool Crop(ref Image image, ref Rectangle cropRectangle)
|
||||
{
|
||||
if (image is Bitmap && (image.Width * image.Height > 0))
|
||||
{
|
||||
cropNativeRect = cropNativeRect.Intersect(new NativeRect(0, 0, image.Width, image.Height));
|
||||
if (cropNativeRect.Width != 0 || cropNativeRect.Height != 0)
|
||||
cropRectangle.Intersect(new Rectangle(0, 0, image.Width, image.Height));
|
||||
if (cropRectangle.Width != 0 || cropRectangle.Height != 0)
|
||||
{
|
||||
Image returnImage = CloneArea(image, cropNativeRect, PixelFormat.DontCare);
|
||||
Image returnImage = CloneArea(image, cropRectangle, PixelFormat.DontCare);
|
||||
image.Dispose();
|
||||
image = returnImage;
|
||||
return true;
|
||||
|
@ -188,26 +269,24 @@ namespace Greenshot.Base.Core
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Private helper method for the FindAutoCropNativeRect
|
||||
/// Private helper method for the FindAutoCropRectangle
|
||||
/// </summary>
|
||||
/// <param name="fastBitmap">IFastBitmap</param>
|
||||
/// <param name="colorPoint">NativePoint</param>
|
||||
/// <param name="cropDifference">int</param>
|
||||
/// <param name="area">NativeRect with optional area to scan in</param>
|
||||
/// <returns>NativeRect</returns>
|
||||
private static NativeRect FindAutoCropNativeRect(IFastBitmap fastBitmap, NativePoint colorPoint, int cropDifference, NativeRect? area = null)
|
||||
/// <param name="fastBitmap"></param>
|
||||
/// <param name="colorPoint"></param>
|
||||
/// <param name="cropDifference"></param>
|
||||
/// <returns>Rectangle</returns>
|
||||
private static Rectangle FindAutoCropRectangle(IFastBitmap fastBitmap, Point colorPoint, int cropDifference)
|
||||
{
|
||||
area ??= new NativeRect(0, 0, fastBitmap.Width, fastBitmap.Height);
|
||||
NativeRect cropNativeRect = NativeRect.Empty;
|
||||
Rectangle cropRectangle = Rectangle.Empty;
|
||||
Color referenceColor = fastBitmap.GetColorAt(colorPoint.X, colorPoint.Y);
|
||||
NativePoint min = new NativePoint(int.MaxValue, int.MaxValue);
|
||||
NativePoint max = new NativePoint(int.MinValue, int.MinValue);
|
||||
Point min = new Point(int.MaxValue, int.MaxValue);
|
||||
Point max = new Point(int.MinValue, int.MinValue);
|
||||
|
||||
if (cropDifference > 0)
|
||||
{
|
||||
for (int y = area.Value.Top; y < area.Value.Bottom; y++)
|
||||
for (int y = 0; y < fastBitmap.Height; y++)
|
||||
{
|
||||
for (int x = area.Value.Left; x < area.Value.Right; x++)
|
||||
for (int x = 0; x < fastBitmap.Width; x++)
|
||||
{
|
||||
Color currentColor = fastBitmap.GetColorAt(x, y);
|
||||
int diffR = Math.Abs(currentColor.R - referenceColor.R);
|
||||
|
@ -218,18 +297,18 @@ namespace Greenshot.Base.Core
|
|||
continue;
|
||||
}
|
||||
|
||||
if (x < min.X) min = min.ChangeX(x);
|
||||
if (y < min.Y) min = min.ChangeY(y);
|
||||
if (x > max.X) max = max.ChangeX(x);
|
||||
if (y > max.Y) max = max.ChangeY(y);
|
||||
if (x < min.X) min.X = x;
|
||||
if (y < min.Y) min.Y = y;
|
||||
if (x > max.X) max.X = x;
|
||||
if (y > max.Y) max.Y = y;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int y = area.Value.Top; y < area.Value.Bottom; y++)
|
||||
for (int y = 0; y < fastBitmap.Height; y++)
|
||||
{
|
||||
for (int x = area.Value.Left; x < area.Value.Right; x++)
|
||||
for (int x = 0; x < fastBitmap.Width; x++)
|
||||
{
|
||||
Color currentColor = fastBitmap.GetColorAt(x, y);
|
||||
if (!referenceColor.Equals(currentColor))
|
||||
|
@ -237,44 +316,41 @@ namespace Greenshot.Base.Core
|
|||
continue;
|
||||
}
|
||||
|
||||
if (x < min.X) min = min.ChangeX(x);
|
||||
if (y < min.Y) min = min.ChangeY(y);
|
||||
if (x > max.X) max = max.ChangeX(x);
|
||||
if (y > max.Y) max = max.ChangeY(y);
|
||||
if (x < min.X) min.X = x;
|
||||
if (y < min.Y) min.Y = y;
|
||||
if (x > max.X) max.X = x;
|
||||
if (y > max.Y) max.Y = y;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!(NativePoint.Empty.Equals(min) && max.Equals(new NativePoint(area.Value.Width - 1, area.Value.Height - 1))))
|
||||
if (!(Point.Empty.Equals(min) && max.Equals(new Point(fastBitmap.Width - 1, fastBitmap.Height - 1))))
|
||||
{
|
||||
if (!(min.X == int.MaxValue || min.Y == int.MaxValue || max.X == int.MinValue || min.X == int.MinValue))
|
||||
{
|
||||
cropNativeRect = new NativeRect(min.X, min.Y, max.X - min.X + 1, max.Y - min.Y + 1);
|
||||
cropRectangle = new Rectangle(min.X, min.Y, max.X - min.X + 1, max.Y - min.Y + 1);
|
||||
}
|
||||
}
|
||||
|
||||
return cropNativeRect;
|
||||
return cropRectangle;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a NativeRect for the image which crops the image of all colors equal to that on 0,0
|
||||
/// Get a rectangle for the image which crops the image of all colors equal to that on 0,0
|
||||
/// </summary>
|
||||
/// <param name="image">Image</param>
|
||||
/// <param name="cropDifference">int</param>
|
||||
/// <param name="area">NativeRect with optional area</param>
|
||||
/// <returns>NativeRect</returns>
|
||||
public static NativeRect FindAutoCropRectangle(Image image, int cropDifference, NativeRect? area = null)
|
||||
/// <param name="image"></param>
|
||||
/// <param name="cropDifference"></param>
|
||||
/// <returns>Rectangle</returns>
|
||||
public static Rectangle FindAutoCropRectangle(Image image, int cropDifference)
|
||||
{
|
||||
area ??= new NativeRect(0, 0, image.Width, image.Height);
|
||||
NativeRect cropNativeRect = NativeRect.Empty;
|
||||
var checkPoints = new List<NativePoint>
|
||||
Rectangle cropRectangle = Rectangle.Empty;
|
||||
var checkPoints = new List<Point>
|
||||
{
|
||||
new(area.Value.Left, area.Value.Top),
|
||||
new(area.Value.Left, area.Value.Bottom - 1),
|
||||
new(area.Value.Right - 1, area.Value.Top),
|
||||
new(area.Value.Right - 1, area.Value.Bottom - 1)
|
||||
new Point(0, 0),
|
||||
new Point(0, image.Height - 1),
|
||||
new Point(image.Width - 1, 0),
|
||||
new Point(image.Width - 1, image.Height - 1)
|
||||
};
|
||||
|
||||
// Top Left
|
||||
// Bottom Left
|
||||
// Top Right
|
||||
|
@ -282,17 +358,138 @@ namespace Greenshot.Base.Core
|
|||
using (IFastBitmap fastBitmap = FastBitmap.Create((Bitmap) image))
|
||||
{
|
||||
// find biggest area
|
||||
foreach (var checkPoint in checkPoints)
|
||||
foreach (Point checkPoint in checkPoints)
|
||||
{
|
||||
var currentNativeRect = FindAutoCropNativeRect(fastBitmap, checkPoint, cropDifference, area);
|
||||
if (currentNativeRect.Width * currentNativeRect.Height > cropNativeRect.Width * cropNativeRect.Height)
|
||||
var currentRectangle = FindAutoCropRectangle(fastBitmap, checkPoint, cropDifference);
|
||||
if (currentRectangle.Width * currentRectangle.Height > cropRectangle.Width * cropRectangle.Height)
|
||||
{
|
||||
cropNativeRect = currentNativeRect;
|
||||
cropRectangle = currentRectangle;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return cropNativeRect;
|
||||
return cropRectangle;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Load an image from file
|
||||
/// </summary>
|
||||
/// <param name="filename"></param>
|
||||
/// <returns></returns>
|
||||
public static Image LoadImage(string filename)
|
||||
{
|
||||
if (string.IsNullOrEmpty(filename))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!File.Exists(filename))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
Image fileImage;
|
||||
Log.InfoFormat("Loading image from file {0}", filename);
|
||||
// Fixed lock problem Bug #3431881
|
||||
using (Stream imageFileStream = File.OpenRead(filename))
|
||||
{
|
||||
fileImage = FromStream(imageFileStream, Path.GetExtension(filename));
|
||||
}
|
||||
|
||||
if (fileImage != null)
|
||||
{
|
||||
Log.InfoFormat("Information about file {0}: {1}x{2}-{3} Resolution {4}x{5}", filename, fileImage.Width, fileImage.Height, fileImage.PixelFormat,
|
||||
fileImage.HorizontalResolution, fileImage.VerticalResolution);
|
||||
}
|
||||
|
||||
return fileImage;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Based on: https://www.codeproject.com/KB/cs/IconExtractor.aspx
|
||||
/// And a hint from: https://www.codeproject.com/KB/cs/IconLib.aspx
|
||||
/// </summary>
|
||||
/// <param name="iconStream">Stream with the icon information</param>
|
||||
/// <returns>Bitmap with the Vista Icon (256x256)</returns>
|
||||
private static Bitmap ExtractVistaIcon(Stream iconStream)
|
||||
{
|
||||
const int sizeIconDir = 6;
|
||||
const int sizeIconDirEntry = 16;
|
||||
Bitmap bmpPngExtracted = null;
|
||||
try
|
||||
{
|
||||
byte[] srcBuf = new byte[iconStream.Length];
|
||||
iconStream.Read(srcBuf, 0, (int) iconStream.Length);
|
||||
int iCount = BitConverter.ToInt16(srcBuf, 4);
|
||||
for (int iIndex = 0; iIndex < iCount; iIndex++)
|
||||
{
|
||||
int iWidth = srcBuf[sizeIconDir + sizeIconDirEntry * iIndex];
|
||||
int iHeight = srcBuf[sizeIconDir + sizeIconDirEntry * iIndex + 1];
|
||||
if (iWidth == 0 && iHeight == 0)
|
||||
{
|
||||
int iImageSize = BitConverter.ToInt32(srcBuf, sizeIconDir + sizeIconDirEntry * iIndex + 8);
|
||||
int iImageOffset = BitConverter.ToInt32(srcBuf, sizeIconDir + sizeIconDirEntry * iIndex + 12);
|
||||
using MemoryStream destStream = new MemoryStream();
|
||||
destStream.Write(srcBuf, iImageOffset, iImageSize);
|
||||
destStream.Seek(0, SeekOrigin.Begin);
|
||||
bmpPngExtracted = new Bitmap(destStream); // This is PNG! :)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return bmpPngExtracted;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// See: https://msdn.microsoft.com/en-us/library/windows/desktop/ms648069%28v=vs.85%29.aspx
|
||||
/// </summary>
|
||||
/// <param name="location">The file (EXE or DLL) to get the icon from</param>
|
||||
/// <param name="index">Index of the icon</param>
|
||||
/// <param name="takeLarge">true if the large icon is wanted</param>
|
||||
/// <returns>Icon</returns>
|
||||
public static Icon ExtractAssociatedIcon(string location, int index, bool takeLarge)
|
||||
{
|
||||
Shell32.ExtractIconEx(location, index, out var large, out var small, 1);
|
||||
Icon returnIcon = null;
|
||||
bool isLarge = false;
|
||||
bool isSmall = false;
|
||||
try
|
||||
{
|
||||
if (takeLarge && !IntPtr.Zero.Equals(large))
|
||||
{
|
||||
returnIcon = Icon.FromHandle(large);
|
||||
isLarge = true;
|
||||
}
|
||||
else if (!IntPtr.Zero.Equals(small))
|
||||
{
|
||||
returnIcon = Icon.FromHandle(small);
|
||||
isSmall = true;
|
||||
}
|
||||
else if (!IntPtr.Zero.Equals(large))
|
||||
{
|
||||
returnIcon = Icon.FromHandle(large);
|
||||
isLarge = true;
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (isLarge && !IntPtr.Zero.Equals(small))
|
||||
{
|
||||
User32.DestroyIcon(small);
|
||||
}
|
||||
|
||||
if (isSmall && !IntPtr.Zero.Equals(large))
|
||||
{
|
||||
User32.DestroyIcon(large);
|
||||
}
|
||||
}
|
||||
|
||||
return returnIcon;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -300,7 +497,7 @@ namespace Greenshot.Base.Core
|
|||
/// </summary>
|
||||
/// <param name="sourceImage">Bitmap</param>
|
||||
/// <param name="effect">IEffect</param>
|
||||
/// <param name="matrix">Matrix</param>
|
||||
/// <param name="matrix"></param>
|
||||
/// <returns>Bitmap</returns>
|
||||
public static Image ApplyEffect(Image sourceImage, IEffect effect, Matrix matrix)
|
||||
{
|
||||
|
@ -346,7 +543,7 @@ namespace Greenshot.Base.Core
|
|||
/// </summary>
|
||||
/// <param name="path">Path to draw to</param>
|
||||
/// <param name="points">Points for the lines to draw</param>
|
||||
private static void DrawLines(GraphicsPath path, List<NativePoint> points)
|
||||
private static void DrawLines(GraphicsPath path, List<Point> points)
|
||||
{
|
||||
path.AddLine(points[0], points[1]);
|
||||
for (int i = 0; i < points.Count - 1; i++)
|
||||
|
@ -366,19 +563,20 @@ namespace Greenshot.Base.Core
|
|||
/// <returns>Changed bitmap</returns>
|
||||
public static Image CreateTornEdge(Image sourceImage, int toothHeight, int horizontalToothRange, int verticalToothRange, bool[] edges)
|
||||
{
|
||||
Image returnImage = CreateEmpty(sourceImage.Width, sourceImage.Height, PixelFormat.Format32bppArgb, Color.Empty, sourceImage.HorizontalResolution, sourceImage.VerticalResolution);
|
||||
Image returnImage = CreateEmpty(sourceImage.Width, sourceImage.Height, PixelFormat.Format32bppArgb, Color.Empty, sourceImage.HorizontalResolution,
|
||||
sourceImage.VerticalResolution);
|
||||
using (var path = new GraphicsPath())
|
||||
{
|
||||
Random random = new Random();
|
||||
int horizontalRegions = (int) Math.Round((float) sourceImage.Width / horizontalToothRange);
|
||||
int verticalRegions = (int) Math.Round((float) sourceImage.Height / verticalToothRange);
|
||||
|
||||
var topLeft = new NativePoint(0, 0);
|
||||
var topRight = new NativePoint(sourceImage.Width, 0);
|
||||
var bottomLeft = new NativePoint(0, sourceImage.Height);
|
||||
var bottomRight = new NativePoint(sourceImage.Width, sourceImage.Height);
|
||||
Point topLeft = new Point(0, 0);
|
||||
Point topRight = new Point(sourceImage.Width, 0);
|
||||
Point bottomLeft = new Point(0, sourceImage.Height);
|
||||
Point bottomRight = new Point(sourceImage.Width, sourceImage.Height);
|
||||
|
||||
var points = new List<NativePoint>();
|
||||
List<Point> points = new List<Point>();
|
||||
|
||||
if (edges[0])
|
||||
{
|
||||
|
@ -389,15 +587,15 @@ namespace Greenshot.Base.Core
|
|||
}
|
||||
else
|
||||
{
|
||||
points.Add(new NativePoint(random.Next(1, toothHeight), random.Next(1, toothHeight)));
|
||||
points.Add(new Point(random.Next(1, toothHeight), random.Next(1, toothHeight)));
|
||||
}
|
||||
|
||||
for (int i = 1; i < horizontalRegions - 1; i++)
|
||||
{
|
||||
points.Add(new NativePoint(i * horizontalToothRange, random.Next(1, toothHeight)));
|
||||
points.Add(new Point(i * horizontalToothRange, random.Next(1, toothHeight)));
|
||||
}
|
||||
|
||||
points.Add(new NativePoint(sourceImage.Width - random.Next(1, toothHeight), random.Next(1, toothHeight)));
|
||||
points.Add(new Point(sourceImage.Width - random.Next(1, toothHeight), random.Next(1, toothHeight)));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -411,10 +609,10 @@ namespace Greenshot.Base.Core
|
|||
{
|
||||
for (int i = 1; i < verticalRegions - 1; i++)
|
||||
{
|
||||
points.Add(new NativePoint(sourceImage.Width - random.Next(1, toothHeight), i * verticalToothRange));
|
||||
points.Add(new Point(sourceImage.Width - random.Next(1, toothHeight), i * verticalToothRange));
|
||||
}
|
||||
|
||||
points.Add(new NativePoint(sourceImage.Width - random.Next(1, toothHeight), sourceImage.Height - random.Next(1, toothHeight)));
|
||||
points.Add(new Point(sourceImage.Width - random.Next(1, toothHeight), sourceImage.Height - random.Next(1, toothHeight)));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -429,10 +627,10 @@ namespace Greenshot.Base.Core
|
|||
{
|
||||
for (int i = 1; i < horizontalRegions - 1; i++)
|
||||
{
|
||||
points.Add(new NativePoint(sourceImage.Width - i * horizontalToothRange, sourceImage.Height - random.Next(1, toothHeight)));
|
||||
points.Add(new Point(sourceImage.Width - i * horizontalToothRange, sourceImage.Height - random.Next(1, toothHeight)));
|
||||
}
|
||||
|
||||
points.Add(new NativePoint(random.Next(1, toothHeight), sourceImage.Height - random.Next(1, toothHeight)));
|
||||
points.Add(new Point(random.Next(1, toothHeight), sourceImage.Height - random.Next(1, toothHeight)));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -448,7 +646,7 @@ namespace Greenshot.Base.Core
|
|||
// One fewer as the end point is the starting point
|
||||
for (int i = 1; i < verticalRegions - 1; i++)
|
||||
{
|
||||
points.Add(new NativePoint(random.Next(1, toothHeight), points[points.Count - 1].Y - verticalToothRange));
|
||||
points.Add(new Point(random.Next(1, toothHeight), points[points.Count - 1].Y - verticalToothRange));
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -769,18 +967,19 @@ namespace Greenshot.Base.Core
|
|||
/// <param name="applySize"></param>
|
||||
/// <param name="rect"></param>
|
||||
/// <param name="invert"></param>
|
||||
/// <returns>NativeRect</returns>
|
||||
public static NativeRect CreateIntersectRectangle(NativeSize applySize, NativeRect rect, bool invert)
|
||||
/// <returns></returns>
|
||||
public static Rectangle CreateIntersectRectangle(Size applySize, Rectangle rect, bool invert)
|
||||
{
|
||||
NativeRect myRect;
|
||||
Rectangle myRect;
|
||||
if (invert)
|
||||
{
|
||||
myRect = new NativeRect(0, 0, applySize.Width, applySize.Height);
|
||||
myRect = new Rectangle(0, 0, applySize.Width, applySize.Height);
|
||||
}
|
||||
else
|
||||
{
|
||||
NativeRect applyRect = new NativeRect(0, 0, applySize.Width, applySize.Height);
|
||||
myRect = new NativeRect(rect.X, rect.Y, rect.Width, rect.Height).Intersect(applyRect);
|
||||
Rectangle applyRect = new Rectangle(0, 0, applySize.Width, applySize.Height);
|
||||
myRect = new Rectangle(rect.X, rect.Y, rect.Width, rect.Height);
|
||||
myRect.Intersect(applyRect);
|
||||
}
|
||||
|
||||
return myRect;
|
||||
|
@ -796,9 +995,11 @@ namespace Greenshot.Base.Core
|
|||
/// <param name="shadowOffset"></param>
|
||||
/// <param name="matrix">The transform matrix which describes how the elements need to be transformed to stay at the same location</param>
|
||||
/// <returns>Bitmap with the shadow, is bigger than the sourceBitmap!!</returns>
|
||||
public static Bitmap CreateShadow(Image sourceBitmap, float darkness, int shadowSize, NativePoint shadowOffset, Matrix matrix, PixelFormat targetPixelformat)
|
||||
public static Bitmap CreateShadow(Image sourceBitmap, float darkness, int shadowSize, Point shadowOffset, Matrix matrix, PixelFormat targetPixelformat)
|
||||
{
|
||||
NativePoint offset = shadowOffset.Offset(shadowSize - 1, shadowSize - 1);
|
||||
Point offset = shadowOffset;
|
||||
offset.X += shadowSize - 1;
|
||||
offset.Y += shadowSize - 1;
|
||||
matrix.Translate(offset.X, offset.Y, MatrixOrder.Append);
|
||||
// Create a new "clean" image
|
||||
Bitmap returnImage = CreateEmpty(sourceBitmap.Width + shadowSize * 2, sourceBitmap.Height + shadowSize * 2, targetPixelformat, Color.Empty,
|
||||
|
@ -809,7 +1010,7 @@ namespace Greenshot.Base.Core
|
|||
shadowSize++;
|
||||
}
|
||||
|
||||
bool useGdiBlur = GdiPlusApi.IsBlurPossible(shadowSize);
|
||||
bool useGdiBlur = GDIplus.IsBlurPossible(shadowSize);
|
||||
// Create "mask" for the shadow
|
||||
ColorMatrix maskMatrix = new ColorMatrix
|
||||
{
|
||||
|
@ -826,20 +1027,20 @@ namespace Greenshot.Base.Core
|
|||
maskMatrix.Matrix33 = darkness;
|
||||
}
|
||||
|
||||
NativeRect shadowNativeRect = new NativeRect(new NativePoint(shadowSize, shadowSize), sourceBitmap.Size);
|
||||
ApplyColorMatrix((Bitmap) sourceBitmap, NativeRect.Empty, returnImage, shadowNativeRect, maskMatrix);
|
||||
Rectangle shadowRectangle = new Rectangle(new Point(shadowSize, shadowSize), sourceBitmap.Size);
|
||||
ApplyColorMatrix((Bitmap) sourceBitmap, Rectangle.Empty, returnImage, shadowRectangle, maskMatrix);
|
||||
|
||||
// blur "shadow", apply to whole new image
|
||||
if (useGdiBlur)
|
||||
{
|
||||
// Use GDI Blur
|
||||
NativeRect newImageNativeRect = new NativeRect(0, 0, returnImage.Width, returnImage.Height);
|
||||
GdiPlusApi.ApplyBlur(returnImage, newImageNativeRect, shadowSize + 1, false);
|
||||
Rectangle newImageRectangle = new Rectangle(0, 0, returnImage.Width, returnImage.Height);
|
||||
GDIplus.ApplyBlur(returnImage, newImageRectangle, shadowSize + 1, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
// try normal software blur
|
||||
//returnImage = CreateBlur(returnImage, newImageNativeRect, true, shadowSize, 1d, false, newImageNativeRect);
|
||||
//returnImage = CreateBlur(returnImage, newImageRectangle, true, shadowSize, 1d, false, newImageRectangle);
|
||||
ApplyBoxBlur(returnImage, shadowSize);
|
||||
}
|
||||
|
||||
|
@ -903,18 +1104,18 @@ namespace Greenshot.Base.Core
|
|||
/// <param name="colorMatrix">ColorMatrix to apply</param>
|
||||
public static void ApplyColorMatrix(Bitmap source, ColorMatrix colorMatrix)
|
||||
{
|
||||
ApplyColorMatrix(source, NativeRect.Empty, source, NativeRect.Empty, colorMatrix);
|
||||
ApplyColorMatrix(source, Rectangle.Empty, source, Rectangle.Empty, colorMatrix);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Apply a color matrix by copying from the source to the destination
|
||||
/// </summary>
|
||||
/// <param name="source">Image to copy from</param>
|
||||
/// <param name="sourceRect">NativeRect to copy from</param>
|
||||
/// <param name="destRect">NativeRect to copy to</param>
|
||||
/// <param name="sourceRect">Rectangle to copy from</param>
|
||||
/// <param name="destRect">Rectangle to copy to</param>
|
||||
/// <param name="dest">Image to copy to</param>
|
||||
/// <param name="colorMatrix">ColorMatrix to apply</param>
|
||||
public static void ApplyColorMatrix(Bitmap source, NativeRect sourceRect, Bitmap dest, NativeRect destRect, ColorMatrix colorMatrix)
|
||||
public static void ApplyColorMatrix(Bitmap source, Rectangle sourceRect, Bitmap dest, Rectangle destRect, ColorMatrix colorMatrix)
|
||||
{
|
||||
using ImageAttributes imageAttributes = new ImageAttributes();
|
||||
imageAttributes.ClearColorMatrix();
|
||||
|
@ -926,15 +1127,15 @@ namespace Greenshot.Base.Core
|
|||
/// Apply a color matrix by copying from the source to the destination
|
||||
/// </summary>
|
||||
/// <param name="source">Image to copy from</param>
|
||||
/// <param name="sourceRect">NativeRect to copy from</param>
|
||||
/// <param name="destRect">NativeRect to copy to</param>
|
||||
/// <param name="sourceRect">Rectangle to copy from</param>
|
||||
/// <param name="destRect">Rectangle to copy to</param>
|
||||
/// <param name="dest">Image to copy to</param>
|
||||
/// <param name="imageAttributes">ImageAttributes to apply</param>
|
||||
public static void ApplyImageAttributes(Bitmap source, NativeRect sourceRect, Bitmap dest, NativeRect destRect, ImageAttributes imageAttributes)
|
||||
public static void ApplyImageAttributes(Bitmap source, Rectangle sourceRect, Bitmap dest, Rectangle destRect, ImageAttributes imageAttributes)
|
||||
{
|
||||
if (sourceRect == NativeRect.Empty)
|
||||
if (sourceRect == Rectangle.Empty)
|
||||
{
|
||||
sourceRect = new NativeRect(0, 0, source.Width, source.Height);
|
||||
sourceRect = new Rectangle(0, 0, source.Width, source.Height);
|
||||
}
|
||||
|
||||
if (dest == null)
|
||||
|
@ -942,9 +1143,9 @@ namespace Greenshot.Base.Core
|
|||
dest = source;
|
||||
}
|
||||
|
||||
if (destRect == NativeRect.Empty)
|
||||
if (destRect == Rectangle.Empty)
|
||||
{
|
||||
destRect = new NativeRect(0, 0, dest.Width, dest.Height);
|
||||
destRect = new Rectangle(0, 0, dest.Width, dest.Height);
|
||||
}
|
||||
|
||||
using Graphics graphics = Graphics.FromImage(dest);
|
||||
|
@ -993,7 +1194,7 @@ namespace Greenshot.Base.Core
|
|||
public static Image CreateBorder(Image sourceImage, int borderSize, Color borderColor, PixelFormat targetPixelformat, Matrix matrix)
|
||||
{
|
||||
// "return" the shifted offset, so the caller can e.g. move elements
|
||||
NativePoint offset = new NativePoint(borderSize, borderSize);
|
||||
Point offset = new Point(borderSize, borderSize);
|
||||
matrix.Translate(offset.X, offset.Y, MatrixOrder.Append);
|
||||
|
||||
// Create a new "clean" image
|
||||
|
@ -1008,7 +1209,7 @@ namespace Greenshot.Base.Core
|
|||
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
|
||||
using (GraphicsPath path = new GraphicsPath())
|
||||
{
|
||||
path.AddRectangle(new NativeRect(borderSize >> 1, borderSize >> 1, newImage.Width - borderSize, newImage.Height - borderSize));
|
||||
path.AddRectangle(new Rectangle(borderSize >> 1, borderSize >> 1, newImage.Width - borderSize, newImage.Height - borderSize));
|
||||
using Pen pen = new Pen(borderColor, borderSize)
|
||||
{
|
||||
LineJoin = LineJoin.Round,
|
||||
|
@ -1088,7 +1289,7 @@ namespace Greenshot.Base.Core
|
|||
sourceImage.VerticalResolution);
|
||||
using (ImageAttributes adjustAttributes = CreateAdjustAttributes(brightness, contrast, gamma))
|
||||
{
|
||||
ApplyImageAttributes((Bitmap) sourceImage, NativeRect.Empty, newBitmap, NativeRect.Empty, adjustAttributes);
|
||||
ApplyImageAttributes((Bitmap) sourceImage, Rectangle.Empty, newBitmap, Rectangle.Empty, adjustAttributes);
|
||||
}
|
||||
|
||||
return newBitmap;
|
||||
|
@ -1154,7 +1355,7 @@ namespace Greenshot.Base.Core
|
|||
return (Image) sourceImage.Clone();
|
||||
}
|
||||
|
||||
return CloneArea(sourceImage, NativeRect.Empty, PixelFormat.DontCare);
|
||||
return CloneArea(sourceImage, Rectangle.Empty, PixelFormat.DontCare);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -1165,7 +1366,7 @@ namespace Greenshot.Base.Core
|
|||
/// <returns>Bitmap with clone image data</returns>
|
||||
public static Bitmap Clone(Image sourceBitmap, PixelFormat targetFormat)
|
||||
{
|
||||
return CloneArea(sourceBitmap, NativeRect.Empty, targetFormat);
|
||||
return CloneArea(sourceBitmap, Rectangle.Empty, targetFormat);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -1176,26 +1377,26 @@ namespace Greenshot.Base.Core
|
|||
/// 2) When going from a transparent to a non transparent bitmap, we draw the background white!
|
||||
/// </summary>
|
||||
/// <param name="sourceImage">Source bitmap to clone</param>
|
||||
/// <param name="sourceRect">NativeRect to copy from the source, use NativeRect.Empty for all</param>
|
||||
/// <param name="sourceRect">Rectangle to copy from the source, use Rectangle.Empty for all</param>
|
||||
/// <param name="targetFormat">Target Format, use PixelFormat.DontCare if you want the original (or a default if the source PixelFormat is not supported)</param>
|
||||
/// <returns></returns>
|
||||
public static Bitmap CloneArea(Image sourceImage, NativeRect sourceRect, PixelFormat targetFormat)
|
||||
public static Bitmap CloneArea(Image sourceImage, Rectangle sourceRect, PixelFormat targetFormat)
|
||||
{
|
||||
Bitmap newImage;
|
||||
NativeRect bitmapRect = new NativeRect(0, 0, sourceImage.Width, sourceImage.Height);
|
||||
Rectangle bitmapRect = new Rectangle(0, 0, sourceImage.Width, sourceImage.Height);
|
||||
|
||||
// Make sure the source is not NativeRect.Empty
|
||||
if (NativeRect.Empty.Equals(sourceRect))
|
||||
// Make sure the source is not Rectangle.Empty
|
||||
if (Rectangle.Empty.Equals(sourceRect))
|
||||
{
|
||||
sourceRect = new NativeRect(0, 0, sourceImage.Width, sourceImage.Height);
|
||||
sourceRect = new Rectangle(0, 0, sourceImage.Width, sourceImage.Height);
|
||||
}
|
||||
else
|
||||
{
|
||||
sourceRect = sourceRect.Intersect(bitmapRect);
|
||||
sourceRect.Intersect(bitmapRect);
|
||||
}
|
||||
|
||||
// If no pixelformat is supplied
|
||||
if (targetFormat is PixelFormat.DontCare or PixelFormat.Undefined)
|
||||
if (PixelFormat.DontCare == targetFormat || PixelFormat.Undefined == targetFormat)
|
||||
{
|
||||
if (SupportsPixelFormat(sourceImage.PixelFormat))
|
||||
{
|
||||
|
@ -1316,10 +1517,10 @@ namespace Greenshot.Base.Core
|
|||
/// <param name="height"></param>
|
||||
/// <param name="format"></param>
|
||||
/// <param name="backgroundColor">The color to fill with, or Color.Empty to take the default depending on the pixel format</param>
|
||||
/// <param name="horizontalResolution">float</param>
|
||||
/// <param name="verticalResolution">float</param>
|
||||
/// <param name="horizontalResolution"></param>
|
||||
/// <param name="verticalResolution"></param>
|
||||
/// <returns>Bitmap</returns>
|
||||
public static Bitmap CreateEmpty(int width, int height, PixelFormat format, Color backgroundColor, float horizontalResolution = 96f, float verticalResolution = 96f)
|
||||
public static Bitmap CreateEmpty(int width, int height, PixelFormat format, Color backgroundColor, float horizontalResolution, float verticalResolution)
|
||||
{
|
||||
// Create a new "clean" image
|
||||
Bitmap newImage = new Bitmap(width, height, format);
|
||||
|
@ -1503,113 +1704,105 @@ namespace Greenshot.Base.Core
|
|||
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
|
||||
using ImageAttributes wrapMode = new ImageAttributes();
|
||||
wrapMode.SetWrapMode(WrapMode.TileFlipXY);
|
||||
graphics.DrawImage(sourceImage, new NativeRect(destX, destY, destWidth, destHeight), 0, 0, sourceImage.Width, sourceImage.Height, GraphicsUnit.Pixel, wrapMode);
|
||||
graphics.DrawImage(sourceImage, new Rectangle(destX, destY, destWidth, destHeight), 0, 0, sourceImage.Width, sourceImage.Height, GraphicsUnit.Pixel, wrapMode);
|
||||
}
|
||||
|
||||
return newImage;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Rotate the image
|
||||
/// Load a Greenshot surface from a stream
|
||||
/// </summary>
|
||||
/// <param name="image">Input image</param>
|
||||
/// <param name="rotationAngle">Angle in degrees</param>
|
||||
/// <returns>Rotated image</returns>
|
||||
public static Image Rotate(this Image image, float rotationAngle)
|
||||
/// <param name="surfaceFileStream">Stream</param>
|
||||
/// <param name="returnSurface"></param>
|
||||
/// <returns>ISurface</returns>
|
||||
public static ISurface LoadGreenshotSurface(Stream surfaceFileStream, ISurface returnSurface)
|
||||
{
|
||||
var bitmap = CreateEmptyLike(image, Color.Transparent);
|
||||
Image fileImage;
|
||||
// Fixed problem that the bitmap stream is disposed... by Cloning the image
|
||||
// This also ensures the bitmap is correctly created
|
||||
|
||||
using var graphics = Graphics.FromImage(bitmap);
|
||||
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
|
||||
// We create a copy of the bitmap, so everything else can be disposed
|
||||
surfaceFileStream.Position = 0;
|
||||
using (Image tmpImage = Image.FromStream(surfaceFileStream, true, true))
|
||||
{
|
||||
Log.DebugFormat("Loaded .greenshot file with Size {0}x{1} and PixelFormat {2}", tmpImage.Width, tmpImage.Height, tmpImage.PixelFormat);
|
||||
fileImage = Clone(tmpImage);
|
||||
}
|
||||
|
||||
graphics.TranslateTransform((float)bitmap.Width / 2, (float)bitmap.Height / 2);
|
||||
graphics.RotateTransform(rotationAngle);
|
||||
graphics.TranslateTransform(-(float)bitmap.Width / 2, -(float)bitmap.Height / 2);
|
||||
// Start at -14 read "GreenshotXX.YY" (XX=Major, YY=Minor)
|
||||
const int markerSize = 14;
|
||||
surfaceFileStream.Seek(-markerSize, SeekOrigin.End);
|
||||
using (StreamReader streamReader = new StreamReader(surfaceFileStream))
|
||||
{
|
||||
var greenshotMarker = streamReader.ReadToEnd();
|
||||
if (!greenshotMarker.StartsWith("Greenshot"))
|
||||
{
|
||||
throw new ArgumentException("Stream is not a Greenshot file!");
|
||||
}
|
||||
|
||||
graphics.DrawImage(image, new NativePoint(0, 0));
|
||||
Log.InfoFormat("Greenshot file format: {0}", greenshotMarker);
|
||||
const int filesizeLocation = 8 + markerSize;
|
||||
surfaceFileStream.Seek(-filesizeLocation, SeekOrigin.End);
|
||||
using BinaryReader reader = new BinaryReader(surfaceFileStream);
|
||||
long bytesWritten = reader.ReadInt64();
|
||||
surfaceFileStream.Seek(-(bytesWritten + filesizeLocation), SeekOrigin.End);
|
||||
returnSurface.LoadElementsFromStream(surfaceFileStream);
|
||||
}
|
||||
|
||||
return bitmap;
|
||||
if (fileImage != null)
|
||||
{
|
||||
returnSurface.Image = fileImage;
|
||||
Log.InfoFormat("Information about .greenshot file: {0}x{1}-{2} Resolution {3}x{4}", fileImage.Width, fileImage.Height, fileImage.PixelFormat,
|
||||
fileImage.HorizontalResolution, fileImage.VerticalResolution);
|
||||
}
|
||||
|
||||
return returnSurface;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Map a System.Drawing.Imaging.PixelFormat to a System.Windows.Media.PixelFormat
|
||||
/// Create an image from a stream, if an extension is supplied more formats are supported.
|
||||
/// </summary>
|
||||
/// <param name="pixelFormat">System.Drawing.Imaging.PixelFormat</param>
|
||||
/// <returns>System.Windows.Media.PixelFormat</returns>
|
||||
/// <exception cref="NotSupportedException"></exception>
|
||||
public static System.Windows.Media.PixelFormat Map(this PixelFormat pixelFormat) =>
|
||||
pixelFormat switch
|
||||
{
|
||||
PixelFormat.Format32bppArgb => PixelFormats.Bgra32,
|
||||
PixelFormat.Format24bppRgb => PixelFormats.Bgr24,
|
||||
PixelFormat.Format32bppRgb => PixelFormats.Bgr32,
|
||||
_ => throw new NotSupportedException($"Can't map {pixelFormat}.")
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Map a System.Windows.Media.PixelFormat to a System.Drawing.Imaging.PixelFormat
|
||||
/// </summary>
|
||||
/// <param name="pixelFormat">System.Windows.Media.PixelFormat</param>
|
||||
/// <returns>System.Drawing.Imaging.PixelFormat</returns>
|
||||
/// <exception cref="NotSupportedException"></exception>
|
||||
public static PixelFormat Map(this System.Windows.Media.PixelFormat pixelFormat)
|
||||
/// <param name="stream">Stream</param>
|
||||
/// <param name="extension"></param>
|
||||
/// <returns>Image</returns>
|
||||
public static Image FromStream(Stream stream, string extension = null)
|
||||
{
|
||||
if (pixelFormat == PixelFormats.Bgra32)
|
||||
if (stream == null)
|
||||
{
|
||||
return PixelFormat.Format32bppArgb;
|
||||
}
|
||||
if (pixelFormat == PixelFormats.Bgr24)
|
||||
{
|
||||
return PixelFormat.Format24bppRgb;
|
||||
}
|
||||
if (pixelFormat == PixelFormats.Bgr32)
|
||||
{
|
||||
return PixelFormat.Format32bppRgb;
|
||||
return null;
|
||||
}
|
||||
|
||||
throw new NotSupportedException($"Can't map {pixelFormat}.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convert a Bitmap to a BitmapSource
|
||||
/// </summary>
|
||||
/// <param name="bitmap">Bitmap</param>
|
||||
/// <returns>BitmapSource</returns>
|
||||
public static BitmapSource ToBitmapSource(this Bitmap bitmap)
|
||||
{
|
||||
var bitmapData = bitmap.LockBits(new NativeRect(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadOnly, bitmap.PixelFormat);
|
||||
|
||||
BitmapSource bitmapSource;
|
||||
try
|
||||
if (!string.IsNullOrEmpty(extension))
|
||||
{
|
||||
bitmapSource = BitmapSource.Create(
|
||||
bitmapData.Width, bitmapData.Height,
|
||||
bitmap.HorizontalResolution, bitmap.VerticalResolution,
|
||||
bitmap.PixelFormat.Map(), null,
|
||||
bitmapData.Scan0, bitmapData.Stride * bitmapData.Height, bitmapData.Stride);
|
||||
}
|
||||
finally
|
||||
{
|
||||
bitmap.UnlockBits(bitmapData);
|
||||
extension = extension.Replace(".", string.Empty);
|
||||
}
|
||||
|
||||
return bitmapSource;
|
||||
}
|
||||
// Make sure we can try multiple times
|
||||
if (!stream.CanSeek)
|
||||
{
|
||||
var memoryStream = new MemoryStream();
|
||||
stream.CopyTo(memoryStream);
|
||||
stream = memoryStream;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convert a BitmapSource to a Bitmap
|
||||
/// </summary>
|
||||
/// <param name="bitmapSource">BitmapSource</param>
|
||||
/// <returns>Bitmap</returns>
|
||||
public static Bitmap ToBitmap(this BitmapSource bitmapSource)
|
||||
{
|
||||
var pixelFormat = bitmapSource.Format.Map();
|
||||
Image returnImage = null;
|
||||
if (StreamConverters.TryGetValue(extension ?? string.Empty, out var converter))
|
||||
{
|
||||
returnImage = converter(stream, extension);
|
||||
}
|
||||
|
||||
Bitmap bitmap = new Bitmap(bitmapSource.PixelWidth, bitmapSource.PixelHeight, pixelFormat);
|
||||
BitmapData data = bitmap.LockBits(new NativeRect(NativePoint.Empty, bitmap.Size), ImageLockMode.WriteOnly, pixelFormat);
|
||||
bitmapSource.CopyPixels(Int32Rect.Empty, data.Scan0, data.Height * data.Stride, data.Stride);
|
||||
bitmap.UnlockBits(data);
|
||||
return bitmap;
|
||||
// Fallback
|
||||
if (returnImage == null)
|
||||
{
|
||||
// We create a copy of the bitmap, so everything else can be disposed
|
||||
stream.Position = 0;
|
||||
using var tmpImage = Image.FromStream(stream, true, true);
|
||||
Log.DebugFormat("Loaded bitmap with Size {0}x{1} and PixelFormat {2}", tmpImage.Width, tmpImage.Height, tmpImage.PixelFormat);
|
||||
returnImage = Clone(tmpImage, PixelFormat.Format32bppArgb);
|
||||
}
|
||||
|
||||
return returnImage;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -20,11 +20,12 @@
|
|||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Drawing2D;
|
||||
using System.Drawing.Imaging;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
@ -32,20 +33,20 @@ using System.Text.RegularExpressions;
|
|||
using System.Windows.Forms;
|
||||
using Greenshot.Base.Controls;
|
||||
using Greenshot.Base.Core.Enums;
|
||||
using Greenshot.Base.Core.FileFormatHandlers;
|
||||
using Greenshot.Base.IniFile;
|
||||
using Greenshot.Base.Interfaces;
|
||||
using Greenshot.Base.Interfaces.Plugin;
|
||||
using log4net;
|
||||
using Encoder = System.Drawing.Imaging.Encoder;
|
||||
|
||||
namespace Greenshot.Base.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// This contains all io related logic for image
|
||||
/// Description of ImageOutput.
|
||||
/// </summary>
|
||||
public static class ImageIO
|
||||
public static class ImageOutput
|
||||
{
|
||||
private static readonly ILog Log = LogManager.GetLogger(typeof(ImageIO));
|
||||
private static readonly ILog Log = LogManager.GetLogger(typeof(ImageOutput));
|
||||
private static readonly CoreConfiguration CoreConfig = IniConfig.GetIniSection<CoreConfiguration>();
|
||||
private static readonly int PROPERTY_TAG_SOFTWARE_USED = 0x0131;
|
||||
private static readonly Cache<string, string> TmpFileCache = new Cache<string, string>(10 * 60 * 60, RemoveExpiredTmpFile);
|
||||
|
@ -53,7 +54,7 @@ namespace Greenshot.Base.Core
|
|||
/// <summary>
|
||||
/// Creates a PropertyItem (Metadata) to store with the image.
|
||||
/// For the possible ID's see: https://msdn.microsoft.com/de-de/library/system.drawing.imaging.propertyitem.id(v=vs.80).aspx
|
||||
/// This code uses Reflection to create a PropertyItem, although it's not advised it's not as stupid as having a image in the project so we can read a PropertyItem from that!
|
||||
/// This code uses Reflection to create a PropertyItem, although it's not adviced it's not as stupid as having a image in the project so we can read a PropertyItem from that!
|
||||
/// </summary>
|
||||
/// <param name="id">ID</param>
|
||||
/// <param name="text">Text</param>
|
||||
|
@ -123,21 +124,102 @@ namespace Greenshot.Base.Core
|
|||
|
||||
try
|
||||
{
|
||||
// Check if we want to use a memory stream, to prevent issues with non seekable streams
|
||||
var imageFormat = outputSettings.Format switch
|
||||
{
|
||||
OutputFormat.bmp => ImageFormat.Bmp,
|
||||
OutputFormat.gif => ImageFormat.Gif,
|
||||
OutputFormat.jpg => ImageFormat.Jpeg,
|
||||
OutputFormat.tiff => ImageFormat.Tiff,
|
||||
OutputFormat.ico => ImageFormat.Icon,
|
||||
_ => ImageFormat.Png
|
||||
};
|
||||
Log.DebugFormat("Saving image to stream with Format {0} and PixelFormat {1}", imageFormat, imageToSave.PixelFormat);
|
||||
|
||||
// Check if we want to use a memory stream, to prevent issues with non seakable streams
|
||||
// The save is made to the targetStream, this is directed to either the MemoryStream or the original
|
||||
Stream targetStream = stream;
|
||||
if (!stream.CanSeek)
|
||||
{
|
||||
useMemoryStream = true;
|
||||
Log.Warn("Using a memory stream prevent an issue with saving to a non seekable stream.");
|
||||
Log.Warn("Using memorystream prevent an issue with saving to a non seekable stream.");
|
||||
memoryStream = new MemoryStream();
|
||||
targetStream = memoryStream;
|
||||
}
|
||||
|
||||
var fileFormatHandlers = SimpleServiceProvider.Current.GetAllInstances<IFileFormatHandler>();
|
||||
if (!fileFormatHandlers.TrySaveToStream(imageToSave as Bitmap, targetStream, outputSettings.Format.ToString(), surface, outputSettings))
|
||||
if (Equals(imageFormat, ImageFormat.Jpeg))
|
||||
{
|
||||
return;
|
||||
bool foundEncoder = false;
|
||||
foreach (ImageCodecInfo imageCodec in ImageCodecInfo.GetImageEncoders())
|
||||
{
|
||||
if (imageCodec.FormatID == imageFormat.Guid)
|
||||
{
|
||||
EncoderParameters parameters = new EncoderParameters(1)
|
||||
{
|
||||
Param =
|
||||
{
|
||||
[0] = new EncoderParameter(Encoder.Quality, outputSettings.JPGQuality)
|
||||
}
|
||||
};
|
||||
// Removing transparency if it's not supported in the output
|
||||
if (Image.IsAlphaPixelFormat(imageToSave.PixelFormat))
|
||||
{
|
||||
Image nonAlphaImage = ImageHelper.Clone(imageToSave, PixelFormat.Format24bppRgb);
|
||||
AddTag(nonAlphaImage);
|
||||
nonAlphaImage.Save(targetStream, imageCodec, parameters);
|
||||
nonAlphaImage.Dispose();
|
||||
}
|
||||
else
|
||||
{
|
||||
AddTag(imageToSave);
|
||||
imageToSave.Save(targetStream, imageCodec, parameters);
|
||||
}
|
||||
|
||||
foundEncoder = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!foundEncoder)
|
||||
{
|
||||
throw new ApplicationException("No JPG encoder found, this should not happen.");
|
||||
}
|
||||
}
|
||||
else if (Equals(imageFormat, ImageFormat.Icon))
|
||||
{
|
||||
// FEATURE-916: Added Icon support
|
||||
IList<Image> images = new List<Image>
|
||||
{
|
||||
imageToSave
|
||||
};
|
||||
WriteIcon(stream, images);
|
||||
}
|
||||
else
|
||||
{
|
||||
bool needsDispose = false;
|
||||
// Removing transparency if it's not supported in the output
|
||||
if (!Equals(imageFormat, ImageFormat.Png) && Image.IsAlphaPixelFormat(imageToSave.PixelFormat))
|
||||
{
|
||||
imageToSave = ImageHelper.Clone(imageToSave, PixelFormat.Format24bppRgb);
|
||||
needsDispose = true;
|
||||
}
|
||||
|
||||
AddTag(imageToSave);
|
||||
// Added for OptiPNG
|
||||
bool processed = false;
|
||||
if (Equals(imageFormat, ImageFormat.Png) && !string.IsNullOrEmpty(CoreConfig.OptimizePNGCommand))
|
||||
{
|
||||
processed = ProcessPngImageExternally(imageToSave, targetStream);
|
||||
}
|
||||
|
||||
if (!processed)
|
||||
{
|
||||
imageToSave.Save(targetStream, imageFormat);
|
||||
}
|
||||
|
||||
if (needsDispose)
|
||||
{
|
||||
imageToSave.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
// If we used a memory stream, we need to stream the memory stream to the original stream.
|
||||
|
@ -145,6 +227,21 @@ namespace Greenshot.Base.Core
|
|||
{
|
||||
memoryStream.WriteTo(stream);
|
||||
}
|
||||
|
||||
// Output the surface elements, size and marker to the stream
|
||||
if (outputSettings.Format != OutputFormat.greenshot)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
using MemoryStream tmpStream = new MemoryStream();
|
||||
long bytesWritten = surface.SaveElementsToStream(tmpStream);
|
||||
using BinaryWriter writer = new BinaryWriter(tmpStream);
|
||||
writer.Write(bytesWritten);
|
||||
Version v = Assembly.GetExecutingAssembly().GetName().Version;
|
||||
byte[] marker = Encoding.ASCII.GetBytes($"Greenshot{v.Major:00}.{v.Minor:00}");
|
||||
writer.Write(marker);
|
||||
tmpStream.WriteTo(stream);
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
@ -152,6 +249,89 @@ namespace Greenshot.Base.Core
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write the passed Image to a tmp-file and call an external process, than read the file back and write it to the targetStream
|
||||
/// </summary>
|
||||
/// <param name="imageToProcess">Image to pass to the external process</param>
|
||||
/// <param name="targetStream">stream to write the processed image to</param>
|
||||
/// <returns></returns>
|
||||
private static bool ProcessPngImageExternally(Image imageToProcess, Stream targetStream)
|
||||
{
|
||||
if (string.IsNullOrEmpty(CoreConfig.OptimizePNGCommand))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!File.Exists(CoreConfig.OptimizePNGCommand))
|
||||
{
|
||||
Log.WarnFormat("Can't find 'OptimizePNGCommand' {0}", CoreConfig.OptimizePNGCommand);
|
||||
return false;
|
||||
}
|
||||
|
||||
string tmpFileName = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName() + ".png");
|
||||
try
|
||||
{
|
||||
using (FileStream tmpStream = File.Create(tmpFileName))
|
||||
{
|
||||
Log.DebugFormat("Writing png to tmp file: {0}", tmpFileName);
|
||||
imageToProcess.Save(tmpStream, ImageFormat.Png);
|
||||
if (Log.IsDebugEnabled)
|
||||
{
|
||||
Log.DebugFormat("File size before processing {0}", new FileInfo(tmpFileName).Length);
|
||||
}
|
||||
}
|
||||
|
||||
if (Log.IsDebugEnabled)
|
||||
{
|
||||
Log.DebugFormat("Starting : {0}", CoreConfig.OptimizePNGCommand);
|
||||
}
|
||||
|
||||
ProcessStartInfo processStartInfo = new ProcessStartInfo(CoreConfig.OptimizePNGCommand)
|
||||
{
|
||||
Arguments = string.Format(CoreConfig.OptimizePNGCommandArguments, tmpFileName),
|
||||
CreateNoWindow = true,
|
||||
RedirectStandardOutput = true,
|
||||
RedirectStandardError = true,
|
||||
UseShellExecute = false
|
||||
};
|
||||
using Process process = Process.Start(processStartInfo);
|
||||
if (process != null)
|
||||
{
|
||||
process.WaitForExit();
|
||||
if (process.ExitCode == 0)
|
||||
{
|
||||
if (Log.IsDebugEnabled)
|
||||
{
|
||||
Log.DebugFormat("File size after processing {0}", new FileInfo(tmpFileName).Length);
|
||||
Log.DebugFormat("Reading back tmp file: {0}", tmpFileName);
|
||||
}
|
||||
|
||||
byte[] processedImage = File.ReadAllBytes(tmpFileName);
|
||||
targetStream.Write(processedImage, 0, processedImage.Length);
|
||||
return true;
|
||||
}
|
||||
|
||||
Log.ErrorFormat("Error while processing PNG image: {0}", process.ExitCode);
|
||||
Log.ErrorFormat("Output: {0}", process.StandardOutput.ReadToEnd());
|
||||
Log.ErrorFormat("Error: {0}", process.StandardError.ReadToEnd());
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error("Error while processing PNG image: ", e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (File.Exists(tmpFileName))
|
||||
{
|
||||
Log.DebugFormat("Cleaning up tmp file: {0}", tmpFileName);
|
||||
File.Delete(tmpFileName);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create an image from a surface with the settings from the output settings applied
|
||||
/// </summary>
|
||||
|
@ -249,18 +429,20 @@ namespace Greenshot.Base.Core
|
|||
/// Add the greenshot property!
|
||||
/// </summary>
|
||||
/// <param name="imageToSave"></param>
|
||||
public static void AddTag(this Image imageToSave)
|
||||
private static void AddTag(Image imageToSave)
|
||||
{
|
||||
// Create meta-data
|
||||
PropertyItem softwareUsedPropertyItem = CreatePropertyItem(PROPERTY_TAG_SOFTWARE_USED, "Greenshot");
|
||||
if (softwareUsedPropertyItem == null) return;
|
||||
try
|
||||
if (softwareUsedPropertyItem != null)
|
||||
{
|
||||
imageToSave.SetPropertyItem(softwareUsedPropertyItem);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
Log.WarnFormat("Couldn't set property {0}", softwareUsedPropertyItem.Id);
|
||||
try
|
||||
{
|
||||
imageToSave.SetPropertyItem(softwareUsedPropertyItem);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
Log.WarnFormat("Couldn't set property {0}", softwareUsedPropertyItem.Id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -281,7 +463,7 @@ namespace Greenshot.Base.Core
|
|||
// Fixed lock problem Bug #3431881
|
||||
using (Stream surfaceFileStream = File.OpenRead(fullPath))
|
||||
{
|
||||
returnSurface = LoadGreenshotSurface(surfaceFileStream, returnSurface);
|
||||
returnSurface = ImageHelper.LoadGreenshotSurface(surfaceFileStream, returnSurface);
|
||||
}
|
||||
|
||||
if (returnSurface != null)
|
||||
|
@ -365,25 +547,27 @@ namespace Greenshot.Base.Core
|
|||
using (SaveImageFileDialog saveImageFileDialog = new SaveImageFileDialog(captureDetails))
|
||||
{
|
||||
DialogResult dialogResult = saveImageFileDialog.ShowDialog();
|
||||
if (!dialogResult.Equals(DialogResult.OK)) return returnValue;
|
||||
try
|
||||
if (dialogResult.Equals(DialogResult.OK))
|
||||
{
|
||||
string fileNameWithExtension = saveImageFileDialog.FileNameWithExtension;
|
||||
SurfaceOutputSettings outputSettings = new SurfaceOutputSettings(FormatForFilename(fileNameWithExtension));
|
||||
if (CoreConfig.OutputFilePromptQuality)
|
||||
try
|
||||
{
|
||||
QualityDialog qualityDialog = new QualityDialog(outputSettings);
|
||||
qualityDialog.ShowDialog();
|
||||
}
|
||||
string fileNameWithExtension = saveImageFileDialog.FileNameWithExtension;
|
||||
SurfaceOutputSettings outputSettings = new SurfaceOutputSettings(FormatForFilename(fileNameWithExtension));
|
||||
if (CoreConfig.OutputFilePromptQuality)
|
||||
{
|
||||
QualityDialog qualityDialog = new QualityDialog(outputSettings);
|
||||
qualityDialog.ShowDialog();
|
||||
}
|
||||
|
||||
// TODO: For now we always overwrite, should be changed
|
||||
Save(surface, fileNameWithExtension, true, outputSettings, CoreConfig.OutputFileCopyPathToClipboard);
|
||||
returnValue = fileNameWithExtension;
|
||||
IniConfig.Save();
|
||||
}
|
||||
catch (ExternalException)
|
||||
{
|
||||
MessageBox.Show(Language.GetFormattedString("error_nowriteaccess", saveImageFileDialog.FileName).Replace(@"\\", @"\"), Language.GetString("error"));
|
||||
// TODO: For now we always overwrite, should be changed
|
||||
Save(surface, fileNameWithExtension, true, outputSettings, CoreConfig.OutputFileCopyPathToClipboard);
|
||||
returnValue = fileNameWithExtension;
|
||||
IniConfig.Save();
|
||||
}
|
||||
catch (ExternalException)
|
||||
{
|
||||
MessageBox.Show(Language.GetFormattedString("error_nowriteaccess", saveImageFileDialog.FileName).Replace(@"\\", @"\"), Language.GetString("error"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -525,131 +709,91 @@ namespace Greenshot.Base.Core
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Load an image from file
|
||||
/// Write the images to the stream as icon
|
||||
/// Every image is resized to 256x256 (but the content maintains the aspect ratio)
|
||||
/// </summary>
|
||||
/// <param name="filename"></param>
|
||||
/// <returns></returns>
|
||||
public static Image LoadImage(string filename)
|
||||
/// <param name="stream">Stream to write to</param>
|
||||
/// <param name="images">List of images</param>
|
||||
public static void WriteIcon(Stream stream, IList<Image> images)
|
||||
{
|
||||
if (string.IsNullOrEmpty(filename))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
var binaryWriter = new BinaryWriter(stream);
|
||||
//
|
||||
// ICONDIR structure
|
||||
//
|
||||
binaryWriter.Write((short) 0); // reserved
|
||||
binaryWriter.Write((short) 1); // image type (icon)
|
||||
binaryWriter.Write((short) images.Count); // number of images
|
||||
|
||||
if (!File.Exists(filename))
|
||||
IList<Size> imageSizes = new List<Size>();
|
||||
IList<MemoryStream> encodedImages = new List<MemoryStream>();
|
||||
foreach (var image in images)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
Image fileImage;
|
||||
Log.InfoFormat("Loading image from file {0}", filename);
|
||||
// Fixed lock problem Bug #3431881
|
||||
using (Stream imageFileStream = File.OpenRead(filename))
|
||||
{
|
||||
fileImage = FromStream(imageFileStream, Path.GetExtension(filename));
|
||||
}
|
||||
|
||||
if (fileImage != null)
|
||||
{
|
||||
Log.InfoFormat("Information about file {0}: {1}x{2}-{3} Resolution {4}x{5}", filename, fileImage.Width, fileImage.Height, fileImage.PixelFormat,
|
||||
fileImage.HorizontalResolution, fileImage.VerticalResolution);
|
||||
}
|
||||
|
||||
return fileImage;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create an image from a stream, if an extension is supplied more formats are supported.
|
||||
/// </summary>
|
||||
/// <param name="stream">Stream</param>
|
||||
/// <param name="extension"></param>
|
||||
/// <returns>Image</returns>
|
||||
public static Image FromStream(Stream stream, string extension = null)
|
||||
{
|
||||
if (stream == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(extension))
|
||||
{
|
||||
extension = extension.Replace(".", string.Empty);
|
||||
}
|
||||
|
||||
var startingPosition = stream.Position;
|
||||
|
||||
// Make sure we can try multiple times
|
||||
if (!stream.CanSeek)
|
||||
{
|
||||
var memoryStream = new MemoryStream();
|
||||
stream.CopyTo(memoryStream);
|
||||
stream = memoryStream;
|
||||
// As we are if a different stream, which starts at 0, change the starting position
|
||||
startingPosition = 0;
|
||||
}
|
||||
var fileFormatHandlers = SimpleServiceProvider.Current.GetAllInstances<IFileFormatHandler>();
|
||||
foreach (var fileFormatHandler in fileFormatHandlers
|
||||
.Where(ffh => ffh.Supports(FileFormatHandlerActions.LoadFromStream, extension))
|
||||
.OrderBy(ffh => ffh.PriorityFor(FileFormatHandlerActions.LoadFromStream, extension)))
|
||||
{
|
||||
stream.Seek(startingPosition, SeekOrigin.Begin);
|
||||
if (fileFormatHandler.TryLoadFromStream(stream, extension, out var bitmap))
|
||||
// Pick the best fit
|
||||
var sizes = new[]
|
||||
{
|
||||
return bitmap;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Load a Greenshot surface from a stream
|
||||
/// </summary>
|
||||
/// <param name="surfaceFileStream">Stream</param>
|
||||
/// <param name="returnSurface"></param>
|
||||
/// <returns>ISurface</returns>
|
||||
public static ISurface LoadGreenshotSurface(Stream surfaceFileStream, ISurface returnSurface)
|
||||
{
|
||||
Image fileImage;
|
||||
// Fixed problem that the bitmap stream is disposed... by Cloning the image
|
||||
// This also ensures the bitmap is correctly created
|
||||
|
||||
// We create a copy of the bitmap, so everything else can be disposed
|
||||
surfaceFileStream.Position = 0;
|
||||
using (Image tmpImage = Image.FromStream(surfaceFileStream, true, true))
|
||||
{
|
||||
Log.DebugFormat("Loaded .greenshot file with Size {0}x{1} and PixelFormat {2}", tmpImage.Width, tmpImage.Height, tmpImage.PixelFormat);
|
||||
fileImage = ImageHelper.Clone(tmpImage);
|
||||
}
|
||||
|
||||
// Start at -14 read "GreenshotXX.YY" (XX=Major, YY=Minor)
|
||||
const int markerSize = 14;
|
||||
surfaceFileStream.Seek(-markerSize, SeekOrigin.End);
|
||||
using (StreamReader streamReader = new StreamReader(surfaceFileStream))
|
||||
{
|
||||
var greenshotMarker = streamReader.ReadToEnd();
|
||||
if (!greenshotMarker.StartsWith("Greenshot"))
|
||||
16, 32, 48
|
||||
};
|
||||
int size = 256;
|
||||
foreach (var possibleSize in sizes)
|
||||
{
|
||||
throw new ArgumentException("Stream is not a Greenshot file!");
|
||||
if (image.Width <= possibleSize && image.Height <= possibleSize)
|
||||
{
|
||||
size = possibleSize;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Log.InfoFormat("Greenshot file format: {0}", greenshotMarker);
|
||||
const int filesizeLocation = 8 + markerSize;
|
||||
surfaceFileStream.Seek(-filesizeLocation, SeekOrigin.End);
|
||||
using BinaryReader reader = new BinaryReader(surfaceFileStream);
|
||||
long bytesWritten = reader.ReadInt64();
|
||||
surfaceFileStream.Seek(-(bytesWritten + filesizeLocation), SeekOrigin.End);
|
||||
returnSurface.LoadElementsFromStream(surfaceFileStream);
|
||||
var imageStream = new MemoryStream();
|
||||
if (image.Width == size && image.Height == size)
|
||||
{
|
||||
using var clonedImage = ImageHelper.Clone(image, PixelFormat.Format32bppArgb);
|
||||
clonedImage.Save(imageStream, ImageFormat.Png);
|
||||
imageSizes.Add(new Size(size, size));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Resize to the specified size, first make sure the image is 32bpp
|
||||
using var clonedImage = ImageHelper.Clone(image, PixelFormat.Format32bppArgb);
|
||||
using var resizedImage = ImageHelper.ResizeImage(clonedImage, true, true, Color.Empty, size, size, null);
|
||||
resizedImage.Save(imageStream, ImageFormat.Png);
|
||||
imageSizes.Add(resizedImage.Size);
|
||||
}
|
||||
|
||||
imageStream.Seek(0, SeekOrigin.Begin);
|
||||
encodedImages.Add(imageStream);
|
||||
}
|
||||
|
||||
if (fileImage != null)
|
||||
//
|
||||
// ICONDIRENTRY structure
|
||||
//
|
||||
const int iconDirSize = 6;
|
||||
const int iconDirEntrySize = 16;
|
||||
|
||||
var offset = iconDirSize + (images.Count * iconDirEntrySize);
|
||||
for (int i = 0; i < images.Count; i++)
|
||||
{
|
||||
returnSurface.Image = fileImage;
|
||||
Log.InfoFormat("Information about .greenshot file: {0}x{1}-{2} Resolution {3}x{4}", fileImage.Width, fileImage.Height, fileImage.PixelFormat,
|
||||
fileImage.HorizontalResolution, fileImage.VerticalResolution);
|
||||
var imageSize = imageSizes[i];
|
||||
// Write the width / height, 0 means 256
|
||||
binaryWriter.Write(imageSize.Width == 256 ? (byte) 0 : (byte) imageSize.Width);
|
||||
binaryWriter.Write(imageSize.Height == 256 ? (byte) 0 : (byte) imageSize.Height);
|
||||
binaryWriter.Write((byte) 0); // no pallete
|
||||
binaryWriter.Write((byte) 0); // reserved
|
||||
binaryWriter.Write((short) 0); // no color planes
|
||||
binaryWriter.Write((short) 32); // 32 bpp
|
||||
binaryWriter.Write((int) encodedImages[i].Length); // image data length
|
||||
binaryWriter.Write(offset);
|
||||
offset += (int) encodedImages[i].Length;
|
||||
}
|
||||
|
||||
return returnSurface;
|
||||
binaryWriter.Flush();
|
||||
//
|
||||
// Write image data
|
||||
//
|
||||
foreach (var encodedImage in encodedImages)
|
||||
{
|
||||
encodedImage.WriteTo(stream);
|
||||
encodedImage.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
77
src/Greenshot.Base/Core/ImageWrapper.cs
Normal file
77
src/Greenshot.Base/Core/ImageWrapper.cs
Normal file
|
@ -0,0 +1,77 @@
|
|||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
|
||||
namespace Greenshot.Base.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Wrap an image, make it resizeable
|
||||
/// </summary>
|
||||
public class ImageWrapper : IImage
|
||||
{
|
||||
// Underlying image, is used to generate a resized version of it when needed
|
||||
private readonly Image _image;
|
||||
private Image _imageClone;
|
||||
|
||||
public ImageWrapper(Image image)
|
||||
{
|
||||
// Make sure the orientation is set correctly so Greenshot can process the image correctly
|
||||
ImageHelper.Orientate(image);
|
||||
_image = image;
|
||||
Width = _image.Width;
|
||||
Height = _image.Height;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_image.Dispose();
|
||||
_imageClone?.Dispose();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Height of the image, can be set to change
|
||||
/// </summary>
|
||||
public int Height { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Width of the image, can be set to change.
|
||||
/// </summary>
|
||||
public int Width { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Size of the image
|
||||
/// </summary>
|
||||
public Size Size => new Size(Width, Height);
|
||||
|
||||
/// <summary>
|
||||
/// Pixelformat of the underlying image
|
||||
/// </summary>
|
||||
public PixelFormat PixelFormat => Image.PixelFormat;
|
||||
|
||||
public float HorizontalResolution => Image.HorizontalResolution;
|
||||
public float VerticalResolution => Image.VerticalResolution;
|
||||
|
||||
public Image Image
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_imageClone == null)
|
||||
{
|
||||
if (_image.Height == Height && _image.Width == Width)
|
||||
{
|
||||
return _image;
|
||||
}
|
||||
}
|
||||
|
||||
if (_imageClone?.Height == Height && _imageClone?.Width == Width)
|
||||
{
|
||||
return _imageClone;
|
||||
}
|
||||
|
||||
// Calculate new image clone
|
||||
_imageClone?.Dispose();
|
||||
_imageClone = ImageHelper.ResizeImage(_image, false, Width, Height, null);
|
||||
return _imageClone;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -470,7 +470,7 @@ namespace Greenshot.Base.Core
|
|||
languageFile
|
||||
};
|
||||
LanguageFiles.Add(languageFile.Ietf, currentFiles);
|
||||
Log.DebugFormat("Added language definition {0} from: {1}", languageFile.Description, languageFile.Filepath);
|
||||
Log.InfoFormat("Added language definition {0} from: {1}", languageFile.Description, languageFile.Filepath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,14 +24,11 @@ using System.Collections.Generic;
|
|||
using System.Drawing;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using Greenshot.Base.Core.FileFormatHandlers;
|
||||
using Greenshot.Base.IniFile;
|
||||
using Greenshot.Base.Interfaces;
|
||||
using Greenshot.Base.Interfaces.Drawing;
|
||||
using Greenshot.Base.Interfaces.Plugin;
|
||||
using log4net;
|
||||
|
||||
|
@ -90,77 +87,24 @@ namespace Greenshot.Base.Core
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Download the uri to build an IDrawableContainer
|
||||
/// </summary>
|
||||
/// <param name="url">Of an image</param>
|
||||
/// <returns>IDrawableContainer</returns>
|
||||
public static IDrawableContainer DownloadImageAsDrawableContainer(string url)
|
||||
{
|
||||
var fileFormatHandlers = SimpleServiceProvider.Current.GetAllInstances<IFileFormatHandler>();
|
||||
var extensions = string.Join("|", fileFormatHandlers.ExtensionsFor(FileFormatHandlerActions.LoadFromStream));
|
||||
|
||||
var imageUrlRegex = new Regex($@"(http|https)://.*(?<extension>{extensions})");
|
||||
var match = imageUrlRegex.Match(url);
|
||||
try
|
||||
{
|
||||
using var memoryStream = GetAsMemoryStream(url);
|
||||
try
|
||||
{
|
||||
var extension = match.Success ? match.Groups["extension"]?.Value : null;
|
||||
var drawableContainer = fileFormatHandlers.LoadDrawablesFromStream(memoryStream, extension).FirstOrDefault();
|
||||
if (drawableContainer != null)
|
||||
{
|
||||
return drawableContainer;
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// If we arrive here, the image loading didn't work, try to see if the response has a http(s) URL to an image and just take this instead.
|
||||
string content;
|
||||
using (var streamReader = new StreamReader(memoryStream, Encoding.UTF8, true))
|
||||
{
|
||||
content = streamReader.ReadLine();
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(content))
|
||||
{
|
||||
throw;
|
||||
}
|
||||
|
||||
match = imageUrlRegex.Match(content);
|
||||
if (!match.Success)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
|
||||
using var memoryStream2 = GetAsMemoryStream(match.Value);
|
||||
|
||||
var extension = match.Success ? match.Groups["extension"]?.Value : null;
|
||||
var drawableContainer = fileFormatHandlers.LoadDrawablesFromStream(memoryStream2, extension).FirstOrDefault();
|
||||
if (drawableContainer != null)
|
||||
{
|
||||
return drawableContainer;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error("Problem downloading the image from: " + url, e);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Download the uri to create a Bitmap
|
||||
/// Download the uri to Bitmap
|
||||
/// </summary>
|
||||
/// <param name="url">Of an image</param>
|
||||
/// <returns>Bitmap</returns>
|
||||
public static Bitmap DownloadImage(string url)
|
||||
public static Image DownloadImage(string url)
|
||||
{
|
||||
var fileFormatHandlers = SimpleServiceProvider.Current.GetAllInstances<IFileFormatHandler>();
|
||||
var extensions = new StringBuilder();
|
||||
foreach (var extension in ImageHelper.StreamConverters.Keys)
|
||||
{
|
||||
if (string.IsNullOrEmpty(extension))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var extensions = string.Join("|", fileFormatHandlers.ExtensionsFor(FileFormatHandlerActions.LoadFromStream));
|
||||
extensions.AppendFormat(@"\.{0}|", extension);
|
||||
}
|
||||
|
||||
extensions.Length--;
|
||||
|
||||
var imageUrlRegex = new Regex($@"(http|https)://.*(?<extension>{extensions})");
|
||||
var match = imageUrlRegex.Match(url);
|
||||
|
@ -169,10 +113,7 @@ namespace Greenshot.Base.Core
|
|||
using var memoryStream = GetAsMemoryStream(url);
|
||||
try
|
||||
{
|
||||
if (fileFormatHandlers.TryLoadFromStream(memoryStream, match.Success ? match.Groups["extension"]?.Value : null, out var bitmap))
|
||||
{
|
||||
return bitmap;
|
||||
}
|
||||
return ImageHelper.FromStream(memoryStream, match.Success ? match.Groups["extension"]?.Value : null);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
|
@ -195,10 +136,7 @@ namespace Greenshot.Base.Core
|
|||
}
|
||||
|
||||
using var memoryStream2 = GetAsMemoryStream(match.Value);
|
||||
if (fileFormatHandlers.TryLoadFromStream(memoryStream2, match.Success ? match.Groups["extension"]?.Value : null, out var bitmap))
|
||||
{
|
||||
return bitmap;
|
||||
}
|
||||
return ImageHelper.FromStream(memoryStream2, match.Groups["extension"]?.Value);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
|
@ -732,7 +670,7 @@ namespace Greenshot.Base.Core
|
|||
public string ToBase64String(Base64FormattingOptions formattingOptions)
|
||||
{
|
||||
using MemoryStream stream = new MemoryStream();
|
||||
ImageIO.SaveToStream(_surface, stream, _outputSettings);
|
||||
ImageOutput.SaveToStream(_surface, stream, _outputSettings);
|
||||
return Convert.ToBase64String(stream.GetBuffer(), 0, (int) stream.Length, formattingOptions);
|
||||
}
|
||||
|
||||
|
@ -744,7 +682,7 @@ namespace Greenshot.Base.Core
|
|||
public byte[] ToByteArray()
|
||||
{
|
||||
using MemoryStream stream = new MemoryStream();
|
||||
ImageIO.SaveToStream(_surface, stream, _outputSettings);
|
||||
ImageOutput.SaveToStream(_surface, stream, _outputSettings);
|
||||
return stream.ToArray();
|
||||
}
|
||||
|
||||
|
@ -760,7 +698,7 @@ namespace Greenshot.Base.Core
|
|||
string header = $"--{boundary}\r\nContent-Disposition: form-data; name=\"{name}\"; filename=\"{Filename ?? name}\";\r\nContent-Type: {ContentType}\r\n\r\n";
|
||||
|
||||
formDataStream.Write(Encoding.UTF8.GetBytes(header), 0, Encoding.UTF8.GetByteCount(header));
|
||||
ImageIO.SaveToStream(_surface, formDataStream, _outputSettings);
|
||||
ImageOutput.SaveToStream(_surface, formDataStream, _outputSettings);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -770,7 +708,7 @@ namespace Greenshot.Base.Core
|
|||
public void WriteToStream(Stream dataStream)
|
||||
{
|
||||
// Write the file data directly to the Stream, rather than serializing it to a string.
|
||||
ImageIO.SaveToStream(_surface, dataStream, _outputSettings);
|
||||
ImageOutput.SaveToStream(_surface, dataStream, _outputSettings);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -24,10 +24,9 @@ using System.Collections.Generic;
|
|||
using System.ComponentModel;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Windows.Forms;
|
||||
using Dapplo.Windows.Icons;
|
||||
using Greenshot.Base.IniFile;
|
||||
using Greenshot.Base.UnmanagedHelpers;
|
||||
using log4net;
|
||||
using Microsoft.Win32;
|
||||
|
||||
|
@ -40,8 +39,8 @@ namespace Greenshot.Base.Core
|
|||
{
|
||||
private static readonly ILog Log = LogManager.GetLogger(typeof(PluginUtils));
|
||||
private static readonly CoreConfiguration CoreConfig = IniConfig.GetIniSection<CoreConfiguration>();
|
||||
private static readonly IDictionary<string, Image> ExeIconCache = new Dictionary<string, Image>();
|
||||
private const string PathKey = @"SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\";
|
||||
private static readonly IDictionary<string, Image> ExeIconCache = new Dictionary<string, Image>();
|
||||
|
||||
static PluginUtils()
|
||||
{
|
||||
|
@ -85,7 +84,7 @@ namespace Greenshot.Base.Core
|
|||
if (key != null)
|
||||
{
|
||||
// "" is the default key, which should point to the requested location
|
||||
return (string)key.GetValue(string.Empty);
|
||||
return (string) key.GetValue(string.Empty);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -114,7 +113,7 @@ namespace Greenshot.Base.Core
|
|||
/// </summary>
|
||||
/// <param name="path">path to the exe or dll</param>
|
||||
/// <param name="index">index of the icon</param>
|
||||
/// <returns>Bitmap with the icon or null if something happened</returns>
|
||||
/// <returns>Bitmap with the icon or null if something happended</returns>
|
||||
public static Image GetCachedExeIcon(string path, int index)
|
||||
{
|
||||
string cacheKey = $"{path}:{index}";
|
||||
|
@ -149,7 +148,7 @@ namespace Greenshot.Base.Core
|
|||
/// </summary>
|
||||
/// <param name="path">path to the exe or dll</param>
|
||||
/// <param name="index">index of the icon</param>
|
||||
/// <returns>Bitmap with the icon or null if something happened</returns>
|
||||
/// <returns>Bitmap with the icon or null if something happended</returns>
|
||||
private static Bitmap GetExeIcon(string path, int index)
|
||||
{
|
||||
if (!File.Exists(path))
|
||||
|
@ -159,11 +158,20 @@ namespace Greenshot.Base.Core
|
|||
|
||||
try
|
||||
{
|
||||
var appIcon = IconHelper.ExtractAssociatedIcon<Bitmap>(path, index, CoreConfig.UseLargeIcons);
|
||||
if (appIcon != null)
|
||||
using (Icon appIcon = ImageHelper.ExtractAssociatedIcon(path, index, CoreConfig.UseLargeIcons))
|
||||
{
|
||||
Log.DebugFormat("Loaded icon for {0}, with dimensions {1}x{2}", path, appIcon.Width, appIcon.Height);
|
||||
return appIcon;
|
||||
if (appIcon != null)
|
||||
{
|
||||
return appIcon.ToBitmap();
|
||||
}
|
||||
}
|
||||
|
||||
using (Icon appIcon = Shell32.GetFileIcon(path, CoreConfig.UseLargeIcons ? Shell32.IconSize.Large : Shell32.IconSize.Small, false))
|
||||
{
|
||||
if (appIcon != null)
|
||||
{
|
||||
return appIcon.ToBitmap();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception exIcon)
|
||||
|
@ -187,25 +195,27 @@ namespace Greenshot.Base.Core
|
|||
// Try to find a separator, so we insert ourselves after it
|
||||
for (int i = 0; i < contextMenu.Items.Count; i++)
|
||||
{
|
||||
if (contextMenu.Items[i].GetType() != typeof(ToolStripSeparator)) continue;
|
||||
// Check if we need to add a new separator, which is done if the first found has a Tag with the value "PluginsAreAddedBefore"
|
||||
if ("PluginsAreAddedBefore".Equals(contextMenu.Items[i].Tag))
|
||||
if (contextMenu.Items[i].GetType() == typeof(ToolStripSeparator))
|
||||
{
|
||||
var separator = new ToolStripSeparator
|
||||
// Check if we need to add a new separator, which is done if the first found has a Tag with the value "PluginsAreAddedBefore"
|
||||
if ("PluginsAreAddedBefore".Equals(contextMenu.Items[i].Tag))
|
||||
{
|
||||
Tag = "PluginsAreAddedAfter",
|
||||
Size = new Size(305, 6)
|
||||
};
|
||||
contextMenu.Items.Insert(i, separator);
|
||||
}
|
||||
else if (!"PluginsAreAddedAfter".Equals(contextMenu.Items[i].Tag))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
var separator = new ToolStripSeparator
|
||||
{
|
||||
Tag = "PluginsAreAddedAfter",
|
||||
Size = new Size(305, 6)
|
||||
};
|
||||
contextMenu.Items.Insert(i, separator);
|
||||
}
|
||||
else if (!"PluginsAreAddedAfter".Equals(contextMenu.Items[i].Tag))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
contextMenu.Items.Insert(i + 1, item);
|
||||
addedItem = true;
|
||||
break;
|
||||
contextMenu.Items.Insert(i + 1, item);
|
||||
addedItem = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If we didn't insert the item, we just add it...
|
||||
|
|
|
@ -10,19 +10,22 @@ namespace Greenshot.Base.Core
|
|||
/// </summary>
|
||||
public class SimpleServiceProvider : IServiceLocator
|
||||
{
|
||||
private readonly Dictionary<Type, IList<object>> _services = new();
|
||||
private readonly Dictionary<Type, List<object>> _services = new Dictionary<Type, List<object>>();
|
||||
|
||||
public static IServiceLocator Current { get; } = new SimpleServiceProvider();
|
||||
|
||||
public IReadOnlyList<TService> GetAllInstances<TService>()
|
||||
public IEnumerable<TService> GetAllInstances<TService>()
|
||||
{
|
||||
var typeOfService = typeof(TService);
|
||||
if (!_services.TryGetValue(typeOfService, out var results))
|
||||
{
|
||||
return Array.Empty<TService>();
|
||||
yield break;
|
||||
}
|
||||
|
||||
return results.Cast<TService>().ToArray();
|
||||
foreach (TService result in results)
|
||||
{
|
||||
yield return result;
|
||||
}
|
||||
}
|
||||
|
||||
public TService GetInstance<TService>()
|
||||
|
|
117
src/Greenshot.Base/Core/SvgImage.cs
Normal file
117
src/Greenshot.Base/Core/SvgImage.cs
Normal file
|
@ -0,0 +1,117 @@
|
|||
/*
|
||||
* Greenshot - a free and open source screenshot tool
|
||||
* Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
|
||||
*
|
||||
* For more information see: https://getgreenshot.org/
|
||||
* The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using System.IO;
|
||||
using Svg;
|
||||
|
||||
namespace Greenshot.Base.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Create an image look like of the SVG
|
||||
/// </summary>
|
||||
public sealed class SvgImage : IImage
|
||||
{
|
||||
private readonly SvgDocument _svgDocument;
|
||||
|
||||
private Image _imageClone;
|
||||
|
||||
/// <summary>
|
||||
/// Factory to create via a stream
|
||||
/// </summary>
|
||||
/// <param name="stream">Stream</param>
|
||||
/// <returns>IImage</returns>
|
||||
public static IImage FromStream(Stream stream)
|
||||
{
|
||||
return new SvgImage(stream);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Default constructor
|
||||
/// </summary>
|
||||
/// <param name="stream"></param>
|
||||
public SvgImage(Stream stream)
|
||||
{
|
||||
_svgDocument = SvgDocument.Open<SvgDocument>(stream);
|
||||
Height = (int) _svgDocument.ViewBox.Height;
|
||||
Width = (int) _svgDocument.ViewBox.Width;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Height of the image, can be set to change
|
||||
/// </summary>
|
||||
public int Height { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Width of the image, can be set to change.
|
||||
/// </summary>
|
||||
public int Width { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Size of the image
|
||||
/// </summary>
|
||||
public Size Size => new Size(Width, Height);
|
||||
|
||||
/// <summary>
|
||||
/// Pixelformat of the underlying image
|
||||
/// </summary>
|
||||
public PixelFormat PixelFormat => Image.PixelFormat;
|
||||
|
||||
/// <summary>
|
||||
/// Horizontal resolution of the underlying image
|
||||
/// </summary>
|
||||
public float HorizontalResolution => Image.HorizontalResolution;
|
||||
|
||||
/// <summary>
|
||||
/// Vertical resolution of the underlying image
|
||||
/// </summary>
|
||||
public float VerticalResolution => Image.VerticalResolution;
|
||||
|
||||
/// <summary>
|
||||
/// Underlying image, or an on demand rendered version with different attributes as the original
|
||||
/// </summary>
|
||||
public Image Image
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_imageClone?.Height == Height && _imageClone?.Width == Width)
|
||||
{
|
||||
return _imageClone;
|
||||
}
|
||||
|
||||
// Calculate new image clone
|
||||
_imageClone?.Dispose();
|
||||
_imageClone = ImageHelper.CreateEmpty(Width, Height, PixelFormat.Format32bppArgb, Color.Transparent, 96, 96);
|
||||
_svgDocument.Draw((Bitmap) _imageClone);
|
||||
return _imageClone;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
_imageClone?.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -26,20 +26,10 @@ using System.Drawing;
|
|||
using System.Drawing.Imaging;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Windows.Forms;
|
||||
using Dapplo.Windows.Common.Extensions;
|
||||
using Dapplo.Windows.Common.Structs;
|
||||
using Dapplo.Windows.Gdi32;
|
||||
using Dapplo.Windows.Gdi32.Enums;
|
||||
using Dapplo.Windows.Gdi32.SafeHandles;
|
||||
using Dapplo.Windows.Gdi32.Structs;
|
||||
using Dapplo.Windows.Icons;
|
||||
using Dapplo.Windows.Icons.SafeHandles;
|
||||
using Dapplo.Windows.Kernel32;
|
||||
using Dapplo.Windows.User32;
|
||||
using Dapplo.Windows.User32.Enums;
|
||||
using Dapplo.Windows.User32.Structs;
|
||||
using Greenshot.Base.IniFile;
|
||||
using Greenshot.Base.Interfaces;
|
||||
using Greenshot.Base.UnmanagedHelpers;
|
||||
using Greenshot.Base.UnmanagedHelpers.Structs;
|
||||
using log4net;
|
||||
|
||||
namespace Greenshot.Base.Core
|
||||
|
@ -52,6 +42,35 @@ namespace Greenshot.Base.Core
|
|||
private static readonly ILog Log = LogManager.GetLogger(typeof(WindowCapture));
|
||||
private static readonly CoreConfiguration Configuration = IniConfig.GetIniSection<CoreConfiguration>();
|
||||
|
||||
/// <summary>
|
||||
/// Used to cleanup the unmanaged resource in the iconInfo for the CaptureCursor method
|
||||
/// </summary>
|
||||
/// <param name="hObject"></param>
|
||||
/// <returns></returns>
|
||||
[DllImport("gdi32", SetLastError = true)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
private static extern bool DeleteObject(IntPtr hObject);
|
||||
|
||||
/// <summary>
|
||||
/// Get the bounds of all screens combined.
|
||||
/// </summary>
|
||||
/// <returns>A Rectangle of the bounds of the entire display area.</returns>
|
||||
public static Rectangle GetScreenBounds()
|
||||
{
|
||||
int left = 0, top = 0, bottom = 0, right = 0;
|
||||
foreach (Screen screen in Screen.AllScreens)
|
||||
{
|
||||
left = Math.Min(left, screen.Bounds.X);
|
||||
top = Math.Min(top, screen.Bounds.Y);
|
||||
int screenAbsRight = screen.Bounds.X + screen.Bounds.Width;
|
||||
int screenAbsBottom = screen.Bounds.Y + screen.Bounds.Height;
|
||||
right = Math.Max(right, screenAbsRight);
|
||||
bottom = Math.Max(bottom, screenAbsBottom);
|
||||
}
|
||||
|
||||
return new Rectangle(left, top, (right + Math.Abs(left)), (bottom + Math.Abs(top)));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves the cursor location safely, accounting for DPI settings in Vista/Windows 7. This implementation
|
||||
/// can conveniently be used when the cursor location is needed to deal with a fullscreen bitmap.
|
||||
|
@ -59,9 +78,9 @@ namespace Greenshot.Base.Core
|
|||
/// <returns>
|
||||
/// Point with cursor location, relative to the top left corner of the monitor setup (which itself might actually not be on any screen)
|
||||
/// </returns>
|
||||
public static NativePoint GetCursorLocationRelativeToScreenBounds()
|
||||
public static Point GetCursorLocationRelativeToScreenBounds()
|
||||
{
|
||||
return GetLocationRelativeToScreenBounds(User32Api.GetCursorLocation());
|
||||
return GetLocationRelativeToScreenBounds(User32.GetCursorLocation());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -71,10 +90,12 @@ namespace Greenshot.Base.Core
|
|||
/// </summary>
|
||||
/// <param name="locationRelativeToScreenOrigin"></param>
|
||||
/// <returns>Point</returns>
|
||||
public static NativePoint GetLocationRelativeToScreenBounds(NativePoint locationRelativeToScreenOrigin)
|
||||
public static Point GetLocationRelativeToScreenBounds(Point locationRelativeToScreenOrigin)
|
||||
{
|
||||
NativeRect bounds = DisplayInfo.ScreenBounds;
|
||||
return locationRelativeToScreenOrigin.Offset(-bounds.X, -bounds.Y);
|
||||
Point ret = locationRelativeToScreenOrigin;
|
||||
Rectangle bounds = GetScreenBounds();
|
||||
ret.Offset(-bounds.X, -bounds.Y);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -89,26 +110,36 @@ namespace Greenshot.Base.Core
|
|||
capture = new Capture();
|
||||
}
|
||||
|
||||
var cursorInfo = CursorInfo.Create();
|
||||
if (!NativeCursorMethods.GetCursorInfo(ref cursorInfo)) return capture;
|
||||
if (cursorInfo.Flags != CursorInfoFlags.Showing) return capture;
|
||||
var cursorInfo = new CursorInfo();
|
||||
cursorInfo.cbSize = Marshal.SizeOf(cursorInfo);
|
||||
if (!User32.GetCursorInfo(out cursorInfo)) return capture;
|
||||
if (cursorInfo.flags != User32.CURSOR_SHOWING) return capture;
|
||||
|
||||
using SafeIconHandle safeIcon = NativeIconMethods.CopyIcon(cursorInfo.CursorHandle);
|
||||
if (!NativeIconMethods.GetIconInfo(safeIcon, out var iconInfo)) return capture;
|
||||
using SafeIconHandle safeIcon = User32.CopyIcon(cursorInfo.hCursor);
|
||||
if (!User32.GetIconInfo(safeIcon, out var iconInfo)) return capture;
|
||||
|
||||
NativePoint cursorLocation = User32Api.GetCursorLocation();
|
||||
Point cursorLocation = User32.GetCursorLocation();
|
||||
// Align cursor location to Bitmap coordinates (instead of Screen coordinates)
|
||||
var x = cursorLocation.X - iconInfo.Hotspot.X - capture.ScreenBounds.X;
|
||||
var y = cursorLocation.Y - iconInfo.Hotspot.Y - capture.ScreenBounds.Y;
|
||||
var x = cursorLocation.X - iconInfo.xHotspot - capture.ScreenBounds.X;
|
||||
var y = cursorLocation.Y - iconInfo.yHotspot - capture.ScreenBounds.Y;
|
||||
// Set the location
|
||||
capture.CursorLocation = new NativePoint(x, y);
|
||||
capture.CursorLocation = new Point(x, y);
|
||||
|
||||
using (Icon icon = Icon.FromHandle(safeIcon.DangerousGetHandle()))
|
||||
{
|
||||
capture.Cursor = icon;
|
||||
}
|
||||
iconInfo.BitmaskBitmapHandle.Dispose();
|
||||
iconInfo.ColorBitmapHandle.Dispose();
|
||||
|
||||
if (iconInfo.hbmMask != IntPtr.Zero)
|
||||
{
|
||||
DeleteObject(iconInfo.hbmMask);
|
||||
}
|
||||
|
||||
if (iconInfo.hbmColor != IntPtr.Zero)
|
||||
{
|
||||
DeleteObject(iconInfo.hbmColor);
|
||||
}
|
||||
|
||||
return capture;
|
||||
}
|
||||
|
||||
|
@ -130,11 +161,11 @@ namespace Greenshot.Base.Core
|
|||
/// Helper method to create an exception that might explain what is wrong while capturing
|
||||
/// </summary>
|
||||
/// <param name="method">string with current method</param>
|
||||
/// <param name="captureBounds">NativeRect of what we want to capture</param>
|
||||
/// <param name="captureBounds">Rectangle of what we want to capture</param>
|
||||
/// <returns></returns>
|
||||
private static Exception CreateCaptureException(string method, NativeRect captureBounds)
|
||||
private static Exception CreateCaptureException(string method, Rectangle captureBounds)
|
||||
{
|
||||
Exception exceptionToThrow = User32Api.CreateWin32Exception(method);
|
||||
Exception exceptionToThrow = User32.CreateWin32Exception(method);
|
||||
if (!captureBounds.IsEmpty)
|
||||
{
|
||||
exceptionToThrow.Data.Add("Height", captureBounds.Height);
|
||||
|
@ -202,9 +233,9 @@ namespace Greenshot.Base.Core
|
|||
/// This method will use User32 code to capture the specified captureBounds from the screen
|
||||
/// </summary>
|
||||
/// <param name="capture">ICapture where the captured Bitmap will be stored</param>
|
||||
/// <param name="captureBounds">NativeRect with the bounds to capture</param>
|
||||
/// <param name="captureBounds">Rectangle with the bounds to capture</param>
|
||||
/// <returns>A Capture Object with a part of the Screen as an Image</returns>
|
||||
public static ICapture CaptureRectangle(ICapture capture, NativeRect captureBounds)
|
||||
public static ICapture CaptureRectangle(ICapture capture, Rectangle captureBounds)
|
||||
{
|
||||
if (capture == null)
|
||||
{
|
||||
|
@ -240,9 +271,9 @@ namespace Greenshot.Base.Core
|
|||
/// This method will use User32 code to capture the specified captureBounds from the screen
|
||||
/// </summary>
|
||||
/// <param name="capture">ICapture where the captured Bitmap will be stored</param>
|
||||
/// <param name="captureBounds">NativeRect with the bounds to capture</param>
|
||||
/// <param name="captureBounds">Rectangle with the bounds to capture</param>
|
||||
/// <returns>A Capture Object with a part of the Screen as an Image</returns>
|
||||
public static ICapture CaptureRectangleFromDesktopScreen(ICapture capture, NativeRect captureBounds)
|
||||
public static ICapture CaptureRectangleFromDesktopScreen(ICapture capture, Rectangle captureBounds)
|
||||
{
|
||||
if (capture == null)
|
||||
{
|
||||
|
@ -257,9 +288,9 @@ namespace Greenshot.Base.Core
|
|||
/// <summary>
|
||||
/// This method will use User32 code to capture the specified captureBounds from the screen
|
||||
/// </summary>
|
||||
/// <param name="captureBounds">NativeRect with the bounds to capture</param>
|
||||
/// <param name="captureBounds">Rectangle with the bounds to capture</param>
|
||||
/// <returns>Bitmap which is captured from the screen at the location specified by the captureBounds</returns>
|
||||
public static Bitmap CaptureRectangle(NativeRect captureBounds)
|
||||
public static Bitmap CaptureRectangle(Rectangle captureBounds)
|
||||
{
|
||||
Bitmap returnBitmap = null;
|
||||
if (captureBounds.Height <= 0 || captureBounds.Width <= 0)
|
||||
|
@ -290,7 +321,7 @@ namespace Greenshot.Base.Core
|
|||
}
|
||||
|
||||
// create a device context we can copy to
|
||||
using SafeCompatibleDcHandle safeCompatibleDcHandle = Gdi32Api.CreateCompatibleDC(desktopDcHandle);
|
||||
using SafeCompatibleDCHandle safeCompatibleDcHandle = GDI32.CreateCompatibleDC(desktopDcHandle);
|
||||
// Check if the device context is there, if not throw an error with as much info as possible!
|
||||
if (safeCompatibleDcHandle.IsInvalid)
|
||||
{
|
||||
|
@ -301,13 +332,13 @@ namespace Greenshot.Base.Core
|
|||
}
|
||||
|
||||
// Create BITMAPINFOHEADER for CreateDIBSection
|
||||
var bitmapInfoHeader = BitmapV5Header.Create(captureBounds.Width, captureBounds.Height, 24);
|
||||
BITMAPINFOHEADERV5 bmi = new BITMAPINFOHEADERV5(captureBounds.Width, captureBounds.Height, 24);
|
||||
|
||||
// Make sure the last error is set to 0
|
||||
Kernel32Api.SetLastError(0);
|
||||
Win32.SetLastError(0);
|
||||
|
||||
// create a bitmap we can copy it to, using GetDeviceCaps to get the width/height
|
||||
using SafeDibSectionHandle safeDibSectionHandle = Gdi32Api.CreateDIBSection(desktopDcHandle, ref bitmapInfoHeader, DibColors.RgbColors, out _, IntPtr.Zero, 0);
|
||||
using SafeDibSectionHandle safeDibSectionHandle = GDI32.CreateDIBSection(desktopDcHandle, ref bmi, BITMAPINFOHEADERV5.DIB_RGB_COLORS, out _, IntPtr.Zero, 0);
|
||||
if (safeDibSectionHandle.IsInvalid)
|
||||
{
|
||||
// Get Exception before the error is lost
|
||||
|
@ -324,8 +355,8 @@ namespace Greenshot.Base.Core
|
|||
{
|
||||
// bitblt over (make copy)
|
||||
// ReSharper disable once BitwiseOperatorOnEnumWithoutFlags
|
||||
Gdi32Api.BitBlt(safeCompatibleDcHandle, 0, 0, captureBounds.Width, captureBounds.Height, desktopDcHandle, captureBounds.X, captureBounds.Y,
|
||||
RasterOperations.SourceCopy | RasterOperations.CaptureBlt);
|
||||
GDI32.BitBlt(safeCompatibleDcHandle, 0, 0, captureBounds.Width, captureBounds.Height, desktopDcHandle, captureBounds.X, captureBounds.Y,
|
||||
CopyPixelOperation.SourceCopy | CopyPixelOperation.CaptureBlt);
|
||||
}
|
||||
|
||||
// get a .NET image object for it
|
||||
|
@ -357,7 +388,7 @@ namespace Greenshot.Base.Core
|
|||
}
|
||||
|
||||
// If the region is not empty, we have "offscreenContent"
|
||||
using Graphics screenGraphics = Graphics.FromHwnd(User32Api.GetDesktopWindow());
|
||||
using Graphics screenGraphics = Graphics.FromHwnd(User32.GetDesktopWindow());
|
||||
offscreenContent = !captureRegion.IsEmpty(screenGraphics);
|
||||
}
|
||||
|
||||
|
@ -366,16 +397,17 @@ namespace Greenshot.Base.Core
|
|||
{
|
||||
using Bitmap tmpBitmap = Image.FromHbitmap(safeDibSectionHandle.DangerousGetHandle());
|
||||
// Create a new bitmap which has a transparent background
|
||||
returnBitmap = ImageHelper.CreateEmpty(tmpBitmap.Width, tmpBitmap.Height, PixelFormat.Format32bppArgb, Color.Transparent, tmpBitmap.HorizontalResolution, tmpBitmap.VerticalResolution);
|
||||
returnBitmap = ImageHelper.CreateEmpty(tmpBitmap.Width, tmpBitmap.Height, PixelFormat.Format32bppArgb, Color.Transparent,
|
||||
tmpBitmap.HorizontalResolution, tmpBitmap.VerticalResolution);
|
||||
// Content will be copied here
|
||||
using Graphics graphics = Graphics.FromImage(returnBitmap);
|
||||
// For all screens copy the content to the new bitmap
|
||||
|
||||
foreach (var displayInfo in DisplayInfo.AllDisplayInfos)
|
||||
foreach (Screen screen in Screen.AllScreens)
|
||||
{
|
||||
// Make sure the bounds are offset to the capture bounds
|
||||
var displayBounds = displayInfo.Bounds.Offset(-captureBounds.X, -captureBounds.Y);
|
||||
graphics.DrawImage(tmpBitmap, displayBounds, displayBounds.X, displayBounds.Y, displayBounds.Width, displayBounds.Height, GraphicsUnit.Pixel);
|
||||
Rectangle screenBounds = screen.Bounds;
|
||||
// Make sure the bounds are offsetted to the capture bounds
|
||||
screenBounds.Offset(-captureBounds.X, -captureBounds.Y);
|
||||
graphics.DrawImage(tmpBitmap, screenBounds, screenBounds.X, screenBounds.Y, screenBounds.Width, screenBounds.Height, GraphicsUnit.Pixel);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -21,7 +21,8 @@
|
|||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Dapplo.Windows.User32;
|
||||
using System.Text;
|
||||
using Greenshot.Base.UnmanagedHelpers;
|
||||
|
||||
namespace Greenshot.Base.Core
|
||||
{
|
||||
|
@ -43,13 +44,15 @@ namespace Greenshot.Base.Core
|
|||
public WindowsEnumerator GetWindows(IntPtr hWndParent, string classname)
|
||||
{
|
||||
Items = new List<WindowDetails>();
|
||||
User32Api.EnumChildWindows(hWndParent, OnWindowEnum, IntPtr.Zero);
|
||||
User32.EnumChildWindows(hWndParent, WindowEnum, IntPtr.Zero);
|
||||
|
||||
bool hasParent = !IntPtr.Zero.Equals(hWndParent);
|
||||
string parentText = null;
|
||||
if (hasParent)
|
||||
{
|
||||
parentText = User32Api.GetText(hWndParent);
|
||||
var title = new StringBuilder(260, 260);
|
||||
User32.GetWindowText(hWndParent, title, title.Capacity);
|
||||
parentText = title.ToString();
|
||||
}
|
||||
|
||||
var windows = new List<WindowDetails>();
|
||||
|
@ -71,6 +74,17 @@ namespace Greenshot.Base.Core
|
|||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The enum Windows callback.
|
||||
/// </summary>
|
||||
/// <param name="hWnd">Window Handle</param>
|
||||
/// <param name="lParam">Application defined value</param>
|
||||
/// <returns>1 to continue enumeration, 0 to stop</returns>
|
||||
private int WindowEnum(IntPtr hWnd, int lParam)
|
||||
{
|
||||
return OnWindowEnum(hWnd) ? 1 : 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called whenever a new window is about to be added
|
||||
/// by the Window enumeration called from GetWindows.
|
||||
|
@ -80,9 +94,8 @@ namespace Greenshot.Base.Core
|
|||
/// be empty.
|
||||
/// </summary>
|
||||
/// <param name="hWnd">Window handle to add</param>
|
||||
/// <param name="lParam"></param>
|
||||
/// <returns>True to continue enumeration, False to stop</returns>
|
||||
private bool OnWindowEnum(IntPtr hWnd, IntPtr lParam)
|
||||
private bool OnWindowEnum(IntPtr hWnd)
|
||||
{
|
||||
if (!WindowDetails.IsIgnoreHandle(hWnd))
|
||||
{
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
*/
|
||||
|
||||
using System.Windows.Forms;
|
||||
using Dapplo.Windows.Messages.Enumerations;
|
||||
using Greenshot.Base.UnmanagedHelpers.Enums;
|
||||
using log4net;
|
||||
|
||||
namespace Greenshot.Base.Core
|
||||
|
@ -51,13 +51,16 @@ namespace Greenshot.Base.Core
|
|||
public static bool PreFilterMessageExternal(ref Message m)
|
||||
{
|
||||
WindowsMessages message = (WindowsMessages) m.Msg;
|
||||
if (message != WindowsMessages.WM_INPUTLANGCHANGEREQUEST && message != WindowsMessages.WM_INPUTLANGCHANGE) return false;
|
||||
if (message == WindowsMessages.WM_INPUTLANGCHANGEREQUEST || message == WindowsMessages.WM_INPUTLANGCHANGE)
|
||||
{
|
||||
LOG.WarnFormat("Filtering: {0}, {1:X} - {2:X} - {3:X}", message, m.LParam.ToInt64(), m.WParam.ToInt64(), m.HWnd.ToInt64());
|
||||
// For now we always return true
|
||||
return true;
|
||||
// But it could look something like this:
|
||||
//return (m.LParam.ToInt64() | 0x7FFFFFFF) != 0;
|
||||
}
|
||||
|
||||
LOG.DebugFormat("Filtering: {0}, {1:X} - {2:X} - {3:X}", message, m.LParam.ToInt64(), m.WParam.ToInt64(), m.HWnd.ToInt64());
|
||||
// For now we always return true
|
||||
return true;
|
||||
// But it could look something like this:
|
||||
//return (m.LParam.ToInt64() | 0x7FFFFFFF) != 0;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -23,7 +23,6 @@ using System.ComponentModel;
|
|||
using System.Drawing;
|
||||
using System.Drawing.Drawing2D;
|
||||
using System.Drawing.Imaging;
|
||||
using Dapplo.Windows.Common.Structs;
|
||||
using Greenshot.Base.Core;
|
||||
|
||||
namespace Greenshot.Base.Effects
|
||||
|
@ -43,7 +42,7 @@ namespace Greenshot.Base.Effects
|
|||
|
||||
public int ShadowSize { get; set; }
|
||||
|
||||
public NativePoint ShadowOffset { get; set; }
|
||||
public Point ShadowOffset { get; set; }
|
||||
|
||||
public virtual void Reset()
|
||||
{
|
||||
|
|
|
@ -3,22 +3,12 @@
|
|||
<PropertyGroup>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)' == 'Release'">
|
||||
<DebugType>none</DebugType>
|
||||
<DebugSymbols>false</DebugSymbols>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Dapplo.HttpExtensions.JsonNet" Version="1.1.2" />
|
||||
<PackageReference Include="Dapplo.Windows.Clipboard" Version="1.0.28" />
|
||||
<PackageReference Include="Dapplo.Windows.Dpi" Version="1.0.28" />
|
||||
<PackageReference Include="Dapplo.Windows.Gdi32" Version="1.0.28" />
|
||||
<PackageReference Include="Dapplo.Windows.Icons" Version="1.0.28" />
|
||||
<PackageReference Include="Dapplo.Windows.Kernel32" Version="1.0.28" />
|
||||
<PackageReference Include="Dapplo.Windows.Multimedia" Version="1.0.28" />
|
||||
<PackageReference Include="HtmlAgilityPack" Version="1.11.46" />
|
||||
<PackageReference Include="log4net" version="2.0.15" />
|
||||
<PackageReference Include="Svg" Version="3.4.3" />
|
||||
<PackageReference Include="Dapplo.HttpExtensions.JsonNet" Version="1.0.16" />
|
||||
<PackageReference Include="HtmlAgilityPack" Version="1.11.42" />
|
||||
<PackageReference Include="log4net" version="2.0.14" />
|
||||
<PackageReference Include="Svg" Version="3.4.0" />
|
||||
<Reference Include="Accessibility" />
|
||||
<Reference Include="CustomMarshalers" />
|
||||
</ItemGroup>
|
||||
|
|
151
src/Greenshot.Base/Hooking/WindowsEventHook.cs
Normal file
151
src/Greenshot.Base/Hooking/WindowsEventHook.cs
Normal file
|
@ -0,0 +1,151 @@
|
|||
/*
|
||||
* Greenshot - a free and open source screenshot tool
|
||||
* Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
|
||||
*
|
||||
* For more information see: https://getgreenshot.org/
|
||||
* The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
using Greenshot.Base.UnmanagedHelpers.Enums;
|
||||
|
||||
namespace Greenshot.Base.Hooking
|
||||
{
|
||||
/// <summary>
|
||||
/// The WinEventHook can register handlers to become important windows events
|
||||
/// This makes it possible to know a.o. when a window is created, moved, updated and closed.
|
||||
/// </summary>
|
||||
public class WindowsEventHook : IDisposable
|
||||
{
|
||||
private readonly WinEventDelegate _winEventHandler;
|
||||
private GCHandle _gcHandle;
|
||||
|
||||
/// <summary>
|
||||
/// Used with Register hook
|
||||
/// </summary>
|
||||
/// <param name="eventType"></param>
|
||||
/// <param name="hWnd"></param>
|
||||
/// <param name="idObject"></param>
|
||||
/// <param name="idChild"></param>
|
||||
/// <param name="dwEventThread"></param>
|
||||
/// <param name="dwmsEventTime"></param>
|
||||
public delegate void WinEventHandler(WinEvent eventType, IntPtr hWnd, EventObjects idObject, int idChild, uint dwEventThread, uint dwmsEventTime);
|
||||
|
||||
/// <summary>
|
||||
/// Create a WindowsEventHook object
|
||||
/// </summary>
|
||||
public WindowsEventHook()
|
||||
{
|
||||
_winEventHandler = WinEventDelegateHandler;
|
||||
_gcHandle = GCHandle.Alloc(_winEventHandler);
|
||||
}
|
||||
|
||||
[DllImport("user32", SetLastError = true)]
|
||||
private static extern bool UnhookWinEvent(IntPtr hWinEventHook);
|
||||
|
||||
[DllImport("user32", SetLastError = true)]
|
||||
private static extern IntPtr SetWinEventHook(WinEvent eventMin, WinEvent eventMax, IntPtr hmodWinEventProc, WinEventDelegate lpfnWinEventProc, int idProcess, int idThread,
|
||||
WinEventHookFlags dwFlags);
|
||||
|
||||
/// <summary>
|
||||
/// Used with SetWinEventHook
|
||||
/// </summary>
|
||||
/// <param name="hWinEventHook"></param>
|
||||
/// <param name="eventType"></param>
|
||||
/// <param name="hWnd"></param>
|
||||
/// <param name="idObject"></param>
|
||||
/// <param name="idChild"></param>
|
||||
/// <param name="dwEventThread"></param>
|
||||
/// <param name="dwmsEventTime"></param>
|
||||
private delegate void WinEventDelegate(IntPtr hWinEventHook, WinEvent eventType, IntPtr hWnd, EventObjects idObject, int idChild, uint dwEventThread, uint dwmsEventTime);
|
||||
|
||||
private readonly IDictionary<IntPtr, WinEventHandler> _winEventHandlers = new Dictionary<IntPtr, WinEventHandler>();
|
||||
|
||||
/// <summary>
|
||||
/// Are hooks active?
|
||||
/// </summary>
|
||||
public bool IsHooked => _winEventHandlers.Count > 0;
|
||||
|
||||
/// <summary>
|
||||
/// Hook a WinEvent
|
||||
/// </summary>
|
||||
/// <param name="winEvent"></param>
|
||||
/// <param name="winEventHandler"></param>
|
||||
/// <returns>true if success</returns>
|
||||
public void Hook(WinEvent winEvent, WinEventHandler winEventHandler)
|
||||
{
|
||||
Hook(winEvent, winEvent, winEventHandler);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Hook a WinEvent
|
||||
/// </summary>
|
||||
/// <param name="winEventStart"></param>
|
||||
/// <param name="winEventEnd"></param>
|
||||
/// <param name="winEventHandler"></param>
|
||||
public void Hook(WinEvent winEventStart, WinEvent winEventEnd, WinEventHandler winEventHandler)
|
||||
{
|
||||
var hookPtr = SetWinEventHook(winEventStart, winEventEnd, IntPtr.Zero, _winEventHandler, 0, 0,
|
||||
WinEventHookFlags.WINEVENT_SKIPOWNPROCESS | WinEventHookFlags.WINEVENT_OUTOFCONTEXT);
|
||||
_winEventHandlers.Add(hookPtr, winEventHandler);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remove all hooks
|
||||
/// </summary>
|
||||
private void Unhook()
|
||||
{
|
||||
foreach (var hookPtr in _winEventHandlers.Keys)
|
||||
{
|
||||
if (hookPtr != IntPtr.Zero)
|
||||
{
|
||||
UnhookWinEvent(hookPtr);
|
||||
}
|
||||
}
|
||||
|
||||
_winEventHandlers.Clear();
|
||||
_gcHandle.Free();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
Unhook();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Call the WinEventHandler for this event
|
||||
/// </summary>
|
||||
/// <param name="hWinEventHook"></param>
|
||||
/// <param name="eventType"></param>
|
||||
/// <param name="hWnd"></param>
|
||||
/// <param name="idObject"></param>
|
||||
/// <param name="idChild"></param>
|
||||
/// <param name="dwEventThread"></param>
|
||||
/// <param name="dwmsEventTime"></param>
|
||||
private void WinEventDelegateHandler(IntPtr hWinEventHook, WinEvent eventType, IntPtr hWnd, EventObjects idObject, int idChild, uint dwEventThread, uint dwmsEventTime)
|
||||
{
|
||||
if (_winEventHandlers.TryGetValue(hWinEventHook, out var handler))
|
||||
{
|
||||
handler(eventType, hWnd, idObject, idChild, dwEventThread, dwmsEventTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
180
src/Greenshot.Base/Hooking/WindowsOpenCloseMonitor.cs
Normal file
180
src/Greenshot.Base/Hooking/WindowsOpenCloseMonitor.cs
Normal file
|
@ -0,0 +1,180 @@
|
|||
/*
|
||||
* Greenshot - a free and open source screenshot tool
|
||||
* Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
|
||||
*
|
||||
* For more information see: https://getgreenshot.org/
|
||||
* The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using Greenshot.Base.Core;
|
||||
using Greenshot.Base.UnmanagedHelpers.Enums;
|
||||
|
||||
namespace Greenshot.Base.Hooking
|
||||
{
|
||||
/// <summary>
|
||||
/// Event arguments for the WindowOpenCloseEvent
|
||||
/// </summary>
|
||||
public class WindowOpenCloseEventArgs : EventArgs
|
||||
{
|
||||
public bool IsOpen { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// HWnd of the window which has a changed title
|
||||
/// </summary>
|
||||
public IntPtr HWnd { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Title which is changed
|
||||
/// </summary>
|
||||
public string Title { get; set; }
|
||||
|
||||
public string ClassName { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Delegate for the window open close event
|
||||
/// </summary>
|
||||
/// <param name="eventArgs"></param>
|
||||
public delegate void WindowOpenCloseEventDelegate(WindowOpenCloseEventArgs eventArgs);
|
||||
|
||||
/// <summary>
|
||||
/// Monitor all new and destroyed windows
|
||||
/// </summary>
|
||||
public sealed class WindowsOpenCloseMonitor : IDisposable
|
||||
{
|
||||
private WindowsEventHook _hook;
|
||||
private readonly object _lockObject = new object();
|
||||
|
||||
// ReSharper disable once InconsistentNaming
|
||||
private event WindowOpenCloseEventDelegate _windowOpenCloseEvent;
|
||||
|
||||
/// <summary>
|
||||
/// Add / remove event handler to the title monitor
|
||||
/// </summary>
|
||||
public event WindowOpenCloseEventDelegate WindowOpenCloseChangeEvent
|
||||
{
|
||||
add
|
||||
{
|
||||
lock (_lockObject)
|
||||
{
|
||||
if (_hook == null)
|
||||
{
|
||||
_hook = new WindowsEventHook();
|
||||
_hook.Hook(WinEvent.EVENT_OBJECT_CREATE, WinEvent.EVENT_OBJECT_DESTROY, WinEventHandler);
|
||||
}
|
||||
|
||||
_windowOpenCloseEvent += value;
|
||||
}
|
||||
}
|
||||
remove
|
||||
{
|
||||
lock (_lockObject)
|
||||
{
|
||||
_windowOpenCloseEvent -= value;
|
||||
if (_windowOpenCloseEvent == null || _windowOpenCloseEvent.GetInvocationList().Length == 0)
|
||||
{
|
||||
if (_hook != null)
|
||||
{
|
||||
_hook.Dispose();
|
||||
_hook = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// WinEventDelegate for the creation and destruction
|
||||
/// </summary>
|
||||
/// <param name="eventType"></param>
|
||||
/// <param name="hWnd"></param>
|
||||
/// <param name="idObject"></param>
|
||||
/// <param name="idChild"></param>
|
||||
/// <param name="dwEventThread"></param>
|
||||
/// <param name="dwmsEventTime"></param>
|
||||
private void WinEventHandler(WinEvent eventType, IntPtr hWnd, EventObjects idObject, int idChild, uint dwEventThread, uint dwmsEventTime)
|
||||
{
|
||||
if (hWnd == IntPtr.Zero || idObject != EventObjects.OBJID_WINDOW)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (eventType == WinEvent.EVENT_OBJECT_CREATE)
|
||||
{
|
||||
if (_windowOpenCloseEvent != null)
|
||||
{
|
||||
var windowsDetails = new WindowDetails(hWnd);
|
||||
_windowOpenCloseEvent(new WindowOpenCloseEventArgs
|
||||
{
|
||||
HWnd = hWnd,
|
||||
IsOpen = true,
|
||||
Title = windowsDetails.Text,
|
||||
ClassName = windowsDetails.ClassName
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (eventType == WinEvent.EVENT_OBJECT_DESTROY)
|
||||
{
|
||||
_windowOpenCloseEvent?.Invoke(new WindowOpenCloseEventArgs
|
||||
{
|
||||
HWnd = hWnd,
|
||||
IsOpen = false
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private bool _disposedValue; // To detect redundant calls
|
||||
|
||||
/// <summary>
|
||||
/// Dispose the underlying hook
|
||||
/// </summary>
|
||||
public void Dispose(bool disposing)
|
||||
{
|
||||
if (_disposedValue)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
lock (_lockObject)
|
||||
{
|
||||
_hook?.Dispose();
|
||||
}
|
||||
|
||||
_disposedValue = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Make sure the finalizer disposes the underlying hook
|
||||
/// </summary>
|
||||
~WindowsOpenCloseMonitor()
|
||||
{
|
||||
// Do not change this code. Put cleanup code in Dispose(bool disposing) above.
|
||||
Dispose(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Dispose the underlying hook
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
// Do not change this code. Put cleanup code in Dispose(bool disposing) above.
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
||||
}
|
165
src/Greenshot.Base/Hooking/WindowsTitleMonitor.cs
Normal file
165
src/Greenshot.Base/Hooking/WindowsTitleMonitor.cs
Normal file
|
@ -0,0 +1,165 @@
|
|||
/*
|
||||
* Greenshot - a free and open source screenshot tool
|
||||
* Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
|
||||
*
|
||||
* For more information see: https://getgreenshot.org/
|
||||
* The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using Greenshot.Base.Core;
|
||||
using Greenshot.Base.UnmanagedHelpers.Enums;
|
||||
|
||||
namespace Greenshot.Base.Hooking
|
||||
{
|
||||
/// <summary>
|
||||
/// Event arguments for the TitleChangeEvent
|
||||
/// </summary>
|
||||
public class TitleChangeEventArgs : EventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// HWnd of the window which has a changed title
|
||||
/// </summary>
|
||||
public IntPtr HWnd { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Title which is changed
|
||||
/// </summary>
|
||||
public string Title { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Delegate for the title change event
|
||||
/// </summary>
|
||||
/// <param name="eventArgs"></param>
|
||||
public delegate void TitleChangeEventDelegate(TitleChangeEventArgs eventArgs);
|
||||
|
||||
/// <summary>
|
||||
/// Monitor all title changes
|
||||
/// </summary>
|
||||
public sealed class WindowsTitleMonitor : IDisposable
|
||||
{
|
||||
private WindowsEventHook _hook;
|
||||
private readonly object _lockObject = new object();
|
||||
|
||||
// ReSharper disable once InconsistentNaming
|
||||
private event TitleChangeEventDelegate _titleChangeEvent;
|
||||
|
||||
/// <summary>
|
||||
/// Add / remove event handler to the title monitor
|
||||
/// </summary>
|
||||
public event TitleChangeEventDelegate TitleChangeEvent
|
||||
{
|
||||
add
|
||||
{
|
||||
lock (_lockObject)
|
||||
{
|
||||
if (_hook == null)
|
||||
{
|
||||
_hook = new WindowsEventHook();
|
||||
_hook.Hook(WinEvent.EVENT_OBJECT_NAMECHANGE, WinEventHandler);
|
||||
}
|
||||
|
||||
_titleChangeEvent += value;
|
||||
}
|
||||
}
|
||||
remove
|
||||
{
|
||||
lock (_lockObject)
|
||||
{
|
||||
_titleChangeEvent -= value;
|
||||
if (_titleChangeEvent == null || _titleChangeEvent.GetInvocationList().Length == 0)
|
||||
{
|
||||
if (_hook != null)
|
||||
{
|
||||
_hook.Dispose();
|
||||
_hook = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// WinEventDelegate for the creation & destruction
|
||||
/// </summary>
|
||||
/// <param name="eventType"></param>
|
||||
/// <param name="hWnd"></param>
|
||||
/// <param name="idObject"></param>
|
||||
/// <param name="idChild"></param>
|
||||
/// <param name="dwEventThread"></param>
|
||||
/// <param name="dwmsEventTime"></param>
|
||||
private void WinEventHandler(WinEvent eventType, IntPtr hWnd, EventObjects idObject, int idChild, uint dwEventThread, uint dwmsEventTime)
|
||||
{
|
||||
if (hWnd == IntPtr.Zero || idObject != EventObjects.OBJID_WINDOW)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (eventType == WinEvent.EVENT_OBJECT_NAMECHANGE)
|
||||
{
|
||||
if (_titleChangeEvent != null)
|
||||
{
|
||||
string newTitle = new WindowDetails(hWnd).Text;
|
||||
_titleChangeEvent(new TitleChangeEventArgs
|
||||
{
|
||||
HWnd = hWnd,
|
||||
Title = newTitle
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool _disposedValue; // To detect redundant calls
|
||||
|
||||
/// <summary>
|
||||
/// Dispose the underlying hook
|
||||
/// </summary>
|
||||
public void Dispose(bool disposing)
|
||||
{
|
||||
if (_disposedValue)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
lock (_lockObject)
|
||||
{
|
||||
_hook?.Dispose();
|
||||
}
|
||||
|
||||
_disposedValue = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Make sure the finalizer disposes the underlying hook
|
||||
/// </summary>
|
||||
~WindowsTitleMonitor()
|
||||
{
|
||||
// Do not change this code. Put cleanup code in Dispose(bool disposing) above.
|
||||
Dispose(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Dispose the underlying hook
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
// Do not change this code. Put cleanup code in Dispose(bool disposing) above.
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -22,7 +22,6 @@
|
|||
using System.Drawing;
|
||||
using System.Drawing.Drawing2D;
|
||||
using System.Windows.Forms;
|
||||
using Dapplo.Windows.Common.Structs;
|
||||
|
||||
namespace Greenshot.Base.Interfaces.Drawing.Adorners
|
||||
{
|
||||
|
@ -36,7 +35,7 @@ namespace Greenshot.Base.Interfaces.Drawing.Adorners
|
|||
/// <summary>
|
||||
/// These are the bounds of the adorner
|
||||
/// </summary>
|
||||
NativeRect Bounds { get; }
|
||||
Rectangle Bounds { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The current edit status, this is needed to locate the adorner to send events to
|
||||
|
@ -54,7 +53,7 @@ namespace Greenshot.Base.Interfaces.Drawing.Adorners
|
|||
/// </summary>
|
||||
/// <param name="point">Point to test</param>
|
||||
/// <returns>true if so</returns>
|
||||
bool HitTest(NativePoint point);
|
||||
bool HitTest(Point point);
|
||||
|
||||
/// <summary>
|
||||
/// Handle the MouseDown event
|
||||
|
@ -98,21 +97,6 @@ namespace Greenshot.Base.Interfaces.Drawing.Adorners
|
|||
/// Adjust UI elements to the supplied DPI settings
|
||||
/// </summary>
|
||||
/// <param name="dpi"></param>
|
||||
void AdjustToDpi(int dpi);
|
||||
|
||||
/// <summary>
|
||||
/// The color of the lines around the adorner
|
||||
/// </summary>
|
||||
Color OutlineColor { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The color of the fill of the adorner
|
||||
/// </summary>
|
||||
Color FillColor { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// This is to TAG the adorner so we know the type
|
||||
/// </summary>
|
||||
string Tag { get; set; }
|
||||
void AdjustToDpi(uint dpi);
|
||||
}
|
||||
}
|
|
@ -22,23 +22,15 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Drawing2D;
|
||||
using System.Windows.Forms;
|
||||
using Dapplo.Windows.Common.Structs;
|
||||
using Greenshot.Base.Interfaces.Drawing.Adorners;
|
||||
|
||||
namespace Greenshot.Base.Interfaces.Drawing
|
||||
{
|
||||
public interface IDrawableContainer : INotifyPropertyChanged, IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// The parent surface where this IDrawableContainer is on
|
||||
/// </summary>
|
||||
ISurface Parent { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Is this IDrawableContainer selected on the surface
|
||||
/// </summary>
|
||||
bool Selected { get; set; }
|
||||
|
||||
int Left { get; set; }
|
||||
|
@ -49,43 +41,28 @@ namespace Greenshot.Base.Interfaces.Drawing
|
|||
|
||||
int Height { get; set; }
|
||||
|
||||
NativePoint Location { get; }
|
||||
Point Location { get; }
|
||||
|
||||
NativeSize Size { get; }
|
||||
Size Size { get; }
|
||||
|
||||
NativeRect Bounds { get; }
|
||||
Rectangle Bounds { get; }
|
||||
|
||||
NativeRect DrawingBounds { get; }
|
||||
Rectangle DrawingBounds { get; }
|
||||
|
||||
void ApplyBounds(NativeRectFloat newBounds);
|
||||
void ApplyBounds(RectangleF newBounds);
|
||||
|
||||
bool HasFilters { get; }
|
||||
|
||||
EditStatus Status { get; set; }
|
||||
|
||||
void Invalidate();
|
||||
|
||||
bool ClickableAt(int x, int y);
|
||||
|
||||
void MoveBy(int x, int y);
|
||||
|
||||
void Transform(Matrix matrix);
|
||||
|
||||
bool HandleMouseDown(int x, int y);
|
||||
|
||||
void HandleMouseUp(int x, int y);
|
||||
|
||||
bool HandleMouseMove(int x, int y);
|
||||
|
||||
bool InitContent();
|
||||
|
||||
/// <summary>
|
||||
/// Defines if the drawable container participates in undo / redo
|
||||
/// </summary>
|
||||
bool IsUndoable { get; }
|
||||
|
||||
void MakeBoundsChangeUndoable(bool allowMerge);
|
||||
|
||||
EditStatus DefaultEditMode { get; }
|
||||
|
||||
/// <summary>
|
||||
|
@ -93,23 +70,10 @@ namespace Greenshot.Base.Interfaces.Drawing
|
|||
/// </summary>
|
||||
IList<IAdorner> Adorners { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Is confirm/cancel possible for this container
|
||||
/// </summary>
|
||||
bool IsConfirmable { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Adjust UI elements to the supplied DPI settings
|
||||
/// </summary>
|
||||
/// <param name="dpi">int</param>
|
||||
void AdjustToDpi(int dpi);
|
||||
|
||||
/// <summary>
|
||||
/// Enable a way for elements to add a context menu entry
|
||||
/// </summary>
|
||||
/// <param name="menu">ContextMenuStrip</param>
|
||||
/// <param name="surface">ISurface</param>
|
||||
/// <param name="mouseEventArgs">MouseEventArgs</param>
|
||||
void AddContextMenuItems(ContextMenuStrip menu, ISurface surface, MouseEventArgs mouseEventArgs);
|
||||
/// <param name="dpi">uint</param>
|
||||
void AdjustToDpi(uint dpi);
|
||||
}
|
||||
}
|
|
@ -24,7 +24,6 @@ using System.Collections.Generic;
|
|||
using System.Drawing;
|
||||
using System.Drawing.Drawing2D;
|
||||
using System.Windows.Forms;
|
||||
using Dapplo.Windows.Common.Structs;
|
||||
|
||||
namespace Greenshot.Base.Interfaces.Drawing
|
||||
{
|
||||
|
@ -36,16 +35,16 @@ namespace Greenshot.Base.Interfaces.Drawing
|
|||
|
||||
ISurface Parent { get; set; }
|
||||
EditStatus Status { get; set; }
|
||||
NativeRect DrawingBounds { get; }
|
||||
Rectangle DrawingBounds { get; }
|
||||
void MakeBoundsChangeUndoable(bool allowMerge);
|
||||
void Transform(Matrix matrix);
|
||||
void MoveBy(int dx, int dy);
|
||||
bool ClickableAt(int x, int y);
|
||||
IDrawableContainer ClickableElementAt(int x, int y);
|
||||
void OnDoubleClick();
|
||||
bool HasIntersectingFilters(NativeRect clipRectangle);
|
||||
bool IntersectsWith(NativeRect clipRectangle);
|
||||
void Draw(Graphics g, Bitmap bitmap, RenderMode renderMode, NativeRect clipRectangle);
|
||||
bool HasIntersectingFilters(Rectangle clipRectangle);
|
||||
bool IntersectsWith(Rectangle clipRectangle);
|
||||
void Draw(Graphics g, Bitmap bitmap, RenderMode renderMode, Rectangle clipRectangle);
|
||||
void SetForegroundColor(Color color);
|
||||
void SetBackgroundColor(Color color);
|
||||
int IncreaseLineThickness(int increaseBy);
|
||||
|
@ -59,6 +58,6 @@ namespace Greenshot.Base.Interfaces.Drawing
|
|||
void PushElementsToBottom(IDrawableContainerList elements);
|
||||
void ShowContextMenu(MouseEventArgs e, ISurface surface);
|
||||
void HandleFieldChangedEvent(object sender, FieldChangedEventArgs e);
|
||||
void AdjustToDpi(int dpi);
|
||||
void AdjustToDpi(uint dpi);
|
||||
}
|
||||
}
|
|
@ -21,7 +21,6 @@
|
|||
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using Dapplo.Windows.Common.Structs;
|
||||
|
||||
namespace Greenshot.Base.Interfaces
|
||||
{
|
||||
|
@ -48,7 +47,7 @@ namespace Greenshot.Base.Interfaces
|
|||
/// <summary>
|
||||
/// Bounds on the screen from which the capture comes
|
||||
/// </summary>
|
||||
NativeRect ScreenBounds { get; set; }
|
||||
Rectangle ScreenBounds { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The cursor
|
||||
|
@ -63,18 +62,18 @@ namespace Greenshot.Base.Interfaces
|
|||
/// <summary>
|
||||
/// Location of the cursor
|
||||
/// </summary>
|
||||
NativePoint CursorLocation { get; set; }
|
||||
Point CursorLocation { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Location of the capture
|
||||
/// </summary>
|
||||
NativePoint Location { get; set; }
|
||||
Point Location { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Crops the capture to the specified rectangle (with Bitmap coordinates!)
|
||||
/// </summary>
|
||||
/// <param name="cropRectangle">NativeRect with bitmap coordinates</param>
|
||||
bool Crop(NativeRect cropRectangle);
|
||||
/// <param name="cropRectangle">Rectangle with bitmap coordinates</param>
|
||||
bool Crop(Rectangle cropRectangle);
|
||||
|
||||
/// <summary>
|
||||
/// Apply a translate to the mouse location. e.g. needed for crop
|
||||
|
|
|
@ -1,88 +0,0 @@
|
|||
/*
|
||||
* Greenshot - a free and open source screenshot tool
|
||||
* Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
|
||||
*
|
||||
* For more information see: https://getgreenshot.org/
|
||||
* The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using Greenshot.Base.Interfaces.Drawing;
|
||||
using Greenshot.Base.Interfaces.Plugin;
|
||||
|
||||
namespace Greenshot.Base.Interfaces
|
||||
{
|
||||
/// <summary>
|
||||
/// The possible actions a IFileFormatHandler might support
|
||||
/// </summary>
|
||||
public enum FileFormatHandlerActions
|
||||
{
|
||||
SaveToStream,
|
||||
LoadFromStream,
|
||||
LoadDrawableFromStream
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This interface is for code to implement the loading and saving of certain file formats
|
||||
/// </summary>
|
||||
public interface IFileFormatHandler
|
||||
{
|
||||
/// <summary>
|
||||
/// Registry for all the extensions this IFileFormatHandler support
|
||||
/// </summary>
|
||||
IDictionary<FileFormatHandlerActions, IReadOnlyCollection<string>> SupportedExtensions { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Priority (from high int.MinValue, low int.MaxValue) of this IFileFormatHandler for the specified action and extension
|
||||
/// This should be used to sort the possible IFileFormatHandler
|
||||
/// </summary>
|
||||
/// <param name="fileFormatHandlerAction">FileFormatHandlerActions</param>
|
||||
/// <param name="extension">string</param>
|
||||
/// <returns>int specifying the priority for the action and extension</returns>
|
||||
public int PriorityFor(FileFormatHandlerActions fileFormatHandlerAction, string extension);
|
||||
|
||||
/// <summary>
|
||||
/// Try to save the specified bitmap to the stream in the format belonging to the extension
|
||||
/// </summary>
|
||||
/// <param name="bitmap">Bitmap</param>
|
||||
/// <param name="destination">Stream</param>
|
||||
/// <param name="extension">extension</param>
|
||||
/// <param name="surface">ISurface with the elements for those file types which can store a surface (.greenshot)</param>
|
||||
/// <param name="surfaceOutputSettings">SurfaceOutputSettings</param>
|
||||
/// <returns>bool true if it was successful</returns>
|
||||
public bool TrySaveToStream(Bitmap bitmap, Stream destination, string extension, ISurface surface = null, SurfaceOutputSettings surfaceOutputSettings = null);
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="stream"></param>
|
||||
/// <param name="extension"></param>
|
||||
/// <param name="bitmap"></param>
|
||||
/// <returns>bool true if it was successful</returns>
|
||||
public bool TryLoadFromStream(Stream stream, string extension, out Bitmap bitmap);
|
||||
|
||||
/// <summary>
|
||||
/// Try to load a drawable container from the stream
|
||||
/// </summary>
|
||||
/// <param name="stream">Stream</param>
|
||||
/// <param name="extension">string</param>
|
||||
/// <param name="parentSurface">ISurface</param>
|
||||
/// <returns>IEnumerable{IDrawableContainer}</returns>
|
||||
public IEnumerable<IDrawableContainer> LoadDrawablesFromStream(Stream stream, string extension, ISurface parentSurface = null);
|
||||
}
|
||||
}
|
|
@ -32,7 +32,7 @@ namespace Greenshot.Base.Interfaces
|
|||
/// </summary>
|
||||
/// <typeparam name="TService">Service to find</typeparam>
|
||||
/// <returns>IEnumerable{TService}</returns>
|
||||
IReadOnlyList<TService> GetAllInstances<TService>();
|
||||
IEnumerable<TService> GetAllInstances<TService>();
|
||||
|
||||
/// <summary>
|
||||
/// Get the only instance of the specified service
|
||||
|
|
|
@ -21,10 +21,8 @@
|
|||
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Drawing2D;
|
||||
using System.IO;
|
||||
using System.Windows.Forms;
|
||||
using Dapplo.Windows.Common.Structs;
|
||||
using Greenshot.Base.Core;
|
||||
using Greenshot.Base.Effects;
|
||||
using Greenshot.Base.Interfaces.Drawing;
|
||||
|
@ -102,49 +100,13 @@ namespace Greenshot.Base.Interfaces
|
|||
long SaveElementsToStream(Stream stream);
|
||||
void LoadElementsFromStream(Stream stream);
|
||||
|
||||
/// <summary>
|
||||
/// Provides the selected elements
|
||||
/// </summary>
|
||||
IDrawableContainerList SelectedElements { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Is there an element selected on the surface?
|
||||
/// </summary>
|
||||
bool HasSelectedElements { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Remove all selected elements
|
||||
/// </summary>
|
||||
void RemoveSelectedElements();
|
||||
|
||||
/// <summary>
|
||||
/// Cut the selected elements to the clipboard
|
||||
/// </summary>
|
||||
void CutSelectedElements();
|
||||
|
||||
/// <summary>
|
||||
/// Copy the selected elements to the clipboard
|
||||
/// </summary>
|
||||
void CopySelectedElements();
|
||||
|
||||
/// <summary>
|
||||
/// Paste the elements from the clipboard
|
||||
/// </summary>
|
||||
void PasteElementFromClipboard();
|
||||
|
||||
/// <summary>
|
||||
/// Duplicate the selected elements
|
||||
/// </summary>
|
||||
void DuplicateSelectedElements();
|
||||
|
||||
/// <summary>
|
||||
/// Deselected the specified element
|
||||
/// </summary>
|
||||
void DeselectElement(IDrawableContainer container, bool generateEvents = true);
|
||||
|
||||
/// <summary>
|
||||
/// Deselected all elements
|
||||
/// </summary>
|
||||
void DeselectAllElements();
|
||||
|
||||
/// <summary>
|
||||
|
@ -186,8 +148,8 @@ namespace Greenshot.Base.Interfaces
|
|||
/// Invalidates the specified region of the Surface.
|
||||
/// Takes care of the Surface zoom level, accepts rectangle in the coordinate space of the Image.
|
||||
/// </summary>
|
||||
/// <param name="rectangleToInvalidate">NativeRect Bounding rectangle for updated elements, in the coordinate space of the Image.</param>
|
||||
void InvalidateElements(NativeRect rectangleToInvalidate);
|
||||
/// <param name="rectangleToInvalidate">Bounding rectangle for updated elements, in the coordinate space of the Image.</param>
|
||||
void InvalidateElements(Rectangle rectangleToInvalidate);
|
||||
|
||||
bool Modified { get; set; }
|
||||
string LastSaveFullPath { get; set; }
|
||||
|
@ -215,54 +177,29 @@ namespace Greenshot.Base.Interfaces
|
|||
Fraction ZoomFactor { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Translate a point from image coordinate space to surface coordinate space.
|
||||
/// Translate a point from image coorditate space to surface coordinate space.
|
||||
/// </summary>
|
||||
/// <param name="point">A point in the coordinate space of the image.</param>
|
||||
NativePoint ToSurfaceCoordinates(NativePoint point);
|
||||
Point ToSurfaceCoordinates(Point point);
|
||||
|
||||
/// <summary>
|
||||
/// Translate a rectangle from image coordinate space to surface coordinate space.
|
||||
/// Translate a rectangle from image coorditate space to surface coordinate space.
|
||||
/// </summary>
|
||||
/// <param name="rc">NativeRect in the coordinate space of the image.</param>
|
||||
NativeRect ToSurfaceCoordinates(NativeRect rc);
|
||||
/// <param name="rc">A rectangle in the coordinate space of the image.</param>
|
||||
Rectangle ToSurfaceCoordinates(Rectangle rc);
|
||||
|
||||
/// <summary>
|
||||
/// Translate a point from surface coordinate space to image coordinate space.
|
||||
/// Translate a point from surface coorditate space to image coordinate space.
|
||||
/// </summary>
|
||||
/// <param name="point">NativePoint in the coordinate space of the surface.</param>
|
||||
NativePoint ToImageCoordinates(NativePoint point);
|
||||
/// <param name="point">A point in the coordinate space of the surface.</param>
|
||||
Point ToImageCoordinates(Point point);
|
||||
|
||||
/// <summary>
|
||||
/// Translate a NativeRect from surface coordinate space to image coordinate space.
|
||||
/// Translate a rectangle from surface coorditate space to image coordinate space.
|
||||
/// </summary>
|
||||
/// <param name="rc">NativeRect in the coordinate space of the surface.</param>
|
||||
NativeRect ToImageCoordinates(NativeRect rc);
|
||||
/// <param name="rc">A rectangle in the coordinate space of the surface.</param>
|
||||
Rectangle ToImageCoordinates(Rectangle rc);
|
||||
|
||||
/// <summary>
|
||||
/// Make it possible to undo the specified IMemento
|
||||
/// </summary>
|
||||
/// <param name="memento">IMemento</param>
|
||||
/// <param name="allowMerge">bool to specify if the action can be merged, e.g. we do not want an undo for every part of a resize</param>
|
||||
void MakeUndoable(IMemento memento, bool allowMerge);
|
||||
|
||||
/// <summary>
|
||||
/// The IFieldAggregator
|
||||
/// </summary>
|
||||
IFieldAggregator FieldAggregator { get; }
|
||||
|
||||
/// <summary>
|
||||
/// This reverses a change of the background image
|
||||
/// </summary>
|
||||
/// <param name="previous">Image</param>
|
||||
/// <param name="matrix">Matrix</param>
|
||||
void UndoBackgroundChange(Image previous, Matrix matrix);
|
||||
|
||||
/// <summary>
|
||||
/// The most recent DPI value that was used
|
||||
/// </summary>
|
||||
public int CurrentDpi
|
||||
{
|
||||
get;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,26 +1,4 @@
|
|||
/*
|
||||
* Greenshot - a free and open source screenshot tool
|
||||
* Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
|
||||
*
|
||||
* For more information see: https://getgreenshot.org/
|
||||
* The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using Dapplo.Windows.Common.Extensions;
|
||||
using Dapplo.Windows.Common.Structs;
|
||||
using System.Drawing;
|
||||
|
||||
namespace Greenshot.Base.Interfaces.Ocr
|
||||
{
|
||||
|
@ -29,7 +7,7 @@ namespace Greenshot.Base.Interfaces.Ocr
|
|||
/// </summary>
|
||||
public class Line
|
||||
{
|
||||
private NativeRect? _calculatedBounds;
|
||||
private Rectangle? _calculatedBounds;
|
||||
|
||||
/// <summary>
|
||||
/// Constructor will preallocate the number of words
|
||||
|
@ -57,18 +35,18 @@ namespace Greenshot.Base.Interfaces.Ocr
|
|||
/// <summary>
|
||||
/// Calculate the bounds of the words
|
||||
/// </summary>
|
||||
/// <returns>NativeRect</returns>
|
||||
private NativeRect CalculateBounds()
|
||||
/// <returns>Rectangle</returns>
|
||||
private Rectangle CalculateBounds()
|
||||
{
|
||||
if (Words.Length == 0)
|
||||
{
|
||||
return NativeRect.Empty;
|
||||
return Rectangle.Empty;
|
||||
}
|
||||
|
||||
var result = Words[0].Bounds;
|
||||
for (var index = 0; index < Words.Length; index++)
|
||||
{
|
||||
result = result.Union(Words[index].Bounds);
|
||||
result = Rectangle.Union(result, Words[index].Bounds);
|
||||
}
|
||||
|
||||
return result;
|
||||
|
@ -77,7 +55,7 @@ namespace Greenshot.Base.Interfaces.Ocr
|
|||
/// <summary>
|
||||
/// Return the calculated bounds for the whole line
|
||||
/// </summary>
|
||||
public NativeRect CalculatedBounds
|
||||
public Rectangle CalculatedBounds
|
||||
{
|
||||
get { return _calculatedBounds ??= CalculateBounds(); }
|
||||
}
|
||||
|
@ -91,7 +69,9 @@ namespace Greenshot.Base.Interfaces.Ocr
|
|||
{
|
||||
foreach (var word in Words)
|
||||
{
|
||||
word.Bounds = word.Bounds.Offset(x, y);
|
||||
var location = word.Bounds;
|
||||
location.Offset(x, y);
|
||||
word.Bounds = location;
|
||||
}
|
||||
|
||||
_calculatedBounds = null;
|
||||
|
|
|
@ -1,25 +1,4 @@
|
|||
/*
|
||||
* Greenshot - a free and open source screenshot tool
|
||||
* Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
|
||||
*
|
||||
* For more information see: https://getgreenshot.org/
|
||||
* The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
|
|
|
@ -1,25 +1,4 @@
|
|||
/*
|
||||
* Greenshot - a free and open source screenshot tool
|
||||
* Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
|
||||
*
|
||||
* For more information see: https://getgreenshot.org/
|
||||
* The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using Dapplo.Windows.Common.Structs;
|
||||
using System.Drawing;
|
||||
|
||||
namespace Greenshot.Base.Interfaces.Ocr
|
||||
{
|
||||
|
@ -36,6 +15,6 @@ namespace Greenshot.Base.Interfaces.Ocr
|
|||
/// <summary>
|
||||
/// The bounds of the word
|
||||
/// </summary>
|
||||
public NativeRect Bounds { get; set; }
|
||||
public Rectangle Bounds { get; set; }
|
||||
}
|
||||
}
|
|
@ -1,46 +0,0 @@
|
|||
/*
|
||||
* Greenshot - a free and open source screenshot tool
|
||||
* Copyright (C) 2007-2025 Thomas Braun, Jens Klingen, Robin Krom
|
||||
*
|
||||
* For more information see: https://getgreenshot.org/
|
||||
* The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using System;
|
||||
|
||||
namespace Greenshot.Base.Interfaces.Plugin
|
||||
{
|
||||
/// <summary>
|
||||
/// Attribute to specify a custom plugin identifier at assembly level
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = false)]
|
||||
public class AssemblyPluginIdentifierAttribute : Attribute
|
||||
{
|
||||
/// <summary>
|
||||
/// The identifier used for the plugin in configuration
|
||||
/// </summary>
|
||||
public string Identifier { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Constructor for the plugin identifier attribute
|
||||
/// </summary>
|
||||
/// <param name="identifier">The identifier for the plugin in configuration</param>
|
||||
public AssemblyPluginIdentifierAttribute(string identifier)
|
||||
{
|
||||
Identifier = identifier;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,25 +1,4 @@
|
|||
/*
|
||||
* Greenshot - a free and open source screenshot tool
|
||||
* Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
|
||||
*
|
||||
* For more information see: https://getgreenshot.org/
|
||||
* The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using Greenshot.Base.Core;
|
||||
using Greenshot.Base.Core.Enums;
|
||||
using Greenshot.Base.Effects;
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
*/
|
||||
|
||||
using System;
|
||||
using System.Drawing;
|
||||
|
||||
namespace Greenshot.Base.Interfaces
|
||||
{
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
*/
|
||||
|
||||
using System;
|
||||
using System.Drawing;
|
||||
|
||||
namespace Greenshot.Base.Interfaces
|
||||
{
|
||||
|
|
123
src/Greenshot.Base/UnmanagedHelpers/DWM.cs
Normal file
123
src/Greenshot.Base/UnmanagedHelpers/DWM.cs
Normal file
|
@ -0,0 +1,123 @@
|
|||
/*
|
||||
* Greenshot - a free and open source screenshot tool
|
||||
* Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
|
||||
*
|
||||
* For more information see: https://getgreenshot.org/
|
||||
* The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Runtime.InteropServices;
|
||||
using Greenshot.Base.Core;
|
||||
using Greenshot.Base.Core.Enums;
|
||||
using Greenshot.Base.UnmanagedHelpers.Enums;
|
||||
using Greenshot.Base.UnmanagedHelpers.Structs;
|
||||
using Microsoft.Win32;
|
||||
|
||||
namespace Greenshot.Base.UnmanagedHelpers
|
||||
{
|
||||
/// <summary>
|
||||
/// Desktop Window Manager helper code
|
||||
/// </summary>
|
||||
public static class DWM
|
||||
{
|
||||
// DWM
|
||||
[DllImport("dwmapi", SetLastError = true)]
|
||||
public static extern int DwmRegisterThumbnail(IntPtr dest, IntPtr src, out IntPtr thumb);
|
||||
|
||||
[DllImport("dwmapi", SetLastError = true)]
|
||||
public static extern int DwmUnregisterThumbnail(IntPtr thumb);
|
||||
|
||||
[DllImport("dwmapi", SetLastError = true)]
|
||||
public static extern HResult DwmQueryThumbnailSourceSize(IntPtr thumb, out SIZE size);
|
||||
|
||||
[DllImport("dwmapi", SetLastError = true)]
|
||||
public static extern HResult DwmUpdateThumbnailProperties(IntPtr hThumb, ref DWM_THUMBNAIL_PROPERTIES props);
|
||||
|
||||
// Deprecated as of Windows 8 Release Preview
|
||||
[DllImport("dwmapi", SetLastError = true)]
|
||||
public static extern int DwmIsCompositionEnabled(out bool enabled);
|
||||
|
||||
[DllImport("dwmapi", SetLastError = true)]
|
||||
public static extern int DwmGetWindowAttribute(IntPtr hWnd, DWMWINDOWATTRIBUTE dwAttribute, out RECT lpRect, int size);
|
||||
|
||||
[DllImport("dwmapi", SetLastError = true)]
|
||||
public static extern int DwmGetWindowAttribute(IntPtr hWnd, DWMWINDOWATTRIBUTE dwAttribute, out bool pvAttribute, int cbAttribute);
|
||||
|
||||
// Key to ColorizationColor for DWM
|
||||
private const string COLORIZATION_COLOR_KEY = @"SOFTWARE\Microsoft\Windows\DWM";
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the window is cloaked, this should solve some issues with the window selection code
|
||||
/// </summary>
|
||||
/// <param name="hWnd">IntPtr as hWmd</param>
|
||||
/// <returns>bool</returns>
|
||||
public static bool IsWindowCloaked(IntPtr hWnd)
|
||||
{
|
||||
if (!WindowsVersion.IsWindows8OrLater)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
DwmGetWindowAttribute(hWnd, DWMWINDOWATTRIBUTE.DWMWA_CLOAKED, out bool isCloaked, Marshal.SizeOf(typeof(bool)));
|
||||
return isCloaked;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper method for an easy DWM check
|
||||
/// </summary>
|
||||
/// <returns>bool true if DWM is available AND active</returns>
|
||||
public static bool IsDwmEnabled
|
||||
{
|
||||
get
|
||||
{
|
||||
// According to: https://technet.microsoft.com/en-us/subscriptions/aa969538%28v=vs.85%29.aspx
|
||||
// And: https://docs.microsoft.com/en-gb/windows/win32/api/dwmapi/nf-dwmapi-dwmenablecomposition
|
||||
// DMW is always enabled on Windows 8! So return true and save a check! ;-)
|
||||
if (WindowsVersion.IsWindows8OrLater)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (WindowsVersion.IsWindowsVistaOrLater)
|
||||
{
|
||||
DwmIsCompositionEnabled(out var dwmEnabled);
|
||||
return dwmEnabled;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static Color ColorizationColor
|
||||
{
|
||||
get
|
||||
{
|
||||
using (RegistryKey key = Registry.CurrentUser.OpenSubKey(COLORIZATION_COLOR_KEY, false))
|
||||
{
|
||||
object dwordValue = key?.GetValue("ColorizationColor");
|
||||
if (dwordValue != null)
|
||||
{
|
||||
return Color.FromArgb((int) dwordValue);
|
||||
}
|
||||
}
|
||||
|
||||
return Color.White;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
/*
|
||||
/*
|
||||
* Greenshot - a free and open source screenshot tool
|
||||
* Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
|
||||
*
|
||||
|
@ -19,16 +19,15 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace Greenshot.Base.Interfaces
|
||||
using System;
|
||||
|
||||
namespace Greenshot.Base.UnmanagedHelpers
|
||||
{
|
||||
/// <summary>
|
||||
/// IProvideDeviceDpi can provide the current DPI for a component
|
||||
/// Used with EnumWindows or EnumChildWindows
|
||||
/// </summary>
|
||||
public interface IProvideDeviceDpi
|
||||
{
|
||||
/// <summary>
|
||||
/// A simple getter for the current DPI
|
||||
/// </summary>
|
||||
int DeviceDpi { get; }
|
||||
}
|
||||
/// <param name="hWnd">IntPtr</param>
|
||||
/// <param name="lParam">int</param>
|
||||
/// <returns>int</returns>
|
||||
public delegate int EnumWindowsProc(IntPtr hWnd, int lParam);
|
||||
}
|
32
src/Greenshot.Base/UnmanagedHelpers/Enums/ClassLongIndex.cs
Normal file
32
src/Greenshot.Base/UnmanagedHelpers/Enums/ClassLongIndex.cs
Normal file
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* Greenshot - a free and open source screenshot tool
|
||||
* Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
|
||||
*
|
||||
* For more information see: https://getgreenshot.org/
|
||||
* The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace Greenshot.Base.UnmanagedHelpers.Enums
|
||||
{
|
||||
[SuppressMessage("ReSharper", "InconsistentNaming")]
|
||||
public enum ClassLongIndex
|
||||
{
|
||||
GCL_HICON = -14, // a handle to the icon associated with the class.
|
||||
GCL_HICONSM = -34, // a handle to the small icon associated with the class.
|
||||
}
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* Greenshot - a free and open source screenshot tool
|
||||
* Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
|
||||
*
|
||||
* For more information see: https://getgreenshot.org/
|
||||
* The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace Greenshot.Base.UnmanagedHelpers.Enums
|
||||
{
|
||||
[SuppressMessage("ReSharper", "InconsistentNaming")]
|
||||
public enum DWMWINDOWATTRIBUTE : uint
|
||||
{
|
||||
DWMWA_NCRENDERING_ENABLED = 1,
|
||||
DWMWA_NCRENDERING_POLICY,
|
||||
DWMWA_TRANSITIONS_FORCEDISABLED,
|
||||
DWMWA_ALLOW_NCPAINT,
|
||||
DWMWA_CAPTION_BUTTON_BOUNDS,
|
||||
DWMWA_NONCLIENT_RTL_LAYOUT,
|
||||
DWMWA_FORCE_ICONIC_REPRESENTATION,
|
||||
DWMWA_FLIP3D_POLICY,
|
||||
DWMWA_EXTENDED_FRAME_BOUNDS, // This is the one we need for retrieving the Window size since Windows Vista
|
||||
DWMWA_HAS_ICONIC_BITMAP, // Since Windows 7
|
||||
DWMWA_DISALLOW_PEEK, // Since Windows 7
|
||||
DWMWA_EXCLUDED_FROM_PEEK, // Since Windows 7
|
||||
DWMWA_CLOAK, // Since Windows 8
|
||||
DWMWA_CLOAKED, // Since Windows 8
|
||||
DWMWA_FREEZE_REPRESENTATION, // Since Windows 8
|
||||
DWMWA_LAST
|
||||
}
|
||||
}
|
|
@ -0,0 +1,111 @@
|
|||
/*
|
||||
* Greenshot - a free and open source screenshot tool
|
||||
* Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
|
||||
*
|
||||
* For more information see: https://getgreenshot.org/
|
||||
* The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using System.Runtime.InteropServices;
|
||||
using Greenshot.Base.UnmanagedHelpers.Structs;
|
||||
|
||||
namespace Greenshot.Base.UnmanagedHelpers.Enums
|
||||
{
|
||||
/// <summary>
|
||||
/// See <a href="https://docs.microsoft.com/en-gb/windows/win32/api/dwmapi/ns-dwmapi-dwm_thumbnail_properties">DWM_THUMBNAIL_PROPERTIES</a>
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct DWM_THUMBNAIL_PROPERTIES
|
||||
{
|
||||
// A bitwise combination of DWM thumbnail constant values that indicates which members of this structure are set.
|
||||
public int dwFlags;
|
||||
|
||||
// The area in the destination window where the thumbnail will be rendered.
|
||||
public RECT rcDestination;
|
||||
|
||||
// The region of the source window to use as the thumbnail. By default, the entire window is used as the thumbnail.
|
||||
public RECT rcSource;
|
||||
|
||||
// The opacity with which to render the thumbnail. 0 is fully transparent while 255 is fully opaque. The default value is 255.
|
||||
public byte opacity;
|
||||
|
||||
// TRUE to make the thumbnail visible; otherwise, FALSE. The default is FALSE.
|
||||
public bool fVisible;
|
||||
|
||||
// TRUE to use only the thumbnail source's client area; otherwise, FALSE. The default is FALSE.
|
||||
public bool fSourceClientAreaOnly;
|
||||
|
||||
public RECT Destination
|
||||
{
|
||||
set
|
||||
{
|
||||
dwFlags |= DWM_TNP_RECTDESTINATION;
|
||||
rcDestination = value;
|
||||
}
|
||||
}
|
||||
|
||||
public RECT Source
|
||||
{
|
||||
set
|
||||
{
|
||||
dwFlags |= DWM_TNP_RECTSOURCE;
|
||||
rcSource = value;
|
||||
}
|
||||
}
|
||||
|
||||
public byte Opacity
|
||||
{
|
||||
set
|
||||
{
|
||||
dwFlags |= DWM_TNP_OPACITY;
|
||||
opacity = value;
|
||||
}
|
||||
}
|
||||
|
||||
public bool Visible
|
||||
{
|
||||
set
|
||||
{
|
||||
dwFlags |= DWM_TNP_VISIBLE;
|
||||
fVisible = value;
|
||||
}
|
||||
}
|
||||
|
||||
public bool SourceClientAreaOnly
|
||||
{
|
||||
set
|
||||
{
|
||||
dwFlags |= DWM_TNP_SOURCECLIENTAREAONLY;
|
||||
fSourceClientAreaOnly = value;
|
||||
}
|
||||
}
|
||||
|
||||
// A value for the rcDestination member has been specified.
|
||||
public const int DWM_TNP_RECTDESTINATION = 0x00000001;
|
||||
|
||||
// A value for the rcSource member has been specified.
|
||||
public const int DWM_TNP_RECTSOURCE = 0x00000002;
|
||||
|
||||
// A value for the opacity member has been specified.
|
||||
public const int DWM_TNP_OPACITY = 0x00000004;
|
||||
|
||||
// A value for the fVisible member has been specified.
|
||||
public const int DWM_TNP_VISIBLE = 0x00000008;
|
||||
|
||||
// A value for the fSourceClientAreaOnly member has been specified.
|
||||
public const int DWM_TNP_SOURCECLIENTAREAONLY = 0x00000010;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* Greenshot - a free and open source screenshot tool
|
||||
* Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
|
||||
*
|
||||
* For more information see: https://getgreenshot.org/
|
||||
* The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace Greenshot.Base.UnmanagedHelpers.Enums
|
||||
{
|
||||
[Flags]
|
||||
[SuppressMessage("ReSharper", "InconsistentNaming")]
|
||||
public enum DesktopAccessRight : uint
|
||||
{
|
||||
DESKTOP_READOBJECTS = 0x00000001,
|
||||
DESKTOP_CREATEWINDOW = 0x00000002,
|
||||
DESKTOP_CREATEMENU = 0x00000004,
|
||||
DESKTOP_HOOKCONTROL = 0x00000008,
|
||||
DESKTOP_JOURNALRECORD = 0x00000010,
|
||||
DESKTOP_JOURNALPLAYBACK = 0x00000020,
|
||||
DESKTOP_ENUMERATE = 0x00000040,
|
||||
DESKTOP_WRITEOBJECTS = 0x00000080,
|
||||
DESKTOP_SWITCHDESKTOP = 0x00000100,
|
||||
|
||||
GENERIC_ALL = (DESKTOP_READOBJECTS | DESKTOP_CREATEWINDOW | DESKTOP_CREATEMENU |
|
||||
DESKTOP_HOOKCONTROL | DESKTOP_JOURNALRECORD | DESKTOP_JOURNALPLAYBACK |
|
||||
DESKTOP_ENUMERATE | DESKTOP_WRITEOBJECTS | DESKTOP_SWITCHDESKTOP)
|
||||
};
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
/*
|
||||
/*
|
||||
* Greenshot - a free and open source screenshot tool
|
||||
* Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
|
||||
*
|
||||
|
@ -19,26 +19,25 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace Greenshot.Editor.Helpers
|
||||
namespace Greenshot.Base.UnmanagedHelpers.Enums
|
||||
{
|
||||
[Flags]
|
||||
public enum ScaleOptions
|
||||
/// <summary>
|
||||
/// Used by GDI32.GetDeviceCaps
|
||||
/// See <a href="https://docs.microsoft.com/en-gb/windows/win32/api/wingdi/nf-wingdi-getdevicecaps">GetDeviceCaps</a>
|
||||
/// </summary>
|
||||
[SuppressMessage("ReSharper", "InconsistentNaming")]
|
||||
public enum DeviceCaps
|
||||
{
|
||||
/// <summary>
|
||||
/// Default scale behavior.
|
||||
/// Logical pixels inch in X
|
||||
/// </summary>
|
||||
Default = 0x00,
|
||||
LOGPIXELSX = 88,
|
||||
|
||||
/// <summary>
|
||||
/// Scale a rectangle in two our four directions, mirrored at it's center coordinates
|
||||
/// Current vertical refresh rate of the display device (for displays only) in Hz
|
||||
/// </summary>
|
||||
Centered = 0x01,
|
||||
|
||||
/// <summary>
|
||||
/// Scale a rectangle maintaining it's aspect ratio
|
||||
/// </summary>
|
||||
Rational = 0x02
|
||||
VREFRESH = 116
|
||||
}
|
||||
}
|
34
src/Greenshot.Base/UnmanagedHelpers/Enums/EventObjects.cs
Normal file
34
src/Greenshot.Base/UnmanagedHelpers/Enums/EventObjects.cs
Normal file
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* Greenshot - a free and open source screenshot tool
|
||||
* Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
|
||||
*
|
||||
* For more information see: https://getgreenshot.org/
|
||||
* The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace Greenshot.Base.UnmanagedHelpers.Enums
|
||||
{
|
||||
/// <summary>
|
||||
/// See <a href="https://docs.microsoft.com/en-gb/windows/win32/winauto/object-identifiers">Object Identifiers</a>
|
||||
/// </summary>
|
||||
[SuppressMessage("ReSharper", "InconsistentNaming")]
|
||||
public enum EventObjects
|
||||
{
|
||||
OBJID_WINDOW = 0
|
||||
}
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
* Greenshot - a free and open source screenshot tool
|
||||
* Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
|
||||
*
|
||||
* For more information see: https://getgreenshot.org/
|
||||
* The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace Greenshot.Base.UnmanagedHelpers.Enums
|
||||
{
|
||||
[Flags]
|
||||
[SuppressMessage("ReSharper", "InconsistentNaming")]
|
||||
public enum ExtendedWindowStyleFlags : uint
|
||||
{
|
||||
WS_EX_DLGMODALFRAME = 0x00000001,
|
||||
WS_EX_NOPARENTNOTIFY = 0x00000004,
|
||||
WS_EX_TOPMOST = 0x00000008,
|
||||
WS_EX_ACCEPTFILES = 0x00000010,
|
||||
WS_EX_TRANSPARENT = 0x00000020,
|
||||
|
||||
//#if(WINVER >= 0x0400)
|
||||
WS_EX_MDICHILD = 0x00000040,
|
||||
WS_EX_TOOLWINDOW = 0x00000080,
|
||||
WS_EX_WINDOWEDGE = 0x00000100,
|
||||
WS_EX_CLIENTEDGE = 0x00000200,
|
||||
WS_EX_CONTEXTHELP = 0x00000400,
|
||||
|
||||
WS_EX_RIGHT = 0x00001000,
|
||||
WS_EX_LEFT = 0x00000000,
|
||||
WS_EX_RTLREADING = 0x00002000,
|
||||
WS_EX_LTRREADING = 0x00000000,
|
||||
WS_EX_LEFTSCROLLBAR = 0x00004000,
|
||||
WS_EX_RIGHTSCROLLBAR = 0x00000000,
|
||||
|
||||
WS_EX_CONTROLPARENT = 0x00010000,
|
||||
WS_EX_STATICEDGE = 0x00020000,
|
||||
WS_EX_APPWINDOW = 0x00040000,
|
||||
|
||||
//WS_EX_OVERLAPPEDWINDOW = (WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE),
|
||||
//WS_EX_PALETTEWINDOW = (WS_EX_WINDOWEDGE | WS_EX_TOOLWINDOW | WS_EX_TOPMOST),
|
||||
|
||||
WS_EX_LAYERED = 0x00080000,
|
||||
WS_EX_NOINHERITLAYOUT = 0x00100000, // Disable inheritence of mirroring by children
|
||||
WS_EX_NOREDIRECTIONBITMAP = 0x00200000, //The window does not render to a redirection surface. This is for windows that do not have visible content or that use mechanisms other than surfaces to provide their visual.
|
||||
WS_EX_LAYOUTRTL = 0x00400000, // Right to left mirroring
|
||||
/// <summary>
|
||||
/// Paints all descendants of a window in bottom-to-top painting order using double-buffering.
|
||||
/// Bottom-to-top painting order allows a descendent window to have translucency (alpha) and transparency (color-key) effects, but only if the descendent window also has the WS_EX_TRANSPARENT bit set.
|
||||
/// Double-buffering allows the window and its descendents to be painted without flicker.
|
||||
/// This cannot be used if the window has a class style of either CS_OWNDC or CS_CLASSDC.
|
||||
/// </summary>
|
||||
WS_EX_COMPOSITED = 0x02000000,
|
||||
WS_EX_NOACTIVATE = 0x08000000 // A top-level window created with this style does not become the foreground window when the user clicks it. The system does not bring this window to the foreground when the user minimizes or closes the foreground window.
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* Greenshot - a free and open source screenshot tool
|
||||
* Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
|
||||
*
|
||||
* For more information see: https://getgreenshot.org/
|
||||
* The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace Greenshot.Base.UnmanagedHelpers.Enums
|
||||
{
|
||||
[Flags]
|
||||
[SuppressMessage("ReSharper", "InconsistentNaming")]
|
||||
public enum ProcessAccessFlags : uint
|
||||
{
|
||||
VMRead = 0x00000010,
|
||||
QueryInformation = 0x00000400,
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
/*
|
||||
/*
|
||||
* Greenshot - a free and open source screenshot tool
|
||||
* Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
|
||||
*
|
||||
|
@ -19,10 +19,14 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace Greenshot.Editor.Helpers
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace Greenshot.Base.UnmanagedHelpers.Enums
|
||||
{
|
||||
public interface IDoubleProcessor
|
||||
[SuppressMessage("ReSharper", "InconsistentNaming")]
|
||||
public enum RegionResult
|
||||
{
|
||||
double Process(double d);
|
||||
REGION_ERROR = 0,
|
||||
REGION_NULLREGION = 1,
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
/*
|
||||
/*
|
||||
* Greenshot - a free and open source screenshot tool
|
||||
* Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
|
||||
*
|
||||
|
@ -20,20 +20,17 @@
|
|||
*/
|
||||
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace Greenshot.Editor.Helpers
|
||||
namespace Greenshot.Base.UnmanagedHelpers.Enums
|
||||
{
|
||||
public class LineAngleRoundBehavior : IDoubleProcessor
|
||||
/// <summary>
|
||||
/// See: https://www.pinvoke.net/default.aspx/Enums/SendMessageTimeoutFlags.html
|
||||
/// </summary>
|
||||
[Flags]
|
||||
[SuppressMessage("ReSharper", "InconsistentNaming")]
|
||||
public enum SendMessageTimeoutFlags : uint
|
||||
{
|
||||
public static readonly LineAngleRoundBehavior INSTANCE = new();
|
||||
|
||||
private LineAngleRoundBehavior()
|
||||
{
|
||||
}
|
||||
|
||||
public double Process(double angle)
|
||||
{
|
||||
return Math.Round(angle / 15) * 15;
|
||||
}
|
||||
SMTO_NORMAL = 0x0
|
||||
}
|
||||
}
|
110
src/Greenshot.Base/UnmanagedHelpers/Enums/ShowWindowCommand.cs
Normal file
110
src/Greenshot.Base/UnmanagedHelpers/Enums/ShowWindowCommand.cs
Normal file
|
@ -0,0 +1,110 @@
|
|||
/*
|
||||
* Greenshot - a free and open source screenshot tool
|
||||
* Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
|
||||
*
|
||||
* For more information see: https://getgreenshot.org/
|
||||
* The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace Greenshot.Base.UnmanagedHelpers.Enums
|
||||
{
|
||||
[SuppressMessage("ReSharper", "InconsistentNaming")]
|
||||
public enum ShowWindowCommand : uint
|
||||
{
|
||||
/// <summary>
|
||||
/// Hides the window and activates another window.
|
||||
/// </summary>
|
||||
Hide = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Activates and displays a window. If the window is minimized or
|
||||
/// maximized, the system restores it to its original size and position.
|
||||
/// An application should specify this flag when displaying the window
|
||||
/// for the first time.
|
||||
/// </summary>
|
||||
Normal = 1,
|
||||
|
||||
/// <summary>
|
||||
/// Activates the window and displays it as a minimized window.
|
||||
/// </summary>
|
||||
ShowMinimized = 2,
|
||||
|
||||
/// <summary>
|
||||
/// Maximizes the specified window.
|
||||
/// </summary>
|
||||
Maximize = 3, // is this the right value?
|
||||
|
||||
/// <summary>
|
||||
/// Activates the window and displays it as a maximized window.
|
||||
/// </summary>
|
||||
ShowMaximized = 3,
|
||||
|
||||
/// <summary>
|
||||
/// Displays a window in its most recent size and position. This value
|
||||
/// is similar to <see cref="Normal"/>, except
|
||||
/// the window is not actived.
|
||||
/// </summary>
|
||||
ShowNoActivate = 4,
|
||||
|
||||
/// <summary>
|
||||
/// Activates the window and displays it in its current size and position.
|
||||
/// </summary>
|
||||
Show = 5,
|
||||
|
||||
/// <summary>
|
||||
/// Minimizes the specified window and activates the next top-level
|
||||
/// window in the Z order.
|
||||
/// </summary>
|
||||
Minimize = 6,
|
||||
|
||||
/// <summary>
|
||||
/// Displays the window as a minimized window. This value is similar to
|
||||
/// <see cref="ShowMinimized"/>, except the
|
||||
/// window is not activated.
|
||||
/// </summary>
|
||||
ShowMinNoActive = 7,
|
||||
|
||||
/// <summary>
|
||||
/// Displays the window in its current size and position. This value is
|
||||
/// similar to <see cref="Show"/>, except the
|
||||
/// window is not activated.
|
||||
/// </summary>
|
||||
ShowNA = 8,
|
||||
|
||||
/// <summary>
|
||||
/// Activates and displays the window. If the window is minimized or
|
||||
/// maximized, the system restores it to its original size and position.
|
||||
/// An application should specify this flag when restoring a minimized window.
|
||||
/// </summary>
|
||||
Restore = 9,
|
||||
|
||||
/// <summary>
|
||||
/// Sets the show state based on the SW_* value specified in the
|
||||
/// STARTUPINFO structure passed to the CreateProcess function by the
|
||||
/// program that started the application.
|
||||
/// </summary>
|
||||
ShowDefault = 10,
|
||||
|
||||
/// <summary>
|
||||
/// <b>Windows 2000/XP:</b> Minimizes a window, even if the thread
|
||||
/// that owns the window is not responding. This flag should only be
|
||||
/// used when minimizing windows from a different thread.
|
||||
/// </summary>
|
||||
ForceMinimize = 11
|
||||
}
|
||||
}
|
39
src/Greenshot.Base/UnmanagedHelpers/Enums/SoundFlags.cs
Normal file
39
src/Greenshot.Base/UnmanagedHelpers/Enums/SoundFlags.cs
Normal file
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Greenshot - a free and open source screenshot tool
|
||||
* Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
|
||||
*
|
||||
* For more information see: https://getgreenshot.org/
|
||||
* The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace Greenshot.Base.UnmanagedHelpers.Enums
|
||||
{
|
||||
/// <summary>
|
||||
/// See: https://msdn.microsoft.com/en-us/library/aa909766.aspx
|
||||
/// </summary>
|
||||
[Flags]
|
||||
[SuppressMessage("ReSharper", "InconsistentNaming")]
|
||||
public enum SoundFlags
|
||||
{
|
||||
SND_ASYNC = 0x0001, // play asynchronously
|
||||
SND_MEMORY = 0x0004, // pszSound points to a memory file
|
||||
SND_NOSTOP = 0x0010, // don't stop any currently playing sound
|
||||
SND_NOWAIT = 0x00002000, // don't wait if the driver is busy
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* Greenshot - a free and open source screenshot tool
|
||||
* Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom, Francis Noel
|
||||
* Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
|
||||
*
|
||||
* For more information see: https://getgreenshot.org/
|
||||
* The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
|
||||
|
@ -19,10 +19,13 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace Greenshot.Editor.Helpers
|
||||
using System;
|
||||
|
||||
namespace Greenshot.Base.UnmanagedHelpers.Enums
|
||||
{
|
||||
public interface IHaveScaleOptions
|
||||
[Flags]
|
||||
public enum ThreadAccess : int
|
||||
{
|
||||
ScaleOptions GetScaleOptions();
|
||||
SUSPEND_RESUME = (0x0002),
|
||||
}
|
||||
}
|
89
src/Greenshot.Base/UnmanagedHelpers/Enums/Win32Error.cs
Normal file
89
src/Greenshot.Base/UnmanagedHelpers/Enums/Win32Error.cs
Normal file
|
@ -0,0 +1,89 @@
|
|||
/*
|
||||
* Greenshot - a free and open source screenshot tool
|
||||
* Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
|
||||
*
|
||||
* For more information see: https://getgreenshot.org/
|
||||
* The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace Greenshot.Base.UnmanagedHelpers.Enums
|
||||
{
|
||||
/// <summary>
|
||||
/// A Win32 error code.
|
||||
/// </summary>
|
||||
public enum Win32Error : uint
|
||||
{
|
||||
Success = 0x0,
|
||||
InvalidFunction = 0x1,
|
||||
FileNotFound = 0x2,
|
||||
PathNotFound = 0x3,
|
||||
TooManyOpenFiles = 0x4,
|
||||
AccessDenied = 0x5,
|
||||
InvalidHandle = 0x6,
|
||||
ArenaTrashed = 0x7,
|
||||
NotEnoughMemory = 0x8,
|
||||
InvalidBlock = 0x9,
|
||||
BadEnvironment = 0xa,
|
||||
BadFormat = 0xb,
|
||||
InvalidAccess = 0xc,
|
||||
InvalidData = 0xd,
|
||||
OutOfMemory = 0xe,
|
||||
InvalidDrive = 0xf,
|
||||
CurrentDirectory = 0x10,
|
||||
NotSameDevice = 0x11,
|
||||
NoMoreFiles = 0x12,
|
||||
WriteProtect = 0x13,
|
||||
BadUnit = 0x14,
|
||||
NotReady = 0x15,
|
||||
BadCommand = 0x16,
|
||||
Crc = 0x17,
|
||||
BadLength = 0x18,
|
||||
Seek = 0x19,
|
||||
NotDosDisk = 0x1a,
|
||||
SectorNotFound = 0x1b,
|
||||
OutOfPaper = 0x1c,
|
||||
WriteFault = 0x1d,
|
||||
ReadFault = 0x1e,
|
||||
GenFailure = 0x1f,
|
||||
SharingViolation = 0x20,
|
||||
LockViolation = 0x21,
|
||||
WrongDisk = 0x22,
|
||||
SharingBufferExceeded = 0x24,
|
||||
HandleEof = 0x26,
|
||||
HandleDiskFull = 0x27,
|
||||
NotSupported = 0x32,
|
||||
RemNotList = 0x33,
|
||||
DupName = 0x34,
|
||||
BadNetPath = 0x35,
|
||||
NetworkBusy = 0x36,
|
||||
DevNotExist = 0x37,
|
||||
TooManyCmds = 0x38,
|
||||
FileExists = 0x50,
|
||||
CannotMake = 0x52,
|
||||
AlreadyAssigned = 0x55,
|
||||
InvalidPassword = 0x56,
|
||||
InvalidParameter = 0x57,
|
||||
NetWriteFault = 0x58,
|
||||
NoProcSlots = 0x59,
|
||||
TooManySemaphores = 0x64,
|
||||
ExclSemAlreadyOwned = 0x65,
|
||||
SemIsSet = 0x66,
|
||||
TooManySemRequests = 0x67,
|
||||
InvalidAtInterruptTime = 0x68,
|
||||
SemOwnerDied = 0x69,
|
||||
SemUserLimit = 0x6a
|
||||
}
|
||||
}
|
37
src/Greenshot.Base/UnmanagedHelpers/Enums/WinEvent.cs
Normal file
37
src/Greenshot.Base/UnmanagedHelpers/Enums/WinEvent.cs
Normal file
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* Greenshot - a free and open source screenshot tool
|
||||
* Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom, Francis Noel
|
||||
*
|
||||
* For more information see: https://getgreenshot.org/
|
||||
* The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace Greenshot.Base.UnmanagedHelpers.Enums
|
||||
{
|
||||
/// <summary>
|
||||
/// Used for User32.SetWinEventHook
|
||||
/// See MSDN: https://msdn.microsoft.com/en-us/library/windows/desktop/dd318066%28v=vs.85%29.aspx
|
||||
/// </summary>
|
||||
[SuppressMessage("ReSharper", "InconsistentNaming")]
|
||||
public enum WinEvent : uint
|
||||
{
|
||||
EVENT_OBJECT_CREATE = 32768,
|
||||
EVENT_OBJECT_DESTROY = 32769,
|
||||
EVENT_OBJECT_NAMECHANGE = 32780,
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace Greenshot.Base.UnmanagedHelpers.Enums
|
||||
{
|
||||
/// <summary>
|
||||
/// Used for User32.SetWinEventHook
|
||||
/// See: https://msdn.microsoft.com/en-us/library/windows/desktop/dd373640%28v=vs.85%29.aspx
|
||||
/// </summary>
|
||||
[SuppressMessage("ReSharper", "InconsistentNaming"), Flags]
|
||||
public enum WinEventHookFlags
|
||||
{
|
||||
WINEVENT_SKIPOWNTHREAD = 1,
|
||||
WINEVENT_SKIPOWNPROCESS = 2,
|
||||
WINEVENT_OUTOFCONTEXT = 0,
|
||||
WINEVENT_INCONTEXT = 4
|
||||
}
|
||||
}
|
32
src/Greenshot.Base/UnmanagedHelpers/Enums/WindowLongIndex.cs
Normal file
32
src/Greenshot.Base/UnmanagedHelpers/Enums/WindowLongIndex.cs
Normal file
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* Greenshot - a free and open source screenshot tool
|
||||
* Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
|
||||
*
|
||||
* For more information see: https://getgreenshot.org/
|
||||
* The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace Greenshot.Base.UnmanagedHelpers.Enums
|
||||
{
|
||||
[SuppressMessage("ReSharper", "InconsistentNaming")]
|
||||
public enum WindowLongIndex
|
||||
{
|
||||
GWL_EXSTYLE = -20, // Sets a new extended window style.
|
||||
GWL_STYLE = -16, // Sets a new window style.
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* Greenshot - a free and open source screenshot tool
|
||||
* Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
|
||||
*
|
||||
* For more information see: https://getgreenshot.org/
|
||||
* The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace Greenshot.Base.UnmanagedHelpers.Enums
|
||||
{
|
||||
[Flags]
|
||||
[SuppressMessage("ReSharper", "InconsistentNaming")]
|
||||
public enum WindowPlacementFlags : uint
|
||||
{
|
||||
// The coordinates of the minimized window may be specified.
|
||||
// This flag must be specified if the coordinates are set in the ptMinPosition member.
|
||||
WPF_SETMINPOSITION = 0x0001,
|
||||
|
||||
// If the calling thread and the thread that owns the window are attached to different input queues, the system posts the request to the thread that owns the window. This prevents the calling thread from blocking its execution while other threads process the request.
|
||||
WPF_ASYNCWINDOWPLACEMENT = 0x0004,
|
||||
|
||||
// The restored window will be maximized, regardless of whether it was maximized before it was minimized. This setting is only valid the next time the window is restored. It does not change the default restoration behavior.
|
||||
// This flag is only valid when the SW_SHOWMINIMIZED value is specified for the showCmd member.
|
||||
WPF_RESTORETOMAXIMIZED = 0x0002
|
||||
}
|
||||
}
|
36
src/Greenshot.Base/UnmanagedHelpers/Enums/WindowPos.cs
Normal file
36
src/Greenshot.Base/UnmanagedHelpers/Enums/WindowPos.cs
Normal file
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* Greenshot - a free and open source screenshot tool
|
||||
* Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
|
||||
*
|
||||
* For more information see: https://getgreenshot.org/
|
||||
* The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace Greenshot.Base.UnmanagedHelpers.Enums
|
||||
{
|
||||
[Flags]
|
||||
[SuppressMessage("ReSharper", "InconsistentNaming")]
|
||||
public enum WindowPos
|
||||
{
|
||||
SWP_NOACTIVATE =
|
||||
0x0010, // Does not activate the window. If this flag is not set, the window is activated and moved to the top of either the topmost or non-topmost group (depending on the setting of the hWndInsertAfter parameter).
|
||||
SWP_NOMOVE = 0x0002, //Retains the current position (ignores X and Y parameters).
|
||||
SWP_NOSIZE = 0x0001, // Retains the current size (ignores the cx and cy parameters).
|
||||
}
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* Greenshot - a free and open source screenshot tool
|
||||
* Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
|
||||
*
|
||||
* For more information see: https://getgreenshot.org/
|
||||
* The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace Greenshot.Base.UnmanagedHelpers.Enums
|
||||
{
|
||||
/// <summary>
|
||||
/// Window Style Flags
|
||||
/// </summary>
|
||||
[Flags]
|
||||
[SuppressMessage("ReSharper", "InconsistentNaming")]
|
||||
public enum WindowStyleFlags : int
|
||||
{
|
||||
//WS_OVERLAPPED = 0x00000000,
|
||||
WS_POPUP = -2147483648,
|
||||
WS_CHILD = 0x40000000,
|
||||
WS_MINIMIZE = 0x20000000,
|
||||
WS_VISIBLE = 0x10000000,
|
||||
WS_DISABLED = 0x08000000,
|
||||
WS_CLIPSIBLINGS = 0x04000000,
|
||||
WS_CLIPCHILDREN = 0x02000000,
|
||||
WS_MAXIMIZE = 0x01000000,
|
||||
WS_BORDER = 0x00800000,
|
||||
WS_DLGFRAME = 0x00400000,
|
||||
WS_VSCROLL = 0x00200000,
|
||||
WS_HSCROLL = 0x00100000,
|
||||
WS_SYSMENU = 0x00080000,
|
||||
WS_THICKFRAME = 0x00040000,
|
||||
WS_GROUP = 0x00020000,
|
||||
WS_TABSTOP = 0x00010000
|
||||
}
|
||||
}
|
26
src/Greenshot.Base/UnmanagedHelpers/Enums/WindowsMessages.cs
Normal file
26
src/Greenshot.Base/UnmanagedHelpers/Enums/WindowsMessages.cs
Normal file
|
@ -0,0 +1,26 @@
|
|||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace Greenshot.Base.UnmanagedHelpers.Enums
|
||||
{
|
||||
/// <summary>
|
||||
/// All possible windows messages
|
||||
/// See also <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/ms644927(v=vs.85).aspx#system_defined">here</a>
|
||||
/// </summary>
|
||||
[SuppressMessage("ReSharper", "InconsistentNaming")]
|
||||
public enum WindowsMessages : uint
|
||||
{
|
||||
WM_MOUSEACTIVATE = 0x0021,
|
||||
WM_INPUTLANGCHANGEREQUEST = 0x0050,
|
||||
WM_INPUTLANGCHANGE = 0x0051,
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Sent to a window to retrieve a handle to the large or small icon associated with a window. The system displays the large icon in the ALT+TAB dialog, and the small icon in the window caption.
|
||||
/// A window receives this message through its WindowProc function.
|
||||
/// <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/ms632625.aspx">WM_GETICON message</a>
|
||||
/// </summary>
|
||||
WM_GETICON = 0x007F,
|
||||
WM_CHAR = 0x0102,
|
||||
WM_SYSCOMMAND = 0x0112
|
||||
}
|
||||
}
|
596
src/Greenshot.Base/UnmanagedHelpers/GDI32.cs
Normal file
596
src/Greenshot.Base/UnmanagedHelpers/GDI32.cs
Normal file
|
@ -0,0 +1,596 @@
|
|||
/*
|
||||
* Greenshot - a free and open source screenshot tool
|
||||
* Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
|
||||
*
|
||||
* For more information see: https://getgreenshot.org/
|
||||
* The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security;
|
||||
using Greenshot.Base.UnmanagedHelpers.Enums;
|
||||
using Microsoft.Win32.SafeHandles;
|
||||
|
||||
namespace Greenshot.Base.UnmanagedHelpers
|
||||
{
|
||||
public static class GDIExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Check if all the corners of the rectangle are visible in the specified region.
|
||||
/// Not a perfect check, but this currently a workaround for checking if a window is completely visible
|
||||
/// </summary>
|
||||
/// <param name="region"></param>
|
||||
/// <param name="rectangle"></param>
|
||||
/// <returns></returns>
|
||||
public static bool AreRectangleCornersVisisble(this Region region, Rectangle rectangle)
|
||||
{
|
||||
Point topLeft = new Point(rectangle.X, rectangle.Y);
|
||||
Point topRight = new Point(rectangle.X + rectangle.Width, rectangle.Y);
|
||||
Point bottomLeft = new Point(rectangle.X, rectangle.Y + rectangle.Height);
|
||||
Point bottomRight = new Point(rectangle.X + rectangle.Width, rectangle.Y + rectangle.Height);
|
||||
bool topLeftVisible = region.IsVisible(topLeft);
|
||||
bool topRightVisible = region.IsVisible(topRight);
|
||||
bool bottomLeftVisible = region.IsVisible(bottomLeft);
|
||||
bool bottomRightVisible = region.IsVisible(bottomRight);
|
||||
|
||||
return topLeftVisible && topRightVisible && bottomLeftVisible && bottomRightVisible;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a SafeHandle for the GetHdc, so one can use using to automatically cleanup the devicecontext
|
||||
/// </summary>
|
||||
/// <param name="graphics"></param>
|
||||
/// <returns>SafeDeviceContextHandle</returns>
|
||||
public static SafeDeviceContextHandle GetSafeDeviceContext(this Graphics graphics)
|
||||
{
|
||||
return SafeDeviceContextHandle.FromGraphics(graphics);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Abstract class SafeObjectHandle which contains all handles that are cleaned with DeleteObject
|
||||
/// </summary>
|
||||
public abstract class SafeObjectHandle : SafeHandleZeroOrMinusOneIsInvalid
|
||||
{
|
||||
[DllImport("gdi32", SetLastError = true)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
private static extern bool DeleteObject(IntPtr hObject);
|
||||
|
||||
protected SafeObjectHandle(bool ownsHandle) : base(ownsHandle)
|
||||
{
|
||||
}
|
||||
|
||||
protected override bool ReleaseHandle()
|
||||
{
|
||||
return DeleteObject(handle);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A hbitmap SafeHandle implementation
|
||||
/// </summary>
|
||||
public class SafeHBitmapHandle : SafeObjectHandle
|
||||
{
|
||||
/// <summary>
|
||||
/// Needed for marshalling return values
|
||||
/// </summary>
|
||||
[SecurityCritical]
|
||||
public SafeHBitmapHandle() : base(true)
|
||||
{
|
||||
}
|
||||
|
||||
[SecurityCritical]
|
||||
public SafeHBitmapHandle(IntPtr preexistingHandle) : base(true)
|
||||
{
|
||||
SetHandle(preexistingHandle);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A hRegion SafeHandle implementation
|
||||
/// </summary>
|
||||
public class SafeRegionHandle : SafeObjectHandle
|
||||
{
|
||||
/// <summary>
|
||||
/// Needed for marshalling return values
|
||||
/// </summary>
|
||||
[SecurityCritical]
|
||||
public SafeRegionHandle() : base(true)
|
||||
{
|
||||
}
|
||||
|
||||
[SecurityCritical]
|
||||
public SafeRegionHandle(IntPtr preexistingHandle) : base(true)
|
||||
{
|
||||
SetHandle(preexistingHandle);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A dibsection SafeHandle implementation
|
||||
/// </summary>
|
||||
public class SafeDibSectionHandle : SafeObjectHandle
|
||||
{
|
||||
/// <summary>
|
||||
/// Needed for marshalling return values
|
||||
/// </summary>
|
||||
[SecurityCritical]
|
||||
public SafeDibSectionHandle() : base(true)
|
||||
{
|
||||
}
|
||||
|
||||
[SecurityCritical]
|
||||
public SafeDibSectionHandle(IntPtr preexistingHandle) : base(true)
|
||||
{
|
||||
SetHandle(preexistingHandle);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A select object safehandle implementation
|
||||
/// This impl will select the passed SafeHandle to the HDC and replace the returned value when disposing
|
||||
/// </summary>
|
||||
public class SafeSelectObjectHandle : SafeHandleZeroOrMinusOneIsInvalid
|
||||
{
|
||||
[DllImport("gdi32", SetLastError = true)]
|
||||
private static extern IntPtr SelectObject(IntPtr hDC, IntPtr hObject);
|
||||
|
||||
private readonly SafeHandle _hdc;
|
||||
|
||||
/// <summary>
|
||||
/// Needed for marshalling return values
|
||||
/// </summary>
|
||||
[SecurityCritical]
|
||||
public SafeSelectObjectHandle() : base(true)
|
||||
{
|
||||
}
|
||||
|
||||
[SecurityCritical]
|
||||
public SafeSelectObjectHandle(SafeDCHandle hdc, SafeHandle newHandle) : base(true)
|
||||
{
|
||||
_hdc = hdc;
|
||||
SetHandle(SelectObject(hdc.DangerousGetHandle(), newHandle.DangerousGetHandle()));
|
||||
}
|
||||
|
||||
protected override bool ReleaseHandle()
|
||||
{
|
||||
SelectObject(_hdc.DangerousGetHandle(), handle);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public abstract class SafeDCHandle : SafeHandleZeroOrMinusOneIsInvalid
|
||||
{
|
||||
protected SafeDCHandle(bool ownsHandle) : base(ownsHandle)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A CompatibleDC SafeHandle implementation
|
||||
/// </summary>
|
||||
public class SafeCompatibleDCHandle : SafeDCHandle
|
||||
{
|
||||
[DllImport("gdi32", SetLastError = true)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
private static extern bool DeleteDC(IntPtr hDC);
|
||||
|
||||
/// <summary>
|
||||
/// Needed for marshalling return values
|
||||
/// </summary>
|
||||
[SecurityCritical]
|
||||
public SafeCompatibleDCHandle() : base(true)
|
||||
{
|
||||
}
|
||||
|
||||
[SecurityCritical]
|
||||
public SafeCompatibleDCHandle(IntPtr preexistingHandle) : base(true)
|
||||
{
|
||||
SetHandle(preexistingHandle);
|
||||
}
|
||||
|
||||
public SafeSelectObjectHandle SelectObject(SafeHandle newHandle)
|
||||
{
|
||||
return new SafeSelectObjectHandle(this, newHandle);
|
||||
}
|
||||
|
||||
protected override bool ReleaseHandle()
|
||||
{
|
||||
return DeleteDC(handle);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A DeviceContext SafeHandle implementation
|
||||
/// </summary>
|
||||
public class SafeDeviceContextHandle : SafeDCHandle
|
||||
{
|
||||
private readonly Graphics _graphics;
|
||||
|
||||
/// <summary>
|
||||
/// Needed for marshalling return values
|
||||
/// </summary>
|
||||
[SecurityCritical]
|
||||
public SafeDeviceContextHandle() : base(true)
|
||||
{
|
||||
}
|
||||
|
||||
[SecurityCritical]
|
||||
public SafeDeviceContextHandle(Graphics graphics, IntPtr preexistingHandle) : base(true)
|
||||
{
|
||||
_graphics = graphics;
|
||||
SetHandle(preexistingHandle);
|
||||
}
|
||||
|
||||
protected override bool ReleaseHandle()
|
||||
{
|
||||
_graphics.ReleaseHdc(handle);
|
||||
return true;
|
||||
}
|
||||
|
||||
public static SafeDeviceContextHandle FromGraphics(Graphics graphics)
|
||||
{
|
||||
return new SafeDeviceContextHandle(graphics, graphics.GetHdc());
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// GDI32 Helpers
|
||||
/// </summary>
|
||||
public static class GDI32
|
||||
{
|
||||
[DllImport("gdi32", SetLastError = true)]
|
||||
public static extern bool BitBlt(SafeHandle hdcDest, int nXDest, int nYDest, int nWidth, int nHeight, SafeHandle hdcSrc, int nXSrc, int nYSrc, CopyPixelOperation dwRop);
|
||||
|
||||
[DllImport("gdi32", SetLastError = true)]
|
||||
public static extern SafeCompatibleDCHandle CreateCompatibleDC(SafeHandle hDC);
|
||||
|
||||
[DllImport("gdi32", SetLastError = true)]
|
||||
public static extern SafeDibSectionHandle CreateDIBSection(SafeHandle hdc, ref BITMAPINFOHEADERV5 bmi, uint usage, out IntPtr bits, IntPtr hSection, uint dwOffset);
|
||||
|
||||
[DllImport("gdi32", SetLastError = true)]
|
||||
public static extern SafeRegionHandle CreateRectRgn(int nLeftRect, int nTopRect, int nRightRect, int nBottomRect);
|
||||
|
||||
[DllImport("gdi32", SetLastError = true)]
|
||||
public static extern uint GetPixel(SafeHandle hdc, int nXPos, int nYPos);
|
||||
|
||||
[DllImport("gdi32", SetLastError = true)]
|
||||
public static extern int GetDeviceCaps(SafeHandle hdc, DeviceCaps nIndex);
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 2)]
|
||||
public struct BITMAPFILEHEADER
|
||||
{
|
||||
public static readonly short BM = 0x4d42; // BM
|
||||
public short bfType;
|
||||
public int bfSize;
|
||||
public short bfReserved1;
|
||||
public short bfReserved2;
|
||||
public int bfOffBits;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct BitfieldColorMask
|
||||
{
|
||||
public uint blue;
|
||||
public uint green;
|
||||
public uint red;
|
||||
|
||||
public void InitValues()
|
||||
{
|
||||
red = (uint) 255 << 8;
|
||||
green = (uint) 255 << 16;
|
||||
blue = (uint) 255 << 24;
|
||||
}
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct CIEXYZ
|
||||
{
|
||||
public uint ciexyzX; //FXPT2DOT30
|
||||
public uint ciexyzY; //FXPT2DOT30
|
||||
public uint ciexyzZ; //FXPT2DOT30
|
||||
|
||||
public CIEXYZ(uint FXPT2DOT30)
|
||||
{
|
||||
ciexyzX = FXPT2DOT30;
|
||||
ciexyzY = FXPT2DOT30;
|
||||
ciexyzZ = FXPT2DOT30;
|
||||
}
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct RGBQUAD
|
||||
{
|
||||
public byte rgbBlue;
|
||||
public byte rgbGreen;
|
||||
public byte rgbRed;
|
||||
public byte rgbReserved;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct CIEXYZTRIPLE
|
||||
{
|
||||
public CIEXYZ ciexyzRed;
|
||||
public CIEXYZ ciexyzGreen;
|
||||
public CIEXYZ ciexyzBlue;
|
||||
}
|
||||
|
||||
public enum BI_COMPRESSION : uint
|
||||
{
|
||||
BI_RGB = 0, // Uncompressed
|
||||
BI_RLE8 = 1, // RLE 8BPP
|
||||
BI_RLE4 = 2, // RLE 4BPP
|
||||
|
||||
BI_BITFIELDS =
|
||||
3, // Specifies that the bitmap is not compressed and that the color table consists of three DWORD color masks that specify the red, green, and blue components, respectively, of each pixel. This is valid when used with 16- and 32-bpp bitmaps.
|
||||
BI_JPEG = 4, // Indicates that the image is a JPEG image.
|
||||
BI_PNG = 5 // Indicates that the image is a PNG image.
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Explicit)]
|
||||
public struct BITMAPINFOHEADER
|
||||
{
|
||||
[FieldOffset(0)] public uint biSize;
|
||||
[FieldOffset(4)] public int biWidth;
|
||||
[FieldOffset(8)] public int biHeight;
|
||||
[FieldOffset(12)] public ushort biPlanes;
|
||||
[FieldOffset(14)] public ushort biBitCount;
|
||||
[FieldOffset(16)] public BI_COMPRESSION biCompression;
|
||||
[FieldOffset(20)] public uint biSizeImage;
|
||||
[FieldOffset(24)] public int biXPelsPerMeter;
|
||||
[FieldOffset(28)] public int biYPelsPerMeter;
|
||||
[FieldOffset(32)] public uint biClrUsed;
|
||||
[FieldOffset(36)] public uint biClrImportant;
|
||||
|
||||
public const int DIB_RGB_COLORS = 0;
|
||||
|
||||
public BITMAPINFOHEADER(int width, int height, ushort bpp)
|
||||
{
|
||||
biSize = (uint)Marshal.SizeOf(typeof(BITMAPINFOHEADER)); // BITMAPINFOHEADER < DIBV4 is 40 bytes
|
||||
biPlanes = 1; // Should allways be 1
|
||||
biCompression = BI_COMPRESSION.BI_RGB;
|
||||
biWidth = width;
|
||||
biHeight = height;
|
||||
biBitCount = bpp;
|
||||
biSizeImage = (uint)(width * height * (bpp >> 3));
|
||||
biXPelsPerMeter = 0;
|
||||
biYPelsPerMeter = 0;
|
||||
biClrUsed = 0;
|
||||
biClrImportant = 0;
|
||||
}
|
||||
|
||||
public bool IsDibV4
|
||||
{
|
||||
get
|
||||
{
|
||||
uint sizeOfBMI = (uint)Marshal.SizeOf(typeof(BITMAPINFOHEADERV4));
|
||||
return biSize >= sizeOfBMI;
|
||||
}
|
||||
}
|
||||
public bool IsDibV5
|
||||
{
|
||||
get
|
||||
{
|
||||
uint sizeOfBMI = (uint)Marshal.SizeOf(typeof(BITMAPINFOHEADERV5));
|
||||
return biSize >= sizeOfBMI;
|
||||
}
|
||||
}
|
||||
|
||||
public uint OffsetToPixels
|
||||
{
|
||||
get
|
||||
{
|
||||
if (biCompression == BI_COMPRESSION.BI_BITFIELDS)
|
||||
{
|
||||
// Add 3x4 bytes for the bitfield color mask
|
||||
return biSize + 3 * 4;
|
||||
}
|
||||
|
||||
return biSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Explicit)]
|
||||
public struct BITMAPINFOHEADERV4
|
||||
{
|
||||
[FieldOffset(0)] public uint biSize;
|
||||
[FieldOffset(4)] public int biWidth;
|
||||
[FieldOffset(8)] public int biHeight;
|
||||
[FieldOffset(12)] public ushort biPlanes;
|
||||
[FieldOffset(14)] public ushort biBitCount;
|
||||
[FieldOffset(16)] public BI_COMPRESSION biCompression;
|
||||
[FieldOffset(20)] public uint biSizeImage;
|
||||
[FieldOffset(24)] public int biXPelsPerMeter;
|
||||
[FieldOffset(28)] public int biYPelsPerMeter;
|
||||
[FieldOffset(32)] public uint biClrUsed;
|
||||
[FieldOffset(36)] public uint biClrImportant;
|
||||
[FieldOffset(40)] public uint bV4RedMask;
|
||||
[FieldOffset(44)] public uint bV4GreenMask;
|
||||
[FieldOffset(48)] public uint bV4BlueMask;
|
||||
[FieldOffset(52)] public uint bV4AlphaMask;
|
||||
[FieldOffset(56)] public uint bV4CSType;
|
||||
[FieldOffset(60)] public CIEXYZTRIPLE bV4Endpoints;
|
||||
[FieldOffset(96)] public uint bV4GammaRed;
|
||||
[FieldOffset(100)] public uint bV4GammaGreen;
|
||||
[FieldOffset(104)] public uint bV4GammaBlue;
|
||||
|
||||
public const int DIB_RGB_COLORS = 0;
|
||||
|
||||
public BITMAPINFOHEADERV4(int width, int height, ushort bpp)
|
||||
{
|
||||
biSize = (uint)Marshal.SizeOf(typeof(BITMAPINFOHEADERV4)); // BITMAPINFOHEADER < DIBV5 is 40 bytes
|
||||
biPlanes = 1; // Should allways be 1
|
||||
biCompression = BI_COMPRESSION.BI_RGB;
|
||||
biWidth = width;
|
||||
biHeight = height;
|
||||
biBitCount = bpp;
|
||||
biSizeImage = (uint)(width * height * (bpp >> 3));
|
||||
biXPelsPerMeter = 0;
|
||||
biYPelsPerMeter = 0;
|
||||
biClrUsed = 0;
|
||||
biClrImportant = 0;
|
||||
|
||||
// V4
|
||||
bV4RedMask = (uint)255 << 16;
|
||||
bV4GreenMask = (uint)255 << 8;
|
||||
bV4BlueMask = 255;
|
||||
bV4AlphaMask = (uint)255 << 24;
|
||||
bV4CSType = 0x73524742; // LCS_sRGB
|
||||
bV4Endpoints = new CIEXYZTRIPLE
|
||||
{
|
||||
ciexyzBlue = new CIEXYZ(0),
|
||||
ciexyzGreen = new CIEXYZ(0),
|
||||
ciexyzRed = new CIEXYZ(0)
|
||||
};
|
||||
bV4GammaRed = 0;
|
||||
bV4GammaGreen = 0;
|
||||
bV4GammaBlue = 0;
|
||||
}
|
||||
|
||||
public bool IsDibV4
|
||||
{
|
||||
get
|
||||
{
|
||||
uint sizeOfBMI = (uint)Marshal.SizeOf(typeof(BITMAPINFOHEADERV4));
|
||||
return biSize >= sizeOfBMI;
|
||||
}
|
||||
}
|
||||
public bool IsDibV5
|
||||
{
|
||||
get
|
||||
{
|
||||
uint sizeOfBMI = (uint)Marshal.SizeOf(typeof(BITMAPINFOHEADERV5));
|
||||
return biSize >= sizeOfBMI;
|
||||
}
|
||||
}
|
||||
|
||||
public uint OffsetToPixels
|
||||
{
|
||||
get
|
||||
{
|
||||
if (biCompression == BI_COMPRESSION.BI_BITFIELDS)
|
||||
{
|
||||
// Add 3x4 bytes for the bitfield color mask
|
||||
return biSize + 3 * 4;
|
||||
}
|
||||
|
||||
return biSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Explicit)]
|
||||
public struct BITMAPINFOHEADERV5
|
||||
{
|
||||
[FieldOffset(0)] public uint biSize;
|
||||
[FieldOffset(4)] public int biWidth;
|
||||
[FieldOffset(8)] public int biHeight;
|
||||
[FieldOffset(12)] public ushort biPlanes;
|
||||
[FieldOffset(14)] public ushort biBitCount;
|
||||
[FieldOffset(16)] public BI_COMPRESSION biCompression;
|
||||
[FieldOffset(20)] public uint biSizeImage;
|
||||
[FieldOffset(24)] public int biXPelsPerMeter;
|
||||
[FieldOffset(28)] public int biYPelsPerMeter;
|
||||
[FieldOffset(32)] public uint biClrUsed;
|
||||
[FieldOffset(36)] public uint biClrImportant;
|
||||
[FieldOffset(40)] public uint bV4RedMask;
|
||||
[FieldOffset(44)] public uint bV4GreenMask;
|
||||
[FieldOffset(48)] public uint bV4BlueMask;
|
||||
[FieldOffset(52)] public uint bV4AlphaMask;
|
||||
[FieldOffset(56)] public uint bV4CSType;
|
||||
[FieldOffset(60)] public CIEXYZTRIPLE bV4Endpoints;
|
||||
[FieldOffset(96)] public uint bV4GammaRed;
|
||||
[FieldOffset(100)] public uint bV4GammaGreen;
|
||||
[FieldOffset(104)] public uint bV4GammaBlue;
|
||||
[FieldOffset(108)] public uint bV5Intent; // Rendering intent for bitmap
|
||||
[FieldOffset(112)] public uint bV5ProfileData;
|
||||
[FieldOffset(116)] public uint bV5ProfileSize;
|
||||
[FieldOffset(120)] public uint bV5Reserved;
|
||||
|
||||
public const int DIB_RGB_COLORS = 0;
|
||||
|
||||
public BITMAPINFOHEADERV5(int width, int height, ushort bpp)
|
||||
{
|
||||
biSize = (uint) Marshal.SizeOf(typeof(BITMAPINFOHEADERV5)); // BITMAPINFOHEADER < DIBV5 is 40 bytes
|
||||
biPlanes = 1; // Should allways be 1
|
||||
biCompression = BI_COMPRESSION.BI_RGB;
|
||||
biWidth = width;
|
||||
biHeight = height;
|
||||
biBitCount = bpp;
|
||||
biSizeImage = (uint) (width * height * (bpp >> 3));
|
||||
biXPelsPerMeter = 0;
|
||||
biYPelsPerMeter = 0;
|
||||
biClrUsed = 0;
|
||||
biClrImportant = 0;
|
||||
|
||||
// V4
|
||||
bV4RedMask = (uint) 255 << 16;
|
||||
bV4GreenMask = (uint) 255 << 8;
|
||||
bV4BlueMask = 255;
|
||||
bV4AlphaMask = (uint) 255 << 24;
|
||||
bV4CSType = 0x73524742; // LCS_sRGB
|
||||
bV4Endpoints = new CIEXYZTRIPLE
|
||||
{
|
||||
ciexyzBlue = new CIEXYZ(0),
|
||||
ciexyzGreen = new CIEXYZ(0),
|
||||
ciexyzRed = new CIEXYZ(0)
|
||||
};
|
||||
bV4GammaRed = 0;
|
||||
bV4GammaGreen = 0;
|
||||
bV4GammaBlue = 0;
|
||||
// V5
|
||||
bV5Intent = 4;
|
||||
bV5ProfileData = 0;
|
||||
bV5ProfileSize = 0;
|
||||
bV5Reserved = 0;
|
||||
}
|
||||
|
||||
public bool IsDibV4
|
||||
{
|
||||
get
|
||||
{
|
||||
uint sizeOfBMI = (uint)Marshal.SizeOf(typeof(BITMAPINFOHEADERV4));
|
||||
return biSize >= sizeOfBMI;
|
||||
}
|
||||
}
|
||||
public bool IsDibV5
|
||||
{
|
||||
get
|
||||
{
|
||||
uint sizeOfBMI = (uint)Marshal.SizeOf(typeof(BITMAPINFOHEADERV5));
|
||||
return biSize >= sizeOfBMI;
|
||||
}
|
||||
}
|
||||
|
||||
public uint OffsetToPixels
|
||||
{
|
||||
get
|
||||
{
|
||||
if (biCompression == BI_COMPRESSION.BI_BITFIELDS)
|
||||
{
|
||||
// Add 3x4 bytes for the bitfield color mask
|
||||
return biSize + 3 * 4;
|
||||
}
|
||||
|
||||
return biSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
387
src/Greenshot.Base/UnmanagedHelpers/GDIplus.cs
Normal file
387
src/Greenshot.Base/UnmanagedHelpers/GDIplus.cs
Normal file
|
@ -0,0 +1,387 @@
|
|||
/*
|
||||
* Greenshot - a free and open source screenshot tool
|
||||
* Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
|
||||
*
|
||||
* For more information see: https://getgreenshot.org/
|
||||
* The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Drawing2D;
|
||||
using System.Drawing.Imaging;
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
using Greenshot.Base.UnmanagedHelpers.Structs;
|
||||
using log4net;
|
||||
|
||||
namespace Greenshot.Base.UnmanagedHelpers
|
||||
{
|
||||
/// <summary>
|
||||
/// Contains members that specify the nature of a Gaussian blur.
|
||||
/// </summary>
|
||||
/// <remarks>Cannot be pinned with GCHandle due to bool value.</remarks>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
internal struct BlurParams
|
||||
{
|
||||
/// <summary>
|
||||
/// Real number that specifies the blur radius (the radius of the Gaussian convolution kernel) in
|
||||
/// pixels. The radius must be in the range 0 through 255. As the radius increases, the resulting
|
||||
/// bitmap becomes more blurry.
|
||||
/// </summary>
|
||||
public float Radius;
|
||||
|
||||
/// <summary>
|
||||
/// Boolean value that specifies whether the bitmap expands by an amount equal to the blur radius.
|
||||
/// If TRUE, the bitmap expands by an amount equal to the radius so that it can have soft edges.
|
||||
/// If FALSE, the bitmap remains the same size and the soft edges are clipped.
|
||||
/// </summary>
|
||||
public bool ExpandEdges;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// GDI Plus unit description.
|
||||
/// </summary>
|
||||
public enum GpUnit
|
||||
{
|
||||
/// <summary>
|
||||
/// World coordinate (non-physical unit).
|
||||
/// </summary>
|
||||
UnitWorld,
|
||||
|
||||
/// <summary>
|
||||
/// Variable - for PageTransform only.
|
||||
/// </summary>
|
||||
UnitDisplay,
|
||||
|
||||
/// <summary>
|
||||
/// Each unit is one device pixel.
|
||||
/// </summary>
|
||||
UnitPixel,
|
||||
|
||||
/// <summary>
|
||||
/// Each unit is a printer's point, or 1/72 inch.
|
||||
/// </summary>
|
||||
UnitPoint,
|
||||
|
||||
/// <summary>
|
||||
/// Each unit is 1 inch.
|
||||
/// </summary>
|
||||
UnitInch,
|
||||
|
||||
/// <summary>
|
||||
/// Each unit is 1/300 inch.
|
||||
/// </summary>
|
||||
UnitDocument,
|
||||
|
||||
/// <summary>
|
||||
/// Each unit is 1 millimeter.
|
||||
/// </summary>
|
||||
UnitMillimeter
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// GDIplus Helpers
|
||||
/// </summary>
|
||||
public static class GDIplus
|
||||
{
|
||||
private static readonly ILog Log = LogManager.GetLogger(typeof(GDIplus));
|
||||
|
||||
[DllImport("gdiplus.dll", SetLastError = true, ExactSpelling = true)]
|
||||
private static extern int GdipBitmapApplyEffect(IntPtr bitmap, IntPtr effect, ref RECT rectOfInterest, bool useAuxData, IntPtr auxData, int auxDataSize);
|
||||
|
||||
[DllImport("gdiplus.dll", SetLastError = true, ExactSpelling = true)]
|
||||
private static extern int GdipDrawImageFX(IntPtr graphics, IntPtr bitmap, ref RECTF source, IntPtr matrix, IntPtr effect, IntPtr imageAttributes, GpUnit srcUnit);
|
||||
|
||||
[DllImport("gdiplus.dll", SetLastError = true, ExactSpelling = true)]
|
||||
private static extern int GdipSetEffectParameters(IntPtr effect, IntPtr parameters, uint size);
|
||||
|
||||
[DllImport("gdiplus.dll", SetLastError = true, ExactSpelling = true)]
|
||||
private static extern int GdipCreateEffect(Guid guid, out IntPtr effect);
|
||||
|
||||
[DllImport("gdiplus.dll", SetLastError = true, ExactSpelling = true)]
|
||||
private static extern int GdipDeleteEffect(IntPtr effect);
|
||||
|
||||
private static readonly Guid BlurEffectGuid = new Guid("{633C80A4-1843-482B-9EF2-BE2834C5FDD4}");
|
||||
|
||||
// Constant "FieldInfo" for getting the nativeImage from the Bitmap
|
||||
private static readonly FieldInfo FIELD_INFO_NATIVE_IMAGE = typeof(Bitmap).GetField("nativeImage", BindingFlags.GetField | BindingFlags.Instance | BindingFlags.NonPublic);
|
||||
|
||||
// Constant "FieldInfo" for getting the NativeGraphics from the Graphics
|
||||
private static readonly FieldInfo FIELD_INFO_NATIVE_GRAPHICS =
|
||||
typeof(Graphics).GetField("nativeGraphics", BindingFlags.GetField | BindingFlags.Instance | BindingFlags.NonPublic);
|
||||
|
||||
// Constant "FieldInfo" for getting the nativeMatrix from the Matrix
|
||||
private static readonly FieldInfo FIELD_INFO_NATIVE_MATRIX =
|
||||
typeof(Matrix).GetField("nativeMatrix", BindingFlags.GetField | BindingFlags.Instance | BindingFlags.NonPublic);
|
||||
|
||||
// Constant "FieldInfo" for getting the nativeImageAttributes from the ImageAttributes
|
||||
private static readonly FieldInfo FIELD_INFO_NATIVE_IMAGEATTRIBUTES =
|
||||
typeof(ImageAttributes).GetField("nativeImageAttributes", BindingFlags.GetField | BindingFlags.Instance | BindingFlags.NonPublic);
|
||||
|
||||
private static bool _isBlurEnabled = Environment.OSVersion.Version.Major >= 6;
|
||||
|
||||
/// <summary>
|
||||
/// Get the nativeImage field from the bitmap
|
||||
/// </summary>
|
||||
/// <param name="bitmap"></param>
|
||||
/// <returns>IntPtr</returns>
|
||||
private static IntPtr GetNativeImage(Bitmap bitmap)
|
||||
{
|
||||
if (bitmap == null)
|
||||
{
|
||||
return IntPtr.Zero;
|
||||
}
|
||||
|
||||
return (IntPtr) FIELD_INFO_NATIVE_IMAGE.GetValue(bitmap);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the NativeGraphics field from the graphics
|
||||
/// </summary>
|
||||
/// <param name="graphics"></param>
|
||||
/// <returns>IntPtr</returns>
|
||||
private static IntPtr GetNativeGraphics(Graphics graphics)
|
||||
{
|
||||
if (graphics == null)
|
||||
{
|
||||
return IntPtr.Zero;
|
||||
}
|
||||
|
||||
return (IntPtr) FIELD_INFO_NATIVE_GRAPHICS.GetValue(graphics);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the nativeMatrix field from the matrix
|
||||
/// </summary>
|
||||
/// <param name="matrix"></param>
|
||||
/// <returns>IntPtr</returns>
|
||||
private static IntPtr GetNativeMatrix(Matrix matrix)
|
||||
{
|
||||
if (matrix == null)
|
||||
{
|
||||
return IntPtr.Zero;
|
||||
}
|
||||
|
||||
return (IntPtr) FIELD_INFO_NATIVE_MATRIX.GetValue(matrix);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the nativeImageAttributes field from the ImageAttributes
|
||||
/// </summary>
|
||||
/// <param name="imageAttributes"></param>
|
||||
/// <returns>IntPtr</returns>
|
||||
private static IntPtr GetNativeImageAttributes(ImageAttributes imageAttributes)
|
||||
{
|
||||
if (imageAttributes == null)
|
||||
{
|
||||
return IntPtr.Zero;
|
||||
}
|
||||
|
||||
return (IntPtr) FIELD_INFO_NATIVE_IMAGEATTRIBUTES.GetValue(imageAttributes);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns if a GDIPlus blur can be made for the supplied radius.
|
||||
/// This accounts for the "bug" I reported here: https://social.technet.microsoft.com/Forums/en/w8itprogeneral/thread/99ddbe9d-556d-475a-8bab-84e25aa13a2c
|
||||
/// </summary>
|
||||
/// <param name="radius"></param>
|
||||
/// <returns>false if blur is not possible</returns>
|
||||
public static bool IsBlurPossible(int radius)
|
||||
{
|
||||
if (!_isBlurEnabled)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Environment.OSVersion.Version.Major == 6 && Environment.OSVersion.Version.Minor < 2)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return Environment.OSVersion.Version.Major > 6 && radius >= 20;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Use the GDI+ blur effect on the bitmap
|
||||
/// </summary>
|
||||
/// <param name="destinationBitmap">Bitmap to apply the effect to</param>
|
||||
/// <param name="area">Rectangle to apply the blur effect to</param>
|
||||
/// <param name="radius">0-255</param>
|
||||
/// <param name="expandEdges">bool true if the edges are expanded with the radius</param>
|
||||
/// <returns>false if there is no GDI+ available or an exception occurred</returns>
|
||||
public static bool ApplyBlur(Bitmap destinationBitmap, Rectangle area, int radius, bool expandEdges)
|
||||
{
|
||||
if (!IsBlurPossible(radius))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
IntPtr hBlurParams = IntPtr.Zero;
|
||||
IntPtr hEffect = IntPtr.Zero;
|
||||
|
||||
try
|
||||
{
|
||||
// Create the GDI+ BlurEffect, using the Guid
|
||||
int status = GdipCreateEffect(BlurEffectGuid, out hEffect);
|
||||
if (status != 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Create a BlurParams struct and set the values
|
||||
var blurParams = new BlurParams
|
||||
{
|
||||
Radius = radius,
|
||||
ExpandEdges = expandEdges
|
||||
};
|
||||
|
||||
// Allocate space in unmanaged memory
|
||||
hBlurParams = Marshal.AllocHGlobal(Marshal.SizeOf(blurParams));
|
||||
// Copy the structure to the unmanaged memory
|
||||
Marshal.StructureToPtr(blurParams, hBlurParams, false);
|
||||
|
||||
|
||||
// Set the blurParams to the effect
|
||||
GdipSetEffectParameters(hEffect, hBlurParams, (uint) Marshal.SizeOf(blurParams));
|
||||
|
||||
// Somewhere it said we can use destinationBitmap.GetHbitmap(), this doesn't work!!
|
||||
// Get the private nativeImage property from the Bitmap
|
||||
IntPtr hBitmap = GetNativeImage(destinationBitmap);
|
||||
|
||||
// Create a RECT from the Rectangle
|
||||
RECT rec = new RECT(area);
|
||||
// Apply the effect to the bitmap in the specified area
|
||||
GdipBitmapApplyEffect(hBitmap, hEffect, ref rec, false, IntPtr.Zero, 0);
|
||||
|
||||
// Everything worked, return true
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_isBlurEnabled = false;
|
||||
Log.Error("Problem using GdipBitmapApplyEffect: ", ex);
|
||||
return false;
|
||||
}
|
||||
finally
|
||||
{
|
||||
try
|
||||
{
|
||||
if (hEffect != IntPtr.Zero)
|
||||
{
|
||||
// Delete the effect
|
||||
GdipDeleteEffect(hEffect);
|
||||
}
|
||||
|
||||
if (hBlurParams != IntPtr.Zero)
|
||||
{
|
||||
// Free the memory
|
||||
Marshal.FreeHGlobal(hBlurParams);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_isBlurEnabled = false;
|
||||
Log.Error("Problem cleaning up ApplyBlur: ", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Draw the image on the graphics with GDI+ blur effect
|
||||
/// </summary>
|
||||
/// <returns>false if there is no GDI+ available or an exception occurred</returns>
|
||||
public static bool DrawWithBlur(Graphics graphics, Bitmap image, Rectangle source, Matrix transform, ImageAttributes imageAttributes, int radius, bool expandEdges)
|
||||
{
|
||||
if (!IsBlurPossible(radius))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
IntPtr hBlurParams = IntPtr.Zero;
|
||||
IntPtr hEffect = IntPtr.Zero;
|
||||
|
||||
try
|
||||
{
|
||||
// Create the GDI+ BlurEffect, using the Guid
|
||||
int status = GdipCreateEffect(BlurEffectGuid, out hEffect);
|
||||
if (status != 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Create a BlurParams struct and set the values
|
||||
var blurParams = new BlurParams
|
||||
{
|
||||
Radius = radius,
|
||||
ExpandEdges = false
|
||||
};
|
||||
//blurParams.Padding = radius;
|
||||
|
||||
// Allocate space in unmanaged memory
|
||||
hBlurParams = Marshal.AllocHGlobal(Marshal.SizeOf(blurParams));
|
||||
// Copy the structure to the unmanaged memory
|
||||
Marshal.StructureToPtr(blurParams, hBlurParams, true);
|
||||
|
||||
// Set the blurParams to the effect
|
||||
GdipSetEffectParameters(hEffect, hBlurParams, (uint) Marshal.SizeOf(blurParams));
|
||||
|
||||
// Somewhere it said we can use destinationBitmap.GetHbitmap(), this doesn't work!!
|
||||
// Get the private nativeImage property from the Bitmap
|
||||
IntPtr hBitmap = GetNativeImage(image);
|
||||
IntPtr hGraphics = GetNativeGraphics(graphics);
|
||||
IntPtr hMatrix = GetNativeMatrix(transform);
|
||||
IntPtr hAttributes = GetNativeImageAttributes(imageAttributes);
|
||||
|
||||
// Create a RECT from the Rectangle
|
||||
RECTF sourceRecf = new RECTF(source);
|
||||
// Apply the effect to the bitmap in the specified area
|
||||
GdipDrawImageFX(hGraphics, hBitmap, ref sourceRecf, hMatrix, hEffect, hAttributes, GpUnit.UnitPixel);
|
||||
|
||||
// Everything worked, return true
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_isBlurEnabled = false;
|
||||
Log.Error("Problem using GdipDrawImageFX: ", ex);
|
||||
return false;
|
||||
}
|
||||
finally
|
||||
{
|
||||
try
|
||||
{
|
||||
if (hEffect != IntPtr.Zero)
|
||||
{
|
||||
// Delete the effect
|
||||
GdipDeleteEffect(hEffect);
|
||||
}
|
||||
|
||||
if (hBlurParams != IntPtr.Zero)
|
||||
{
|
||||
// Free the memory
|
||||
Marshal.FreeHGlobal(hBlurParams);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_isBlurEnabled = false;
|
||||
Log.Error("Problem cleaning up DrawWithBlur: ", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
135
src/Greenshot.Base/UnmanagedHelpers/Kernel32.cs
Normal file
135
src/Greenshot.Base/UnmanagedHelpers/Kernel32.cs
Normal file
|
@ -0,0 +1,135 @@
|
|||
/*
|
||||
* Greenshot - a free and open source screenshot tool
|
||||
* Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
|
||||
*
|
||||
* For more information see: https://getgreenshot.org/
|
||||
* The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using Greenshot.Base.UnmanagedHelpers.Enums;
|
||||
|
||||
namespace Greenshot.Base.UnmanagedHelpers
|
||||
{
|
||||
/// <summary>
|
||||
/// Description of Kernel32.
|
||||
/// </summary>
|
||||
public class Kernel32
|
||||
{
|
||||
public const uint ATTACHCONSOLE_ATTACHPARENTPROCESS = 0x0ffffffff; // default value if not specifing a process ID
|
||||
|
||||
[DllImport("kernel32", SetLastError = true)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
public static extern bool AttachConsole(uint dwProcessId);
|
||||
|
||||
[DllImport("kernel32", SetLastError = true)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
public static extern bool AllocConsole();
|
||||
|
||||
[DllImport("kernel32", SetLastError = true)]
|
||||
public static extern IntPtr OpenThread(ThreadAccess dwDesiredAccess, bool bInheritHandle, uint dwThreadId);
|
||||
|
||||
[DllImport("kernel32", SetLastError = true)]
|
||||
public static extern uint SuspendThread(IntPtr hThread);
|
||||
|
||||
[DllImport("kernel32", SetLastError = true)]
|
||||
public static extern int ResumeThread(IntPtr hThread);
|
||||
|
||||
[DllImport("kernel32", SetLastError = true)]
|
||||
public static extern IntPtr OpenProcess(ProcessAccessFlags dwDesiredAccess, bool bInheritHandle, int dwProcessId);
|
||||
|
||||
[DllImport("kernel32", SetLastError = true, CharSet = CharSet.Unicode)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
public static extern bool QueryFullProcessImageName(IntPtr hProcess, uint dwFlags, StringBuilder lpExeName, ref uint lpdwSize);
|
||||
|
||||
[DllImport("kernel32", SetLastError = true, CharSet = CharSet.Unicode)]
|
||||
public static extern uint QueryDosDevice(string lpDeviceName, StringBuilder lpTargetPath, uint uuchMax);
|
||||
|
||||
[DllImport("kernel32", SetLastError = true)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
public static extern bool CloseHandle(IntPtr hObject);
|
||||
|
||||
[DllImport("kernel32", SetLastError = true, CharSet = CharSet.Auto)]
|
||||
public static extern int GetPackageFullName(IntPtr hProcess, ref Int32 packageFullNameLength, StringBuilder fullName);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Method to get the process path
|
||||
/// </summary>
|
||||
/// <param name="processid"></param>
|
||||
/// <returns></returns>
|
||||
public static string GetProcessPath(int processid)
|
||||
{
|
||||
StringBuilder _PathBuffer = new StringBuilder(512);
|
||||
// Try the GetModuleFileName method first since it's the fastest.
|
||||
// May return ACCESS_DENIED (due to VM_READ flag) if the process is not owned by the current user.
|
||||
// Will fail if we are compiled as x86 and we're trying to open a 64 bit process...not allowed.
|
||||
IntPtr hprocess = OpenProcess(ProcessAccessFlags.QueryInformation | ProcessAccessFlags.VMRead, false, processid);
|
||||
if (hprocess != IntPtr.Zero)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (PsAPI.GetModuleFileNameEx(hprocess, IntPtr.Zero, _PathBuffer, (uint) _PathBuffer.Capacity) > 0)
|
||||
{
|
||||
return _PathBuffer.ToString();
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
CloseHandle(hprocess);
|
||||
}
|
||||
}
|
||||
|
||||
hprocess = OpenProcess(ProcessAccessFlags.QueryInformation, false, processid);
|
||||
if (hprocess != IntPtr.Zero)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Try this method for Vista or higher operating systems
|
||||
uint size = (uint) _PathBuffer.Capacity;
|
||||
if ((Environment.OSVersion.Version.Major >= 6) && (QueryFullProcessImageName(hprocess, 0, _PathBuffer, ref size) && (size > 0)))
|
||||
{
|
||||
return _PathBuffer.ToString();
|
||||
}
|
||||
|
||||
// Try the GetProcessImageFileName method
|
||||
if (PsAPI.GetProcessImageFileName(hprocess, _PathBuffer, (uint) _PathBuffer.Capacity) > 0)
|
||||
{
|
||||
string dospath = _PathBuffer.ToString();
|
||||
foreach (string drive in Environment.GetLogicalDrives())
|
||||
{
|
||||
if (QueryDosDevice(drive.TrimEnd('\\'), _PathBuffer, (uint) _PathBuffer.Capacity) > 0)
|
||||
{
|
||||
if (dospath.StartsWith(_PathBuffer.ToString()))
|
||||
{
|
||||
return drive + dospath.Remove(0, _PathBuffer.Length);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
CloseHandle(hprocess);
|
||||
}
|
||||
}
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
}
|
56
src/Greenshot.Base/UnmanagedHelpers/PsAPI.cs
Normal file
56
src/Greenshot.Base/UnmanagedHelpers/PsAPI.cs
Normal file
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* Greenshot - a free and open source screenshot tool
|
||||
* Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
|
||||
*
|
||||
* For more information see: https://getgreenshot.org/
|
||||
* The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using log4net;
|
||||
|
||||
namespace Greenshot.Base.UnmanagedHelpers
|
||||
{
|
||||
/// <summary>
|
||||
/// Description of PsAPI.
|
||||
/// </summary>
|
||||
public class PsAPI
|
||||
{
|
||||
private static readonly ILog LOG = LogManager.GetLogger(typeof(PsAPI));
|
||||
|
||||
[DllImport("psapi", SetLastError = true, CharSet = CharSet.Unicode)]
|
||||
public static extern uint GetModuleFileNameEx(IntPtr hProcess, IntPtr hModule, StringBuilder lpFilename, uint nSize);
|
||||
|
||||
[DllImport("psapi", SetLastError = true, CharSet = CharSet.Unicode)]
|
||||
public static extern uint GetProcessImageFileName(IntPtr hProcess, StringBuilder lpImageFileName, uint nSize);
|
||||
|
||||
[DllImport("psapi")]
|
||||
private static extern int EmptyWorkingSet(IntPtr hwProc);
|
||||
|
||||
/// <summary>
|
||||
/// Make the process use less memory by emptying the working set
|
||||
/// </summary>
|
||||
public static void EmptyWorkingSet()
|
||||
{
|
||||
LOG.Info("Calling EmptyWorkingSet");
|
||||
using Process currentProcess = Process.GetCurrentProcess();
|
||||
EmptyWorkingSet(currentProcess.Handle);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
using System;
|
||||
using System.Security.Permissions;
|
||||
using Greenshot.Base.UnmanagedHelpers.Enums;
|
||||
using log4net;
|
||||
using Microsoft.Win32.SafeHandles;
|
||||
|
||||
namespace Greenshot.Base.UnmanagedHelpers
|
||||
{
|
||||
/// <summary>
|
||||
/// A SafeHandle class implementation for the current input desktop
|
||||
/// </summary>
|
||||
public class SafeCurrentInputDesktopHandle : SafeHandleZeroOrMinusOneIsInvalid
|
||||
{
|
||||
private static readonly ILog LOG = LogManager.GetLogger(typeof(SafeCurrentInputDesktopHandle));
|
||||
|
||||
public SafeCurrentInputDesktopHandle() : base(true)
|
||||
{
|
||||
IntPtr hDesktop = User32.OpenInputDesktop(0, true, DesktopAccessRight.GENERIC_ALL);
|
||||
if (hDesktop != IntPtr.Zero)
|
||||
{
|
||||
SetHandle(hDesktop);
|
||||
if (User32.SetThreadDesktop(hDesktop))
|
||||
{
|
||||
LOG.DebugFormat("Switched to desktop {0}", hDesktop);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG.WarnFormat("Couldn't switch to desktop {0}", hDesktop);
|
||||
LOG.Error(User32.CreateWin32Exception("SetThreadDesktop"));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG.Warn("Couldn't get current desktop.");
|
||||
LOG.Error(User32.CreateWin32Exception("OpenInputDesktop"));
|
||||
}
|
||||
}
|
||||
|
||||
[SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode = true)]
|
||||
protected override bool ReleaseHandle()
|
||||
{
|
||||
return User32.CloseDesktop(handle);
|
||||
}
|
||||
}
|
||||
}
|
33
src/Greenshot.Base/UnmanagedHelpers/SafeIconHandle.cs
Normal file
33
src/Greenshot.Base/UnmanagedHelpers/SafeIconHandle.cs
Normal file
|
@ -0,0 +1,33 @@
|
|||
using System;
|
||||
using System.Security;
|
||||
using System.Security.Permissions;
|
||||
using Microsoft.Win32.SafeHandles;
|
||||
|
||||
namespace Greenshot.Base.UnmanagedHelpers
|
||||
{
|
||||
/// <summary>
|
||||
/// A SafeHandle class implementation for the hIcon
|
||||
/// </summary>
|
||||
public class SafeIconHandle : SafeHandleZeroOrMinusOneIsInvalid
|
||||
{
|
||||
/// <summary>
|
||||
/// Needed for marshalling return values
|
||||
/// </summary>
|
||||
[SecurityCritical]
|
||||
public SafeIconHandle() : base(true)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
public SafeIconHandle(IntPtr hIcon) : base(true)
|
||||
{
|
||||
SetHandle(hIcon);
|
||||
}
|
||||
|
||||
[SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode = true)]
|
||||
protected override bool ReleaseHandle()
|
||||
{
|
||||
return User32.DestroyIcon(handle);
|
||||
}
|
||||
}
|
||||
}
|
66
src/Greenshot.Base/UnmanagedHelpers/SafeWindowDcHandle.cs
Normal file
66
src/Greenshot.Base/UnmanagedHelpers/SafeWindowDcHandle.cs
Normal file
|
@ -0,0 +1,66 @@
|
|||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security;
|
||||
using System.Security.Permissions;
|
||||
using Microsoft.Win32.SafeHandles;
|
||||
|
||||
namespace Greenshot.Base.UnmanagedHelpers
|
||||
{
|
||||
/// <summary>
|
||||
/// A WindowDC SafeHandle implementation
|
||||
/// </summary>
|
||||
public class SafeWindowDcHandle : SafeHandleZeroOrMinusOneIsInvalid
|
||||
{
|
||||
[DllImport("user32", SetLastError = true)]
|
||||
private static extern IntPtr GetWindowDC(IntPtr hWnd);
|
||||
|
||||
[DllImport("user32", SetLastError = true)]
|
||||
private static extern bool ReleaseDC(IntPtr hWnd, IntPtr hDC);
|
||||
|
||||
private readonly IntPtr _hWnd;
|
||||
|
||||
/// <summary>
|
||||
/// Needed for marshalling return values
|
||||
/// </summary>
|
||||
public SafeWindowDcHandle() : base(true)
|
||||
{
|
||||
}
|
||||
|
||||
[SecurityCritical]
|
||||
public SafeWindowDcHandle(IntPtr hWnd, IntPtr preexistingHandle) : base(true)
|
||||
{
|
||||
_hWnd = hWnd;
|
||||
SetHandle(preexistingHandle);
|
||||
}
|
||||
|
||||
[SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode = true)]
|
||||
protected override bool ReleaseHandle()
|
||||
{
|
||||
bool returnValue = ReleaseDC(_hWnd, handle);
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a DC as SafeWindowDcHandle for the whole of the specified hWnd
|
||||
/// </summary>
|
||||
/// <param name="hWnd">IntPtr</param>
|
||||
/// <returns>SafeWindowDcHandle</returns>
|
||||
public static SafeWindowDcHandle FromWindow(IntPtr hWnd)
|
||||
{
|
||||
if (hWnd == IntPtr.Zero)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var hDcDesktop = GetWindowDC(hWnd);
|
||||
return new SafeWindowDcHandle(hWnd, hDcDesktop);
|
||||
}
|
||||
|
||||
public static SafeWindowDcHandle FromDesktop()
|
||||
{
|
||||
IntPtr hWndDesktop = User32.GetDesktopWindow();
|
||||
IntPtr hDCDesktop = GetWindowDC(hWndDesktop);
|
||||
return new SafeWindowDcHandle(hWndDesktop, hDCDesktop);
|
||||
}
|
||||
}
|
||||
}
|
123
src/Greenshot.Base/UnmanagedHelpers/Shell32.cs
Normal file
123
src/Greenshot.Base/UnmanagedHelpers/Shell32.cs
Normal file
|
@ -0,0 +1,123 @@
|
|||
/*
|
||||
* Greenshot - a free and open source screenshot tool
|
||||
* Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
|
||||
*
|
||||
* For more information see: https://getgreenshot.org/
|
||||
* The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Greenshot.Base.UnmanagedHelpers
|
||||
{
|
||||
/// <summary>
|
||||
/// Description of Shell32.
|
||||
/// </summary>
|
||||
public static class Shell32
|
||||
{
|
||||
[DllImport("shell32", CharSet = CharSet.Unicode)]
|
||||
public static extern int ExtractIconEx(string sFile, int iIndex, out IntPtr piLargeVersion, out IntPtr piSmallVersion, int amountIcons);
|
||||
|
||||
[DllImport("shell32", CharSet = CharSet.Unicode)]
|
||||
private static extern IntPtr SHGetFileInfo(string pszPath, uint dwFileAttributes, ref SHFILEINFO psfi, uint cbFileInfo, uint uFlags);
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
|
||||
private struct SHFILEINFO
|
||||
{
|
||||
public readonly IntPtr hIcon;
|
||||
public readonly int iIcon;
|
||||
public readonly uint dwAttributes;
|
||||
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
|
||||
public readonly string szDisplayName;
|
||||
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 80)]
|
||||
public readonly string szTypeName;
|
||||
};
|
||||
|
||||
// Browsing for directory.
|
||||
|
||||
private const uint SHGFI_ICON = 0x000000100; // get icon
|
||||
private const uint SHGFI_LINKOVERLAY = 0x000008000; // put a link overlay on icon
|
||||
private const uint SHGFI_LARGEICON = 0x000000000; // get large icon
|
||||
private const uint SHGFI_SMALLICON = 0x000000001; // get small icon
|
||||
private const uint SHGFI_USEFILEATTRIBUTES = 0x000000010; // use passed dwFileAttribute
|
||||
private const uint FILE_ATTRIBUTE_NORMAL = 0x00000080;
|
||||
|
||||
/// <summary>
|
||||
/// Options to specify the size of icons to return.
|
||||
/// </summary>
|
||||
public enum IconSize
|
||||
{
|
||||
/// <summary>
|
||||
/// Specify large icon - 32 pixels by 32 pixels.
|
||||
/// </summary>
|
||||
Large = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Specify small icon - 16 pixels by 16 pixels.
|
||||
/// </summary>
|
||||
Small = 1
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns an icon for a given file extension - indicated by the name parameter.
|
||||
/// See: https://msdn.microsoft.com/en-us/library/windows/desktop/bb762179(v=vs.85).aspx
|
||||
/// </summary>
|
||||
/// <param name="filename">Filename</param>
|
||||
/// <param name="size">Large or small</param>
|
||||
/// <param name="linkOverlay">Whether to include the link icon</param>
|
||||
/// <returns>System.Drawing.Icon</returns>
|
||||
public static Icon GetFileIcon(string filename, IconSize size, bool linkOverlay)
|
||||
{
|
||||
SHFILEINFO shfi = new SHFILEINFO();
|
||||
// SHGFI_USEFILEATTRIBUTES makes it simulate, just gets the icon for the extension
|
||||
uint flags = SHGFI_ICON | SHGFI_USEFILEATTRIBUTES;
|
||||
|
||||
if (linkOverlay)
|
||||
{
|
||||
flags += SHGFI_LINKOVERLAY;
|
||||
}
|
||||
|
||||
// Check the size specified for return.
|
||||
if (IconSize.Small == size)
|
||||
{
|
||||
flags += SHGFI_SMALLICON;
|
||||
}
|
||||
else
|
||||
{
|
||||
flags += SHGFI_LARGEICON;
|
||||
}
|
||||
|
||||
SHGetFileInfo(Path.GetFileName(filename), FILE_ATTRIBUTE_NORMAL, ref shfi, (uint) Marshal.SizeOf(shfi), flags);
|
||||
|
||||
// Only return an icon if we really got one
|
||||
if (shfi.hIcon != IntPtr.Zero)
|
||||
{
|
||||
// Copy (clone) the returned icon to a new object, thus allowing us to clean-up properly
|
||||
Icon icon = (Icon) Icon.FromHandle(shfi.hIcon).Clone();
|
||||
// Cleanup
|
||||
User32.DestroyIcon(shfi.hIcon);
|
||||
return icon;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -19,18 +19,17 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace Greenshot.Base.Core.Enums
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Greenshot.Base.UnmanagedHelpers.Structs
|
||||
{
|
||||
internal enum ExifOrientations : byte
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct CursorInfo
|
||||
{
|
||||
Unknown = 0,
|
||||
TopLeft = 1,
|
||||
TopRight = 2,
|
||||
BottomRight = 3,
|
||||
BottomLeft = 4,
|
||||
LeftTop = 5,
|
||||
RightTop = 6,
|
||||
RightBottom = 7,
|
||||
LeftBottom = 8,
|
||||
public int cbSize;
|
||||
public int flags;
|
||||
public IntPtr hCursor;
|
||||
public POINT ptScreenPos;
|
||||
}
|
||||
}
|
36
src/Greenshot.Base/UnmanagedHelpers/Structs/IconInfo.cs
Normal file
36
src/Greenshot.Base/UnmanagedHelpers/Structs/IconInfo.cs
Normal file
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* Greenshot - a free and open source screenshot tool
|
||||
* Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom
|
||||
*
|
||||
* For more information see: https://getgreenshot.org/
|
||||
* The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Greenshot.Base.UnmanagedHelpers.Structs
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct IconInfo
|
||||
{
|
||||
public bool fIcon;
|
||||
public int xHotspot;
|
||||
public int yHotspot;
|
||||
public IntPtr hbmMask;
|
||||
public IntPtr hbmColor;
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue