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

Importing Images #306

Merged
merged 4 commits into from
Jun 29, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
34 changes: 34 additions & 0 deletions src/js/files/FileReader.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
const path = require('path')
const fs = require('fs')

/**
* Retrieve a base 64 representation of an image file
*
* @param {string} filepath
* @returns {string}
*/
let getBase64ImageDataFromFilePath = (filepath) => {
let arr = filepath.split(path.sep)
let filename = arr[arr.length-1]
let filenameParts =filename.toLowerCase().split('.')
let type = filenameParts[filenameParts.length-1]

switch(type) {
case "png":
return getBase64TypeFromFilePath('png', filepath)
case "jpg":
return getBase64TypeFromFilePath('jpg', filepath)
}
}

let getBase64TypeFromFilePath = (type, filepath) => {
if (!fs.existsSync(filepath)) return null

// via https://gist.github.com/mklabs/1260228/71d62802f82e5ac0bd97fcbd54b1214f501f7e77
let data = fs.readFileSync(filepath).toString('base64')
return `data:image/${type};base64,${data}`
}

module.exports = {
getBase64ImageDataFromFilePath,
}
48 changes: 48 additions & 0 deletions src/js/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,50 @@ let openDialogue = () => {
})
}

let importImagesDialogue = () => {
dialog.showOpenDialog(
{
title:"Import Boards",
filters:[
{name: 'Images', extensions: ['png', 'jpg']},
],
properties: [
"openFile",
"openDirectory",
"multiSelections"
]
},

(filepaths)=>{
if (filepaths) {
let filepathsRecursive = []
let handleDirectory = (dirPath) => {
let innerFilenames = fs.readdirSync(dirPath)
for(let innerFilename of innerFilenames) {
var innerFilePath = path.join(dirPath, innerFilename)
let stats = fs.statSync(innerFilePath)
if(stats.isFile()) {
filepathsRecursive.push(innerFilePath)
} else if(stats.isDirectory()) {
handleDirectory(innerFilePath)
}
}
}
for(let filepath of filepaths) {
let stats = fs.statSync(filepath)
if(stats.isFile()) {
filepathsRecursive.push(filepath)
} else if(stats.isDirectory()) {
handleDirectory(filepath)
}
}

mainWindow.webContents.send('insertNewBoardsWithFiles', filepathsRecursive)
}
}
)
}

let processFountainData = (data, create, update) => {
let scriptData = fountain.parse(data, true)
let locations = fountainDataParser.getLocations(scriptData.tokens)
Expand Down Expand Up @@ -546,6 +590,10 @@ ipcMain.on('openDialogue', (e, arg)=> {
openDialogue()
})

ipcMain.on('importImagesDialogue', (e, arg)=> {
importImagesDialogue()
})

ipcMain.on('createNew', (e, arg)=> {
createNew()
})
Expand Down
7 changes: 7 additions & 0 deletions src/js/menu.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,13 @@ const template = [
ipcRenderer.send('openDialogue')
}
},
{
label: 'Import Storyboards',
accelerator: 'CmdOrCtrl+Shift+i',
click ( item, focusedWindow, event) {
ipcRenderer.send('importImagesDialogue')
}
},
{
type: 'separator'
},
Expand Down
111 changes: 89 additions & 22 deletions src/js/window/main-window.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ const storyTips = new(require('./story-tips'))(sfx, notifications)
const exporter = require('./exporter.js')
const prefsModule = require('electron').remote.require('./prefs.js')

const FileReader = require('../files/FileReader.js')
const writePsd = require('ag-psd').writePsd;
const readPsd = require('ag-psd').readPsd;
const initializeCanvas = require('ag-psd').initializeCanvas;
Expand Down Expand Up @@ -886,16 +887,7 @@ let updateBoardUI = ()=> {
// Board Operations
///////////////////////////////////////////////////////////////

let newBoard = (position, shouldAddToUndoStack = true) => {
if (shouldAddToUndoStack) {
saveImageFile() // force-save any current work
storeUndoStateForScene(true)
notifications.notify({message: "Added a new board. Let's make it a great one!", timing: 5})
}

if (typeof position == "undefined") position = currentBoard + 1

// create array entry
let insertNewBoardDataAtPosition = (position) => {
let uid = util.uidGen(5)

let board = {
Expand All @@ -906,9 +898,23 @@ let newBoard = (position, shouldAddToUndoStack = true) => {
layers: {}
}

// insert
boardData.boards.splice(position, 0, board)

return board
}

let newBoard = (position, shouldAddToUndoStack = true) => {
if (shouldAddToUndoStack) {
saveImageFile() // force-save any current work
storeUndoStateForScene(true)
notifications.notify({message: "Added a new board. Let's make it a great one!", timing: 5})
}

if (typeof position == "undefined") position = currentBoard + 1

// create array entry
insertNewBoardDataAtPosition(position)

// indicate dirty for save sweep
markImageFileDirty([1]) // mark save for 'main' layer only // HACK hardcoded
markBoardFileDirty() // to save new board data
Expand All @@ -923,6 +929,64 @@ let newBoard = (position, shouldAddToUndoStack = true) => {
}
}

let insertNewBoardsWithFiles = (filepaths) => {
let insertionIndex = currentBoard+1
let imageFilePromises = filepaths.map(filepath => {
let imageData = FileReader.getBase64ImageDataFromFilePath(filepath)
if(!imageData) {
return new Promise((fulfill)=>fulfill())
}
let board = insertNewBoardDataAtPosition(insertionIndex++)
var image = new Image()
image.src = imageData

return new Promise((fulfill, reject)=>{
setImmediate(()=>{
// resize the image if it's too big.
let boardSize = storyboarderSketchPane.sketchPane.getCanvasSize()
if(boardSize.width < image.width) {
let scale = boardSize.width / image.width
image.width = scale * image.width
image.height = scale * image.height
}
if(boardSize.height < image.height) {
let scale = boardSize.height / image.height
image.width = scale * image.width
image.height = scale * image.height
}

// try pooling
var canvas = document.createElement('canvas')
canvas.width = image.width
canvas.height = image.height
let context = canvas.getContext('2d')
context.drawImage(image, 0, 0, image.width, image.height)
var imageDataSized = canvas.toDataURL()
saveDataURLtoFile(imageDataSized, board.url)

// thumbnail
let thumbRatio = 60/image.height
canvas.width = image.width = thumbRatio * image.width
canvas.height = image.height = thumbRatio * image.height
context.drawImage(image, 0, 0, image.width, image.height)
var imageDataSized = canvas.toDataURL()
let thumbPath = board.url.replace('.png', '-thumbnail.png')
saveDataURLtoFile(imageDataSized, thumbPath)

fulfill()
})
})

})

Promise.all(imageFilePromises)
.then(()=>{
markImageFileDirty([1])
markBoardFileDirty() // to save new board data
renderThumbnailDrawer()
})
}

let markBoardFileDirty = () => {
boardFileDirty = true
clearTimeout(boardFileDirtyTimer)
Expand Down Expand Up @@ -1042,8 +1106,15 @@ let saveImageFile = () => {
}
}

const getThumbnailSize = () => {
return {
width: Math.floor(60 * boardData.aspectRatio),
height: 60
}
}

const updateThumbnail = imageFilePath => {
let width = Math.floor(60 * boardData.aspectRatio), height = 60
let {width, height} = getThumbnailSize()

storyboarderSketchPane.sketchPane.setLayerVisible(false, 2) // HACK hardcoded
storyboarderSketchPane.sketchPane.setLayerVisible(false, 4) // HACK hardcoded
Expand Down Expand Up @@ -2607,14 +2678,6 @@ let importImage = (imageDataURL) => {

}

let loadPNGImageFileAsDataURI = (filepath) => {
if (!fs.existsSync(filepath)) return null

// via https://gist.github.com/mklabs/1260228/71d62802f82e5ac0bd97fcbd54b1214f501f7e77
let data = fs.readFileSync(filepath).toString('base64')
return `data:image/png;base64,${data}`
}

/**
* Copy
*
Expand Down Expand Up @@ -2654,7 +2717,7 @@ let copyBoards = () => {
boards = boards.map(board => {

let filepath = path.join(boardPath, 'images', board.url)
let data = loadPNGImageFileAsDataURI(filepath)
let data = FileReader.getBase64ImageDataFromFilePath(filepath)
if (data) {
board.imageDataURL = data
} else {
Expand All @@ -2665,7 +2728,7 @@ let copyBoards = () => {
for (let layerName of ['reference', 'notes']) { // HACK hardcoded
if (board.layers[layerName]) {
let filepath = path.join(boardPath, 'images', board.layers[layerName].url)
let data = loadPNGImageFileAsDataURI(filepath)
let data = FileReader.getBase64ImageDataFromFilePath(filepath)
if (data) {
board.layers[layerName].imageDataURL = data
} else {
Expand Down Expand Up @@ -3337,6 +3400,10 @@ ipcRenderer.on('textInputMode', (event, args)=>{
textInputAllowAdvance = false
})

ipcRenderer.on('insertNewBoardsWithFiles', (event, filepaths)=> {
insertNewBoardsWithFiles(filepaths)
})

ipcRenderer.on('importImage', (event, args)=> {
//console.log(args)
importImage(args)
Expand Down