Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
88b5922
Rename qt to viewer, add third-party libraries and Remove support for…
CodeJhF Mar 17, 2025
e305f2b
Update the qt path corresponding to vs2019
CodeJhF Mar 17, 2025
adc2a45
Update the README.md of viewer
CodeJhF Mar 17, 2025
dfec660
Migrate qt build job to macOS environment
CodeJhF Mar 17, 2025
a0e9ebd
Fixed an issue that caused the qt job on the pipeline to run failed
CodeJhF Mar 17, 2025
7037bdf
Set the minimum Qt version required by libpag to 6.2.0
CodeJhF Mar 17, 2025
548e005
Set both the minimum Qt version required by libpag and the Qt version…
CodeJhF Mar 18, 2025
8c22e82
Implement the main window and basic playback controls of viewer
CodeJhF Mar 20, 2025
912bd40
Modify the size adjustment control of the viewer on Windows
CodeJhF Mar 20, 2025
7956726
Using qmlformat to do code-format on QML files
CodeJhF Mar 20, 2025
332275b
Upload the third-party library winspark to the 'vendor' directory
CodeJhF Mar 20, 2025
7484b72
Merge remote-tracking branch 'upstream/main' into build_viewer
CodeJhF Mar 20, 2025
1f1360d
Remove the build script of winsparkle
CodeJhF Mar 21, 2025
26620d6
Replace source code compilation with dynamic library integration for …
CodeJhF Mar 21, 2025
e7c8a96
disable rtti for viewer, modify some programming details
CodeJhF Mar 21, 2025
94ff965
Merge branch 'Tencent:main' into build_viewer
CodeJhF Mar 23, 2025
19a4aaf
Modify the method getPreferredSize() for viewer
CodeJhF Mar 24, 2025
2ee835b
Modify the loading method of the viewer's titleBar
CodeJhF Mar 24, 2025
e8a0daf
Fix the issue with the viewer's Windows resize handle
CodeJhF Mar 24, 2025
9fdf756
Merge branch 'build_viewer' of https://github.com/CodeJhF/libpag into…
CodeJhF Mar 24, 2025
ea34b5d
Fix a logic error in obtaining viewer's preferred size
CodeJhF Mar 25, 2025
5efe2ee
Merge branch 'Tencent:main' into build_viewer
CodeJhF Mar 25, 2025
d3c376d
Add menu bar for windows viewer
CodeJhF Mar 25, 2025
022c412
Add menu bar for macos viewer
CodeJhF Mar 25, 2025
23a2207
Implement the basic functions of the menu bar for viewer
CodeJhF Mar 26, 2025
8bb7f56
Fix some issue about the menu of viewer
CodeJhF Mar 26, 2025
8d32286
Codeformat the qml files of the viewer
CodeJhF Mar 26, 2025
959dcc6
Fix some issues found in code review
CodeJhF Mar 28, 2025
26e95e5
Fix some issues found in code review
CodeJhF Mar 31, 2025
ac2e73f
Add PAG export support in viewer: PNG sequence, single frame PNG and …
CodeJhF Apr 1, 2025
7545b46
Merge branch 'build_viewer' of https://github.com/CodeJhF/libpag into…
CodeJhF Apr 1, 2025
9000be2
Fixed viewer export function issues on Windows
CodeJhF Apr 1, 2025
b9a6ca5
Merge upstream to build_viewer
CodeJhF Apr 1, 2025
3afabc5
Release context when task is completed
CodeJhF Apr 1, 2025
363e548
Add license for viewer source files
CodeJhF Apr 1, 2025
b913045
Remove redundant comments in viewer
CodeJhF Apr 1, 2025
41feb4c
Use smart pointers instead of raw pointers in viewer
CodeJhF Apr 3, 2025
42e68ea
Codeformat the code of viewer
CodeJhF Apr 3, 2025
2732f36
Codeformat the code of viewer
CodeJhF Apr 3, 2025
907b132
Fix the compilation errors of viewer
CodeJhF Apr 3, 2025
c313ad5
Fix some issues found in code review
CodeJhF Apr 8, 2025
64ba351
Fix some issues found in code review
CodeJhF Apr 8, 2025
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
4 changes: 4 additions & 0 deletions viewer/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -105,9 +105,13 @@ add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../ ./libpag)
add_executable(PAGViewer ${RC_FILES} ${PAG_VIEWER_SOURCE_FILES} ${QT_RESOURCES})
if (APPLE)
list(APPEND PAG_VIEWER_INCLUDES ../third_party/out/rttr/mac/include)
list(APPEND PAG_VIEWER_INCLUDES ../third_party/tgfx/third_party/out/zlib/mac/include)
list(APPEND PAG_VIEWER_INCLUDES ../third_party/tgfx/third_party/out/libpng/mac/include)
list(APPEND VIEWER_VENDOR_LIBRARIES ${CMAKE_SOURCE_DIR}/../vendor/sparkle/mac/Sparkle.framework)
elseif (WIN32)
list(APPEND PAG_VIEWER_INCLUDES ../third_party/out/rttr/win/include)
list(APPEND PAG_VIEWER_INCLUDES ../third_party/tgfx/third_party/out/zlib/win/include)
list(APPEND PAG_VIEWER_INCLUDES ../third_party/tgfx/third_party/out/libpng/win/include)
list(APPEND PAG_VIEWER_INCLUDES ../vendor/winsparkle/include)
list(APPEND VIEWER_VENDOR_LIBRARIES ${CMAKE_SOURCE_DIR}/../vendor/winsparkle/win/x64/${CMAKE_BUILD_TYPE}/WinSparkle.lib)
endif ()
Expand Down
215 changes: 200 additions & 15 deletions viewer/qml/Main.qml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ import PAG
import QtCore
import QtQuick
import QtQuick.Dialogs
import QtQuick.Controls
import Qt.labs.settings
import Qt.labs.platform as Platform
import "components"
import "utils"

Expand Down Expand Up @@ -127,18 +129,6 @@ PAGWindow {
}
}

FileDialog {
id: openPAGFileDialog
visible: false
title: qsTr("Open PAG File")
fileMode: FileDialog.OpenFile
nameFilters: ["PAG files(*.pag)"]
onAccepted: {
let filePath = openPAGFileDialog.selectedFile;
mainForm.pagView.setFile(filePath);
}
}

SettingsWindow {
id: settingsWindow
visible: false
Expand All @@ -163,6 +153,120 @@ PAGWindow {
aboutMessage: "<b>PAGViewer</b> " + Qt.application.version + "<br><br>Copyright © 2017-present Tencent. All rights reserved."
}

PAGTaskFactory {
id: taskFactory
objectName: "taskFactory"
}

FileDialog {
id: openFileDialog

property var currentAcceptHandler: null

visible: false
title: ""
fileMode: FileDialog.OpenFile
nameFilters: []
}

Platform.FolderDialog {
id: openFolderDialog

property var currentAcceptHandler: null

visible: false
title: qsTr("Select Save Path")
}

PAGWindow {
id: progressWindow

property var task
property alias progressBar: progressBar

width: 300
height: 64
minimumWidth: width
maximumWidth: width
minimumHeight: height
maximumHeight: height
hasMenu: false
canResize: false
titleBarHeight: windowTitleBarHeight
visible: false

PAGRectangle {
id: rectangle

color: "#2D2D37"
anchors.fill: parent
leftTopRadius: false
rightTopRadius: false
radius: 5

ProgressBar {
id: progressBar
width: parent.width - 24
height: 30
anchors.verticalCenter: parent.verticalCenter
anchors.horizontalCenter: parent.horizontalCenter
value: 0

contentItem: Item {
Rectangle {
width: parent.width
height: 15
radius: 5
color: "#DDDDDD"
anchors.verticalCenter: parent.verticalCenter
}

Rectangle {
width: progressBar.visualPosition * parent.width
height: 15
radius: 5
color: "#448EF9"
anchors.verticalCenter: parent.verticalCenter
}

Text {
anchors.centerIn: parent
text: Math.round(progressBar.value * 100) + "%"
color: progressBar.value > 0.5 ? "white" : "black"
font.pixelSize: 12
}
}
}
}

onClosing: {
if (task) {
task.stop();
}
}
}

Connections {
id: taskConnections
onProgressChanged: function (progress) {
progressWindow.progressBar.value = progress;
}

onVisibleChanged: function (visible) {
progressWindow.visible = visible;
}

onTaskFinished: function (filePath, result) {
if (result !== 0) {
let errStr = qsTr("Export failed, error code: ");
alert(errStr + result);
}
progressWindow.task = null;
progressWindow.progressBar.value = 0;
progressWindow.visible = false;
}
}

Component.onCompleted: {
viewWindow.title = "PAGViewer";

Expand Down Expand Up @@ -217,11 +321,19 @@ PAGWindow {
case "open-pag-file":
if (mainForm.hasPAGFile) {
let filePath = mainForm.pagView.filePath;
openPAGFileDialog.currentFolder = Utils.getFileDir(filePath);
openFileDialog.currentFolder = Utils.getFileDir(filePath);
} else {
openPAGFileDialog.currentFolder = StandardPaths.writableLocation(StandardPaths.DocumentsLocation);
openFileDialog.currentFolder = StandardPaths.writableLocation(StandardPaths.DocumentsLocation);
}
openPAGFileDialog.open();
openFileDialog.accepted.disconnect();
openFileDialog.fileMode = FileDialog.OpenFile;
openFileDialog.title = qsTr("Open PAG File");
openFileDialog.nameFilters = ["PAG files(*.pag)"];
openFileDialog.accepted.connect(function () {
let filePath = openFileDialog.selectedFile;
mainForm.pagView.setFile(filePath);
});
openFileDialog.open();
break;
case "close-window":
viewWindow.close();
Expand Down Expand Up @@ -273,6 +385,79 @@ PAGWindow {
case "fullscreen-window":
viewWindow.visibility = viewWindow.visibility !== Window.Maximized ? Window.Maximized : Window.AutomaticVisibility;
break;
case "export-frame-as-png":
if (openFileDialog.currentAcceptHandler) {
openFileDialog.accepted.disconnect(openFileDialog.currentAcceptHandler);
}
openFileDialog.fileMode = FileDialog.SaveFile;
openFileDialog.title = qsTr("Select save path");
openFileDialog.nameFilters = ["PNG files(*.png)"];
openFileDialog.defaultSuffix = "png";
openFileDialog.currentFolder = Utils.getFileDir(mainForm.pagView.filePath);
openFileDialog.currentAcceptHandler = function () {
let filePath = openFileDialog.selectedFile;
let task = taskFactory.createTask(PAGTaskFactory.PAGTaskType_ExportPNG, filePath, {
"exportFrame": mainForm.pagView.currentFrame
});
if (task) {
taskConnections.target = task;
progressWindow.title = qsTr("Exporting");
progressWindow.task = task;
progressWindow.visible = true;
progressWindow.raise();
task.start();
}
};
openFileDialog.accepted.connect(openFileDialog.currentAcceptHandler);
openFileDialog.open();
break;
case "export-as-png-sequence":
if (openFolderDialog.currentAcceptHandler) {
openFolderDialog.accepted.disconnect(openFolderDialog.currentAcceptHandler);
}
openFolderDialog.title = qsTr("Select save path");
openFolderDialog.currentFolder = Utils.getFileDir(mainForm.pagView.filePath);
openFolderDialog.currentAcceptHandler = function () {
let filePath = openFolderDialog.folder;
let task = taskFactory.createTask(PAGTaskFactory.PAGTaskType_ExportPNG, filePath, {});
if (task) {
taskConnections.target = task;
progressWindow.title = qsTr("Exporting");
progressWindow.progressBar.value = 0;
progressWindow.task = task;
progressWindow.visible = true;
progressWindow.raise();
task.start();
}
};
openFolderDialog.accepted.connect(openFolderDialog.currentAcceptHandler);
openFolderDialog.open();
break;
case "export-as-apng":
if (openFileDialog.currentAcceptHandler) {
openFileDialog.accepted.disconnect(openFileDialog.currentAcceptHandler);
}
openFileDialog.fileMode = FileDialog.SaveFile;
openFileDialog.title = qsTr("Select save path");
openFileDialog.nameFilters = ["APNG files(*.png)"];
openFileDialog.defaultSuffix = "png";
openFileDialog.currentFolder = Utils.getFileDir(mainForm.pagView.filePath);
openFileDialog.currentAcceptHandler = function () {
let filePath = openFileDialog.selectedFile;
let task = taskFactory.createTask(PAGTaskFactory.PAGTaskType_ExportAPNG, filePath, {});
if (task) {
taskConnections.target = task;
progressWindow.title = qsTr("Exporting");
progressWindow.progressBar.value = 0;
progressWindow.task = task;
progressWindow.visible = true;
progressWindow.raise();
task.start();
}
};
openFileDialog.accepted.connect(openFileDialog.currentAcceptHandler);
openFileDialog.open();
break;
default:
console.log(`Undefined command: [${command}]`);
break;
Expand Down
51 changes: 51 additions & 0 deletions viewer/qml/Menu.qml
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,32 @@ Item {
root.command("open-preferences");
}
}
PAGMenu {
menuWidth: windowsMenuBar.menuWidth
title: qsTr("Export")
Action {
text: qsTr("Export as PNG Sequence Frames")
enabled: root.hasPAGFile
onTriggered: {
root.command('export-as-png-sequence');
}
}
Action {
text: qsTr("Export as APNG")
enabled: root.hasPAGFile
onTriggered: {
root.command('export-as-apng');
}
}
Action {
text: qsTr("Export current frame as PNG")
enabled: root.hasPAGFile
shortcut: "Ctrl+P"
onTriggered: {
root.command('export-frame-as-png');
}
}
}
}

PAGMenu {
Expand Down Expand Up @@ -196,6 +222,31 @@ Item {
root.command("open-pag-file");
}
}
Platform.Menu {
title: qsTr("Export")
Platform.MenuItem {
text: qsTr("Export as PNG Sequence Frames")
enabled: root.hasPAGFile
onTriggered: {
root.command('export-as-png-sequence');
}
}
Platform.MenuItem {
text: qsTr("Export as APNG")
enabled: root.hasPAGFile
onTriggered: {
root.command('export-as-apng');
}
}
Platform.MenuItem {
text: qsTr("Export current frame as PNG")
enabled: root.hasPAGFile
shortcut: "Meta+P"
onTriggered: {
root.command('export-frame-as-png');
}
}
}
}
Platform.Menu {
title: qsTr("Play")
Expand Down
11 changes: 10 additions & 1 deletion viewer/qml/utils/Utils.qml
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,13 @@ QtObject {
let fileName = urlObject.pathname.split('/').pop();
return fileName;
}
}

function replaceLastIndexOf(str, oldPara, newPara) {
let lastIndex = str.lastIndexOf(oldPara);
if (lastIndex !== -1) {
return str;
}

return str.substring(0, lastIndex) + newPara + str.substring(lastIndex + oldPara.length);
}
}
2 changes: 2 additions & 0 deletions viewer/src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include <QSGRendererInterface>
#include "PAGViewer.h"
#include "rendering/PAGView.h"
#include "task/PAGTaskFactory.h"

int main(int argc, char* argv[]) {
bool cpuMode = false;
Expand Down Expand Up @@ -60,6 +61,7 @@ int main(int argc, char* argv[]) {
pag::PAGViewer app(argc, argv);
QApplication::setWindowIcon(QIcon(":/images/window-icon.png"));
qmlRegisterType<pag::PAGView>("PAG", 1, 0, "PAGView");
qmlRegisterType<pag::PAGTaskFactory>("PAG", 1, 0, "PAGTaskFactory");
app.openFile(filePath.data());

return QApplication::exec();
Expand Down
27 changes: 27 additions & 0 deletions viewer/src/platform/mac/PAGUtilsImpl.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/////////////////////////////////////////////////////////////////////////////////////////////////
//
// Tencent is pleased to support the open source community by making libpag available.
//
// Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
// except in compliance with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// unless required by applicable law or agreed to in writing, software distributed under the
// license is distributed on an "as is" basis, without warranties or conditions of any kind,
// either express or implied. see the license for the specific language governing permissions
// and limitations under the license.
//
/////////////////////////////////////////////////////////////////////////////////////////////////

#pragma once

#include <QFileInfo>

namespace pag::Utils {

auto openFileInFinder(QFileInfo& fileInfo) -> void;

} // namespace pag::Utils
Loading