Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added support for Apple Silicon (M1) and heic images, updated to electron 16/webpack 5 #116

Open
wants to merge 2 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions .babelrc
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
{
"presets": ["es2015-node", "react"]
}
"presets": [
"@babel/preset-env",
"@babel/preset-typescript",
"@babel/preset-react"
],
"plugins": ["@babel/plugin-transform-runtime"]
}
4 changes: 4 additions & 0 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"semi": false,
"singleQuote": true
}
80 changes: 43 additions & 37 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,37 +15,35 @@
"description": "An open source, cross platform app for still image camera matching",
"license": "GPL-3.0",
"devDependencies": {
"@types/electron-window-state": "^2.0.33",
"@babel/core": "^7.16.5",
"@babel/plugin-transform-runtime": "^7.16.5",
"@babel/preset-env": "^7.16.5",
"@babel/preset-react": "^7.16.5",
"@babel/preset-typescript": "^7.16.5",
"@types/electron-window-state": "^5.0.0",
"@types/jest": "^27.0.3",
"@types/minimist": "^1.2.0",
"@types/jest": "^23.0.0",
"@types/react": "^16.3.16",
"@types/react-dom": "^16.0.5",
"@types/react": "^17.0.37",
"@types/react-dom": "^17.0.11",
"@types/react-measure": "^2.0.2",
"@types/react-redux": "^6.0.1",
"babel-core": "^6.26.3",
"babel-loader": "^7.1.4",
"babel-preset-es2015": "^6.24.1",
"babel-preset-es2015-node": "^6.1.1",
"babel-preset-react": "^6.24.1",
"babel-preset-stage-2": "^6.24.1",
"css-loader": "^0.28.11",
"electron": "^8.2.1",
"electron-builder": "^22.4.0",
"html-webpack-plugin": "^3.2.0",
"jest": "^23.1.0",
"jest-junit": "^5.0.0",
"standard": "^11.0.1",
"standard-loader": "^6.0.1",
"style-loader": "^0.21.0",
"trash-cli": "^1.4.0",
"ts-loader": "^4.3.1",
"tslint": "^5.10.0",
"tslint-config-standard": "^7.0.0",
"tslint-loader": "^3.6.0",
"typescript": "^2.9.1",
"webpack": "^4.10.2",
"webpack-cli": "^3.0.1",
"webpack-dev-server": "^3.1.4"
"@types/react-redux": "^7.1.20",
"babel-loader": "^8.2.3",
"css-loader": "^6.5.1",
"electron": "^16.0.5",
"electron-builder": "^22.14.5",
"html-webpack-plugin": "^5.5.0",
"jest": "^27.4.5",
"jest-junit": "^13.0.0",
"standard": "^16.0.4",
"standard-loader": "^7.0.0",
"style-loader": "^3.3.1",
"trash-cli": "^5.0.0",
"tslint": "^6.1.3",
"tslint-config-standard": "^9.0.0",
"typescript": "^4.5.4",
"webpack": "^5.65.0",
"webpack-cli": "^4.9.1",
"webpack-dev-server": "^4.7.0"
},
"scripts": {
"prebuild-dev": "trash build",
Expand All @@ -58,22 +56,24 @@
"prebuild-test": "trash __tests__",
"build-test": "webpack --config webpack.tests.config.js --mode development",
"pretest": "yarn run build-test",
"dev-server": "webpack-dev-server --config webpack.config.js --content-base build/ --mode development",
"dev-server": "webpack-dev-server --config webpack.config.js --mode development",
"electron-dev": "DEV=true electron ./build/main.js",
"dist": "electron-builder -mwl",
"test": "jest",
"prepublish-release": "yarn build-dist",
"publish-release": "electron-builder -mwl --publish always"
},
"dependencies": {
"check-image-type": "^0.1.4",
"electron-window-state": "^5.0.3",
"heic2any": "https://github.com/chebum/heic2any",
"konva": "^8.3.1",
"minimist": "^1.2.0",
"electron-window-state": "^4.1.1",
"konva": "^2.1.3",
"react": "^16.4.0",
"react-dom": "^16.4.0",
"react-konva": "^1.7.4",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-konva": "^17.0.2-5",
"react-measure": "^2.0.2",
"react-redux": "^5.0.7",
"react-redux": "^7.2.6",
"redux": "^4.0.0",
"redux-thunk": "^2.3.0"
},
Expand All @@ -86,7 +86,13 @@
"productName": "fSpy",
"appId": "com.stuffmatic.fspy",
"mac": {
"target": "dmg",
"target": {
"target": "dmg",
"arch": [
"x64",
"arm64"
]
},
"category": "public.app-category.utilities"
},
"linux": {
Expand Down
18 changes: 11 additions & 7 deletions src/cli/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,15 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

import { existsSync, readFileSync, writeFileSync } from 'fs'
import minimist from 'minimist'
import { writeFileSync, readFileSync, existsSync } from 'fs'
import SavedState from '../gui/io/saved-state'
import { CalibrationMode } from '../gui/types/global-settings'
import Solver from '../gui/solver/solver'
import { ImageState } from '../gui/types/image-state'
import { SolverResult } from '../gui/solver/solver-result'
import { CalibrationMode } from '../gui/types/global-settings'
import { ImageState } from '../gui/types/image-state'

export class CLI {

static printUsage() {
console.log('fSpy CLI')
console.log('')
Expand Down Expand Up @@ -80,14 +79,19 @@ export class CLI {
}

const imageState: ImageState = {
loading: false,
width: imageWidth,
height: imageHeight,
url: null,
data: null
data: null,
}

const projectState: SavedState = JSON.parse(readFileSync(statePath).toString())
const is1VPMode = projectState.globalSettings.calibrationMode == CalibrationMode.OneVanishingPoint
const projectState: SavedState = JSON.parse(
readFileSync(statePath).toString()
)
const is1VPMode =
projectState.globalSettings.calibrationMode ==
CalibrationMode.OneVanishingPoint
let solverResult: SolverResult
if (is1VPMode) {
solverResult = Solver.solve1VP(
Expand Down
134 changes: 91 additions & 43 deletions src/gui/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,33 +16,51 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

import { dialog, ipcRenderer } from 'electron'
import { readFileSync } from 'fs'
import * as React from 'react'
import { connect } from 'react-redux'
import { Dispatch } from 'redux'
import {
ExportMessage,
ExportType,
NewProjectMessage,
OpenImageMessage,
OpenProjectMessage,
SaveProjectAsMessage,
SaveProjectMessage,
SetSidePanelVisibilityMessage,
} from '../main/ipc-messages'
import {
AppAction,
loadDefaultState,
setImage,
setImageLoading,
setSidePanelVisibility,
} from './actions'
import SplashScreen from './components/splash-screen'
import ControlPointsContainer from './containers/control-points-container'
import ResultContainer from './containers/result-container'
import SettingsContainer from './containers/settings-container'

import { StoreState } from './types/store-state'
import { connect } from 'react-redux'
import { AppAction, setImage, loadDefaultState, setSidePanelVisibility } from './actions'
import { GlobalSettings } from './types/global-settings'
import { UIState } from './types/ui-state'
import { ImageState } from './types/image-state'
import { SolverResult } from './solver/solver-result'
import { ipcRenderer, remote } from 'electron'
import { NewProjectMessage, OpenProjectMessage, SaveProjectMessage, SaveProjectAsMessage, OpenImageMessage, ExportMessage, ExportType, SetSidePanelVisibilityMessage } from '../main/ipc-messages'
import ProjectFile from './io/project-file'
import { readFileSync } from 'fs'
import { SpecifyProjectPathMessage, OpenDroppedProjectMessage, SpecifyExportPathMessage } from './ipc-messages'
import { loadImage } from './io/util'
import {
OpenDroppedProjectMessage,
SpecifyExportPathMessage,
SpecifyProjectPathMessage,
} from './ipc-messages'
import { SolverResult } from './solver/solver-result'
import store from './store/store'
import SplashScreen from './components/splash-screen'
import { Dispatch } from 'redux'
import { GlobalSettings } from './types/global-settings'
import { ImageState } from './types/image-state'
import { StoreState } from './types/store-state'
import { UIState } from './types/ui-state'

interface AppProps {
uiState: UIState,
globalSettings: GlobalSettings,
solverResult: SolverResult,
image: ImageState,
uiState: UIState
globalSettings: GlobalSettings
solverResult: SolverResult
image: ImageState
onImageFileDropped(imagePath: string): void
onProjectFileDropped(imagePath: string): void
onOpenExampleProjectPressed(): void
Expand All @@ -56,7 +74,6 @@ interface AppProps {
}

class App extends React.PureComponent<AppProps> {

constructor(props: AppProps) {
super(props)
}
Expand Down Expand Up @@ -102,11 +119,17 @@ class App extends React.PureComponent<AppProps> {
render() {
const hasImage = this.props.image.data !== null
return (
<div id='app-container'>
<SettingsContainer isVisible={this.props.uiState.sidePanelsAreVisible} />
<div id="app-container">
<SettingsContainer
isVisible={this.props.uiState.sidePanelsAreVisible}
/>
<ControlPointsContainer />
<ResultContainer isVisible={this.props.uiState.sidePanelsAreVisible} />
{ !hasImage ? (<SplashScreen onClickedLoadExampleProject={this.props.onOpenExampleProjectPressed} />) : null }
{!hasImage ? (
<SplashScreen
onClickedLoadExampleProject={this.props.onOpenExampleProjectPressed}
/>
) : null}
</div>
)
}
Expand All @@ -116,33 +139,56 @@ class App extends React.PureComponent<AppProps> {
this.props.onNewProjectIPCMessage()
})

ipcRenderer.on(OpenProjectMessage.type, (_: any, message: OpenProjectMessage) => {
this.props.onOpenProjectIPCMessage(message.filePath, message.isExampleProject)
})
ipcRenderer.on(
OpenProjectMessage.type,
(_: any, message: OpenProjectMessage) => {
this.props.onOpenProjectIPCMessage(
message.filePath,
message.isExampleProject
)
}
)

ipcRenderer.on(SaveProjectMessage.type, (_: any, __: SaveProjectMessage) => {
if (this.props.uiState.projectFilePath) {
this.props.onSaveProjectAsIPCMessage(this.props.uiState.projectFilePath)
} else {
ipcRenderer.send(SpecifyProjectPathMessage.type, new SpecifyProjectPathMessage())
ipcRenderer.on(
SaveProjectMessage.type,
(_: any, __: SaveProjectMessage) => {
if (this.props.uiState.projectFilePath) {
this.props.onSaveProjectAsIPCMessage(
this.props.uiState.projectFilePath
)
} else {
ipcRenderer.send(
SpecifyProjectPathMessage.type,
new SpecifyProjectPathMessage()
)
}
}
})
)

ipcRenderer.on(SaveProjectAsMessage.type, (_: any, message: SaveProjectAsMessage) => {
this.props.onSaveProjectAsIPCMessage(message.filePath)
})
ipcRenderer.on(
SaveProjectAsMessage.type,
(_: any, message: SaveProjectAsMessage) => {
this.props.onSaveProjectAsIPCMessage(message.filePath)
}
)

ipcRenderer.on(OpenImageMessage.type, (_: any, message: OpenImageMessage) => {
this.props.onOpenImageIPCMessage(message.filePath)
})
ipcRenderer.on(
OpenImageMessage.type,
(_: any, message: OpenImageMessage) => {
this.props.onOpenImageIPCMessage(message.filePath)
}
)

ipcRenderer.on(ExportMessage.type, (_: any, message: ExportMessage) => {
this.props.onExportIPCMessage(message.exportType)
})

ipcRenderer.on(SetSidePanelVisibilityMessage.type, (_: any, message: SetSidePanelVisibilityMessage) => {
this.props.onSetSidePanelVisibilityIPCMessage(message.panelsAreVisible)
})
ipcRenderer.on(
SetSidePanelVisibilityMessage.type,
(_: any, message: SetSidePanelVisibilityMessage) => {
this.props.onSetSidePanelVisibilityIPCMessage(message.panelsAreVisible)
}
)
}
}

Expand All @@ -151,7 +197,7 @@ export function mapStateToProps(state: StoreState) {
uiState: state.uiState,
globalSettings: state.globalSettings,
solverResult: state.solverResult,
image: state.image
image: state.image,
}
}

Expand All @@ -162,11 +208,12 @@ export function mapDispatchToProps(dispatch: Dispatch<AppAction>) {
// TODO: good to do async loading here?
loadImage(
imageBuffer,
() => dispatch(setImageLoading()),
(width: number, height: number, url: string) => {
dispatch(setImage(url, imageBuffer, width, height))
},
() => {
remote.dialog.showErrorBox(
dialog.showErrorBox(
'Failed to load image data',
'Could not load the image data. Is this a valid image file?'
)
Expand Down Expand Up @@ -195,6 +242,7 @@ export function mapDispatchToProps(dispatch: Dispatch<AppAction>) {
let imageBuffer = readFileSync(imagePath)
loadImage(
imageBuffer,
() => dispatch(setImageLoading()),
(width: number, height: number, url: string) => {
dispatch(setImage(url, imageBuffer, width, height))
},
Expand Down Expand Up @@ -230,7 +278,7 @@ export function mapDispatchToProps(dispatch: Dispatch<AppAction>) {
},
onSetSidePanelVisibilityIPCMessage: (panelsAreVisible: boolean) => {
dispatch(setSidePanelVisibility(panelsAreVisible))
}
},
}
}

Expand Down
Loading