Skip to content

Commit

Permalink
Merge pull request #8 from shootsoft/1.4.4_dark_ui
Browse files Browse the repository at this point in the history
1.4.4 dark ui
  • Loading branch information
shootsoft committed Apr 28, 2018
2 parents 5238a6a + 49ea557 commit 20eb4bc
Show file tree
Hide file tree
Showing 55 changed files with 551 additions and 80 deletions.
1 change: 1 addition & 0 deletions .gitignore
Expand Up @@ -103,3 +103,4 @@ ENV/

.idea/
/*.dmg
/*.pfx
6 changes: 2 additions & 4 deletions README.md
Expand Up @@ -20,13 +20,11 @@ Pluto Video Snapshoter

![Snapshot UI](doc/images/snapshot_ui.png)

![Snapshot UI](doc/images/snapshot_ui_stitching.png)

![Snapshot UI](doc/images/auto_detection/subtitle_auto_detection.png)

![Snapshot UI](doc/images/auto_detection/preview.png)
![Snapshot UI](doc/images/snapshot_ui_stitching_preview.png)

See [User Maual](doc/user_manual.md)
See [User Maual](doc/user_manual.md) [中文用户手册](https://gitee.com/shootsoft/PlutoVideoSnapshoter/blob/master/doc/user_manual_cn.md)

# Development

Expand Down
25 changes: 24 additions & 1 deletion build_mac.sh
@@ -1,9 +1,32 @@
#!/bin/sh

echo "Creating app file..."
rm -rf dist
pyinstaller -D -w mac_build.spec
dmgbuild -s dmg_settings.py "PlutoVideoSnapshoter Volume" PlutoVideoSnapshoter.dmg
echo "app created."

if [ "$1" == "dmg" ]; then

if [ -n "$2" ]; then
echo "Signing..."
codesign -s "$2" dist/PlutoVideoSnapshoter.app --deep
echo "Verify signing..."
codesign -dv --verbose=4 dist/PlutoVideoSnapshoter.app
fi

echo "Creating dmg file..."
dmgbuild -s dmg_settings.py "PlutoVideoSnapshoter Volume" PlutoVideoSnapshoter.dmg

if [ -n "$2" ]; then
echo "Signing..."
codesign -s "$2" PlutoVideoSnapshoter.dmg
echo "Verify signing..."
codesign -dv --verbose=4 PlutoVideoSnapshoter.dmg
echo "DMG created."
fi
fi

echo "All done."
# Multiple files, for debugging

#pyinstaller --clean -F -w \
Expand Down
12 changes: 8 additions & 4 deletions build_win.bat
@@ -1,18 +1,22 @@
pyinstaller -F -w --icon=res/pluto.ico ^
--add-data "src\windows;windows" ^
--add-data "venv/v36/Lib/site-packages/cv2/opencv_ffmpeg340.dll;./" ^
--add-data "venv/v36/Lib/site-packages/cv2/opencv_ffmpeg330.dll;./" ^
--path "C:\Program Files (x86)\Windows Kits\10\Redist\ucrt\DLLs\x86" ^
--version-file=file_version_info.txt "src\app.py" ^
-n "PlutoVideoSnapshoter"

goto comment
IF [%1] == [] GOTO end
"C:\Program Files (x86)\Windows Kits\10\bin\x86\signtool.exe" sign ^
/f Certificates.pfx /p %1 /t "http://timestamp.comodoca.com" ^
"dist\PlutoVideoSnapshoter.exe"
GOTO end
...skip this...
REM Multiple files, for debugging
pyinstaller -D -w --icon=res/pluto.ico ^
--add-data "src\windows;windows" ^
--add-data "venv/v36/Lib/site-packages/cv2/opencv_ffmpeg340.dll;./" ^
--add-data "venv/v36/Lib/site-packages/cv2/opencv_ffmpeg330.dll;./" ^
--path "C:\Program Files (x86)\Windows Kits\10\Redist\ucrt\DLLs\x86" ^
--version-file=file_version_info.txt "src\app.py" ^
-n "PlutoVideoSnapshoter"

:comment
:end
Binary file modified doc/images/auto_detection/subtitle_auto_detection.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified doc/images/snapshot_ui.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified doc/images/snapshot_ui_stitching.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified doc/images/snapshot_ui_stitching_preview.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/images/usage/screenshot_app.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified doc/images/usage/screenshot_exe.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified doc/images/usage/screenshot_jump.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/images/usage/screenshot_open copy.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified doc/images/usage/screenshot_open.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/images/usage/screenshot_output copy.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified doc/images/usage/screenshot_output.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified doc/images/usage/screenshot_play.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified doc/images/usage/screenshot_preview.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified doc/images/usage/screenshot_preview_selected.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified doc/images/usage/screenshot_save.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified doc/images/usage/screenshot_single.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified doc/images/usage/screenshot_srt.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified doc/images/usage/screenshot_task.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified doc/images/usage/screenshot_updown.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 4 additions & 2 deletions doc/package_doc/说明.txt
@@ -1,8 +1,8 @@
视频截图字幕拼接精灵

- 开发商:射日工作室 https://shootsoft.net
- 主页:https://github.com/shootsoft/PlutoVideoSnapshoter
- 下载:https://github.com/shootsoft/PlutoVideoSnapshoter/releases
- 主页:https://shootsoft.gitee.io/pluto/
- 下载:https://gitee.com/shootsoft/PlutoVideoSnapshoter/releases

本软件运行需要系统安装相应的视频解码类库,推荐 K-Lite Codec Pack http://www.codecguide.com/download_kl.htm

Expand All @@ -14,3 +14,5 @@
- 自动检测字幕区域
- 允许单张批量图片手动调整字幕区域
- 截图拼接一气呵成

视频截图字幕拼接精灵是一款能够在多个平台下使用的视频截图软件,本软件同时集成了依据字幕自动截图,图片字幕区域自动识别功能。能够将多张带有字幕的截图拼接成一张完整图片。
19 changes: 11 additions & 8 deletions doc/user_manual.md
@@ -1,18 +1,24 @@
PlutoVideoSanpshoter Usage
====

1. Launch application
## Launch application
1. Launch application on Windows
![Launch](images/usage/screenshot_exe.png)
1. Launch application on macOS
![Launch](images/usage/screenshot_app.png)

## Usage

1. Open a video
![Open a video](images/usage/screenshot_open.png)
1. (Optional) Select snapshot output folder
![Output folder](images/usage/screenshot_output.png)
1. (Optional, this is required for auto snapshots) Open a subtitle file (*.srt). The file could be automatically detected if the file has the same name as the video file.
1. (Optional, this is required for `Auto Snapshots`) Open a subtitle file (*.srt). The file could be automatically detected if the file has the same name as the video file. Note: current version doesn't support rendering subtitles into video screen or snapshots.
![Open srt file](images/usage/screenshot_srt.png)
1. Play video and take single snapshot
1. Play video and take single snapshot (video will automatically start playing once you opened it. You can also stop the video by click the same button or click video area)
![Play](images/usage/screenshot_play.png)
![Single snapshot](images/usage/screenshot_single.png)
1. Select start and end, run auto snapshot for each line of subtitles.
1. Select `Start` and `End`, run `Auto Anapshot` to take snapshots with each line of subtitles.
![Task](images/usage/screenshot_task.png)
1. Jump to snapshot stitching
![Jump](images/usage/screenshot_jump.png)
Expand All @@ -23,12 +29,9 @@ PlutoVideoSanpshoter Usage
1. Save stitched image
![Save](images/usage/screenshot_save.png)

# Advanced
## Advanced

1. Preview/save selected images (right click selected images)

![Save](images/usage/screenshot_preview_selected.png)

1. Automatically detect subtitle positions

![Save](images/auto_detection/subtitle_auto_detection.png)
52 changes: 52 additions & 0 deletions doc/user_manual_cn.md
@@ -0,0 +1,52 @@
视频截图字幕拼接精灵使用说明
==============
本软件运行需要系统安装相应的视频解码类库,推荐 K-Lite Codec Pack http://www.codecguide.com/download_kl.htm

软件特点:

- 多平台 (macOS/Windows/Linux)
- 视频手动截图
- 视频依据字幕自动截图
- 自动检测字幕区域
- 允许单张批量图片手动调整字幕区域
- 截图拼接一气呵成

视频截图字幕拼接精灵是一款能够在多个平台下使用的视频截图软件,本软件同时集成了依据字幕截图,图片字幕区域自动识别功能。能够将多张带有字幕的截图拼接成一张完整图片。效果如图:
![预览](images/snapshot_ui_stitching_preview.png)

## 启动应用

1. Windows下启动。
![Launch](images/usage/screenshot_exe.png)
1. macOS下启动。
![Launch](images/usage/screenshot_app.png)

## 使用说明

1. 打开视频。
![Open a video](images/usage/screenshot_open.png)
1. (可选) 选择截图存放路径。
![Output folder](images/usage/screenshot_output.png)
1. (可选, 针对`Auto Snapshots`,这个是必选) 打开字幕文件 (*.srt). 如果字幕文件与视频文件是相同的文件名,这个字幕文件会被自动加载。注意:本软件现阶段并不支持渲染字幕到视频或者截屏上。
![Open srt file](images/usage/screenshot_srt.png)
1. 播放视频或者手动截图(当视频被打开之后会立刻开始自动播放,此时,播放按钮会变成暂停,单机视频区域也可以播放或者暂停视频)。
![Play](images/usage/screenshot_play.png)
![Single snapshot](images/usage/screenshot_single.png)
1. 选择 `Start``End`, 之后就可以通过点击`Auto Anapshot`针对有字幕的每一帧自动进行截屏。
![Task](images/usage/screenshot_task.png)
1. 跳转到`Image Stitching`
![Jump](images/usage/screenshot_jump.png)
1. 选择视频字幕上下区域。
![Up and Down limit](images/usage/screenshot_updown.png)
1. 预览拼接效果。
![Jump](images/usage/screenshot_preview.png)
1. 保存拼接的图片。
![Save](images/usage/screenshot_save.png)

## 高级

1. 字幕区域自动识别。
![Save](images/auto_detection/subtitle_auto_detection.png)
1. 预览/保存选择性拼接。
![Save](images/usage/screenshot_preview_selected.png)

4 changes: 2 additions & 2 deletions file_version_info.txt
Expand Up @@ -31,12 +31,12 @@ VSVersionInfo(
u'040904e4',
[StringStruct(u'CompanyName', u'Shoot Sun Studio'),
StringStruct(u'FileDescription', u'Pluto Video Snapshoter'),
StringStruct(u'FileVersion', u'1.4.3'),
StringStruct(u'FileVersion', u'1.4.4'),
StringStruct(u'InternalName', u'https://github.com/shootsoft/PlutoVidoeSnapshoter'),
StringStruct(u'LegalCopyright', u'Copyright (C) 2000-2018 Shoot Sun Studio All Rights Reserved'),
StringStruct(u'OriginalFilename', u'PlutoVideoSnapshoter.exe'),
StringStruct(u'ProductName', u'Pluto Video Snapshoter'),
StringStruct(u'ProductVersion', u'1.4.3')])
StringStruct(u'ProductVersion', u'1.4.4')])
]),
VarFileInfo([VarStruct(u'Translation', [1033, 1252])])
]
Expand Down
7 changes: 5 additions & 2 deletions mac_build.spec
Expand Up @@ -34,8 +34,11 @@ coll = COLLECT(exe,
app = BUNDLE(coll,
name='PlutoVideoSnapshoter.app',
icon='res/pluto.icns',
bundle_identifier=None,
bundle_identifier= 'net.shootsoft.pluto',
info_plist={
'CFBundleShortVersionString': '1.4.3'
'CFBundleName': 'PlutoVideoSnapshoter',
'CFBundleShortVersionString': '1.4.4',
'NSPrincipalClass': 'NSApplication',
'NSHighResolutionCapable': 'True'
},
)
4 changes: 2 additions & 2 deletions src/app.py
Expand Up @@ -11,12 +11,12 @@
from pluto.ui.qt.mvc.routers import Router
from pluto.ui.stitcher.controllers import ImageStitchingController
from pluto.ui.qt.qtutils import QtUtil
# import qdarkstyle
import qdarkstyle

if __name__ == '__main__':
app = QApplication(sys.argv)
# setup stylesheet
# app.setStyleSheet(qdarkstyle.load_stylesheet_pyqt5())
app.setStyleSheet(qdarkstyle.load_stylesheet_pyqt5())
app.setWindowIcon(QtGui.QIcon(QtUtil.resource_path(os.path.join('windows', 'pluto.png'))))
router = Router(app)
router.add_ctrl('player', PlayerController(router))
Expand Down
5 changes: 3 additions & 2 deletions src/pluto/common/media/snapshot.py
Expand Up @@ -3,7 +3,7 @@
import cv2
import os

from pluto.common.utils import SrtUtil
from pluto.common.utils import SrtUtil, TimeUtil


class Snapshot(object):
Expand Down Expand Up @@ -121,7 +121,8 @@ def snapshot_range(self, output_folder, start=0, end=None, callback_progress=Non
position = int((sub.start + sub.end) / 2)
print("current %s start %s end %s mid %s" % (current, sub.start, sub.end, position))
output_file = os.path.join(output_folder,
"%s_range_%s.jpg" % (os.path.basename(self.video_file), position))
"%s_auto_%s.jpg" % (os.path.basename(self.video_file),
TimeUtil.format_ms(position).replace(":", "_")))
output_result = self.snapshot(position, output_file)
success += 1 if output_result else 0
if callback_progress:
Expand Down
26 changes: 20 additions & 6 deletions src/pluto/ui/player/controllers.py
Expand Up @@ -4,7 +4,7 @@
import traceback

from PyQt5.QtCore import QUrl, QDir
from PyQt5.QtMultimedia import QMediaContent, QMediaPlayer
from PyQt5.QtMultimedia import QMediaContent, QMediaPlayer, QSound
from PyQt5.QtWidgets import QFileDialog, QMessageBox, QApplication

from pluto.common.utils import TimeUtil
Expand All @@ -21,12 +21,15 @@ def __init__(self, router):
super(PlayerController, self).__init__(router, PlayerWindow())
self.model = SnapshotModel()
self.snapshot = Snapshot()
self.snapshotSound = QSound(QtUtil.resource_path(os.path.join("windows", "player", "snapshot.wav")))
self.__bind(self.view)

def __bind(self, view):
view.openButton.clicked.connect(self.on_open)
view.playButton.clicked.connect(self.on_play)
view.snapshotButton.clicked.connect(self.on_snapshot)
view.videoBackgroundWidget.mouseReleaseEvent = self.on_video_clicked
view.videoWidget.mouseReleaseEvent = self.on_video_clicked

view.outputButton.clicked.connect(self.on_set_output)
view.subtitleSelectButton.clicked.connect(self.on_set_subtitle)
Expand Down Expand Up @@ -65,11 +68,20 @@ def on_open(self):
self.view.autoSnapshotButton.setEnabled(True)
self.set_video(file_name, self.snapshot.width, self.snapshot.height)

def on_play(self):
def on_video_clicked(self, *event):
if self.model.filename:
self.on_play()
else:
self.on_open()

def on_play(self, ):
self.view.mediaPositionSlider.setEnabled(True)
if self.model.isPlaying:
self.view.mediaPlayer.pause()
self.view.update_icon(self.view.playButton, "play")
else:
self.view.mediaPlayer.play()
self.view.update_icon(self.view.playButton, "pause")
self.model.isPlaying = not self.model.isPlaying
self.view.videoWidget.show()

Expand Down Expand Up @@ -107,14 +119,14 @@ def on_media_state_changed(self, state):
# TODO: find a method to update view instead of these tricks
self.view.videoWidget.hide()
self.model.isPlaying = False
self.view.update_control_text(self.view.playButton, "Play")
self.view.update_icon(self.view.playButton, "play")
self.view.mediaPositionSlider.hide()
self.view.mediaPositionSlider.setValue(0)
self.view.mediaPositionSlider.show()
elif state == QMediaPlayer.PausedState:
self.view.update_control_text(self.view.playButton, "Play")
self.view.update_icon(self.view.playButton, "play")
else:
self.view.update_control_text(self.view.playButton, "Pause")
self.view.update_icon(self.view.playButton, "pause")

def on_video_resize(self, event):
QtUtil.central(self.view.videoWidget, self.view.videoBackgroundWidget,
Expand Down Expand Up @@ -149,10 +161,12 @@ def on_handle_error(self, error):

def on_snapshot(self):
position = self.view.mediaPlayer.position()
output_file = os.path.join(self.model.output, self.model.file + "_%d.jpg" % position)
output_file = os.path.join(self.model.output, self.model.file + "_manual_%s.jpg" %
TimeUtil.format_ms(position).replace(":", "_"))
# print(output_file)
try:
if self.snapshot.snapshot(position, output_file):
self.snapshotSound.play()
self.router.notify('snapshot', output_file)
self.view.messageLabel.setText("Saved " + output_file)
except:
Expand Down
36 changes: 34 additions & 2 deletions src/pluto/ui/player/views.py
@@ -1,9 +1,9 @@
# -*- coding: utf-8 -*-
from PyQt5 import Qt
import os

from PyQt5.QtMultimedia import QMediaPlayer
from PyQt5.QtMultimediaWidgets import QVideoWidget
from PyQt5.QtWidgets import QLabel, QVBoxLayout, QWidget
from PyQt5.QtWidgets import QLabel

from pluto.ui.qt.mvc.views import View

Expand All @@ -19,5 +19,37 @@ def __init__(self):
self.statusbar.addWidget(self.progressLabel)
self.messageLabel = QLabel("")
self.statusbar.addWidget(self.messageLabel)
self.mediaPositionSlider.setEnabled(False)
self.mediaPositionSlider.setStyleSheet("""
QSlider::handle:horizontal {
background: qlineargradient(x1:0, y1:0, x2:1, y2:1, stop:0 #b4b4b4, stop:1 #8f8f8f);
border: 0px solid #5c5c5c;
width: 16px;
margin: -2px -2px -2px -1px;
border-radius: 1px;
}
QSlider::sub-page:horizontal{
background:#3396DA;
}
""")
self.__init_icons()
self.update_icon(self.openButton, "open")
self.update_icon(self.playButton, "play")
self.update_icon(self.snapshotButton, "snapshot")
self.update_icon(self.startButton, "start")
self.update_icon(self.endButton, "end")
self.update_icon(self.autoSnapshotButton, "auto")
self.update_icon(self.imageStitchingButton, "stitching")

def __init_icons(self):
player = os.path.join("windows", "player")
self.add_icon("open.svg", player)
self.add_icon("play.svg", player)
self.add_icon("pause.svg", player)
self.add_icon("snapshot.svg", player)
self.add_icon("start.svg", player)
self.add_icon("end.svg", player)
self.add_icon("auto.svg", player)
self.add_icon("stitching.svg", player)

0 comments on commit 20eb4bc

Please sign in to comment.