4 Commits

Author SHA1 Message Date
G.K.MacGregor
06970fd448 Tag version 0.3-alpha 2021-06-13 12:58:26 +01:00
G.K.MacGregor
a3d4783796 Make smooth pixmap scaling optional 2021-06-07 21:58:14 +01:00
G.K.MacGregor
c8e57150eb Implement exporting PNG images 2021-06-03 22:26:54 +01:00
G.K.MacGregor
23c2623bcf Clarify that we export only the current subpage 2021-05-27 21:57:02 +01:00
7 changed files with 122 additions and 6 deletions

View File

@@ -5,6 +5,8 @@ Features
- Load and save teletext pages in .tti format. - Load and save teletext pages in .tti format.
- Rendering of teletext pages in Levels 1, 1.5, 2.5 and 3.5 - Rendering of teletext pages in Levels 1, 1.5, 2.5 and 3.5
- Rendering of Local Objects and side panels. - Rendering of Local Objects and side panels.
- Export PNG images of teletext pages.
- Undo and redo of editing actions.
- Interactive X/26 Local Enhancement Data triplet editor. - Interactive X/26 Local Enhancement Data triplet editor.
- Editing of X/27/4 and X/27/5 compositional links to enhancement data pages. - Editing of X/27/4 and X/27/5 compositional links to enhancement data pages.
- Palette editor. - Palette editor.

View File

@@ -30,7 +30,7 @@ int main(int argc, char *argv[])
QApplication::setApplicationDisplayName(QApplication::applicationName()); QApplication::setApplicationDisplayName(QApplication::applicationName());
QApplication::setOrganizationName("gkmac.co.uk"); QApplication::setOrganizationName("gkmac.co.uk");
QApplication::setOrganizationDomain("gkmac.co.uk"); QApplication::setOrganizationDomain("gkmac.co.uk");
QApplication::setApplicationVersion("0.2-alpha"); QApplication::setApplicationVersion("0.3-alpha");
QCommandLineParser parser; QCommandLineParser parser;
parser.setApplicationDescription(QApplication::applicationName()); parser.setApplicationDescription(QApplication::applicationName());
parser.addHelpOption(); parser.addHelpOption();

View File

@@ -140,6 +140,16 @@ void TeletextWidget::timerEvent(QTimerEvent *event)
QWidget::timerEvent(event); QWidget::timerEvent(event);
} }
void TeletextWidget::pauseFlash(bool pauseNow)
{
if (pauseNow && m_flashTiming != 0) {
m_flashTimer.stop();
m_flashPhase = 0;
update();
} else if (m_flashTiming != 0)
m_flashTimer.start((m_flashTiming == 1) ? 500 : 167, this);
}
void TeletextWidget::setInsertMode(bool insertMode) void TeletextWidget::setInsertMode(bool insertMode)
{ {
m_insertMode = insertMode; m_insertMode = insertMode;
@@ -654,6 +664,24 @@ void LevelOneScene::toggleGrid(bool gridOn)
m_sidePanelGridItemGroup[i]->setVisible(gridOn); m_sidePanelGridItemGroup[i]->setVisible(gridOn);
} }
void LevelOneScene::hideGUIElements(bool hidden)
{
if (hidden) {
m_mainGridItemGroup->setVisible(false);
m_cursorRectItem->setVisible(false);
m_selectionRectItem->setVisible(false);
for (int i=0; i<32; i++)
if (m_sidePanelGridNeeded[i])
m_sidePanelGridItemGroup[i]->setVisible(false);
} else {
if (static_cast<TeletextWidget *>(m_levelOneProxyWidget->widget())->document()->selectionActive())
m_selectionRectItem->setVisible(true);
m_cursorRectItem->setVisible(true);
toggleGrid(m_grid);
}
}
bool LevelOneScene::eventFilter(QObject *object, QEvent *event) bool LevelOneScene::eventFilter(QObject *object, QEvent *event)
{ {
Q_UNUSED(object); Q_UNUSED(object);

View File

@@ -64,6 +64,7 @@ public slots:
void toggleReveal(bool); void toggleReveal(bool);
void toggleMix(bool); void toggleMix(bool);
void updateFlashTimer(int); void updateFlashTimer(int);
void pauseFlash(bool);
void refreshRow(int); void refreshRow(int);
void setControlBit(int, bool); void setControlBit(int, bool);
@@ -119,6 +120,7 @@ public slots:
void updateCursor(); void updateCursor();
void updateSelection(); void updateSelection();
void toggleGrid(bool); void toggleGrid(bool);
void hideGUIElements(bool);
void setFullScreenColour(const QColor &); void setFullScreenColour(const QColor &);
void setFullRowColour(int, const QColor &); void setFullRowColour(int, const QColor &);

View File

@@ -20,9 +20,11 @@
#include <QApplication> #include <QApplication>
#include <QDesktopServices> #include <QDesktopServices>
#include <QFileDialog> #include <QFileDialog>
#include <QImage>
#include <QList> #include <QList>
#include <QMenuBar> #include <QMenuBar>
#include <QMessageBox> #include <QMessageBox>
#include <QPainter>
#include <QPushButton> #include <QPushButton>
#include <QRadioButton> #include <QRadioButton>
#include <QSaveFile> #include <QSaveFile>
@@ -120,6 +122,56 @@ bool MainWindow::saveAs()
return saveFile(fileName); return saveFile(fileName);
} }
void MainWindow::exportPNG()
{
QString exportFileName = QFileDialog::getSaveFileName(this, tr("Export PNG"), QString(), "PNG image (*.png)");
if (exportFileName.isEmpty())
return;
// Prepare widget image for extraction
m_textWidget->pauseFlash(true);
m_textScene->hideGUIElements(true);
bool reshowCodes = m_textWidget->pageRender()->showCodes();
if (reshowCodes)
m_textWidget->pageRender()->setShowCodes(false);
// Disable exporting in Mix mode as it corrupts the background
bool reMix = m_textWidget->pageRender()->mix();
if (reMix)
m_textWidget->pageRender()->setMix(false);
// Extract the image from the scene
QImage interImage = QImage(m_textScene->sceneRect().size().toSize(), QImage::Format_RGB32);
// This ought to make the background transparent in Mix mode, but it doesn't
// if (m_textWidget->pageRender()->mix())
// interImage.fill(QColor(0, 0, 0, 0));
QPainter interPainter(&interImage);
m_textScene->render(&interPainter);
// Now we've extracted the image we can put the GUI things back
m_textScene->hideGUIElements(false);
if (reshowCodes)
m_textWidget->pageRender()->setShowCodes(true);
if (reMix)
m_textWidget->pageRender()->setMix(true);
m_textWidget->pauseFlash(false);
// Now scale the extracted image to the selected aspect ratio
// We do this in two steps so that anti-aliasing only occurs on vertical lines
// Double the vertical height first
const QImage doubleHeightImage = interImage.scaled(interImage.width(), interImage.height()*2, Qt::IgnoreAspectRatio, Qt::FastTransformation);
// If aspect ratio is Pixel 1:2 we're already at the correct scale
if (m_viewAspectRatio != 3) {
// Scale it horizontally to the selected aspect ratio
const QImage scaledImage = doubleHeightImage.scaled((int)((float)doubleHeightImage.width() * aspectRatioHorizontalScaling[m_viewAspectRatio] * 2), doubleHeightImage.height(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
if (!scaledImage.save(exportFileName, "PNG"))
QMessageBox::warning(this, tr("QTeletextMaker"), tr("Cannot export file %1.").arg(QDir::toNativeSeparators(exportFileName)));
} else if (!doubleHeightImage.save(exportFileName, "PNG"))
QMessageBox::warning(this, tr("QTeletextMaker"), tr("Cannot export file %1.").arg(QDir::toNativeSeparators(exportFileName)));
}
void MainWindow::exportZXNet() void MainWindow::exportZXNet()
{ {
QDesktopServices::openUrl(QUrl("http://zxnet.co.uk/teletext/editor/" + exportHashStringPage(m_textWidget->document()->currentSubPage()) + exportHashStringPackets(m_textWidget->document()->currentSubPage()))); QDesktopServices::openUrl(QUrl("http://zxnet.co.uk/teletext/editor/" + exportHashStringPage(m_textWidget->document()->currentSubPage()) + exportHashStringPackets(m_textWidget->document()->currentSubPage())));
@@ -166,7 +218,8 @@ void MainWindow::init()
m_textView = new QGraphicsView(this); m_textView = new QGraphicsView(this);
m_textView->setScene(m_textScene); m_textView->setScene(m_textScene);
m_textView->setRenderHints(QPainter::SmoothPixmapTransform); if (m_viewSmoothTransform)
m_textView->setRenderHints(QPainter::SmoothPixmapTransform);
m_textView->setBackgroundBrush(QBrush(QColor(32, 48, 96))); m_textView->setBackgroundBrush(QBrush(QColor(32, 48, 96)));
setSceneDimensions(); setSceneDimensions();
setCentralWidget(m_textView); setCentralWidget(m_textView);
@@ -257,14 +310,18 @@ void MainWindow::createActions()
setRecentFilesVisible(MainWindow::hasRecentFiles()); setRecentFilesVisible(MainWindow::hasRecentFiles());
QMenu *exportHashStringSubMenu = fileMenu->addMenu(tr("Export to online editor")); QAction *exportPNGAct = fileMenu->addAction(tr("Export subpage as PNG..."));
exportPNGAct->setStatusTip("Export a PNG image of this subpage");
connect(exportPNGAct, &QAction::triggered, this, &MainWindow::exportPNG);
QMenu *exportHashStringSubMenu = fileMenu->addMenu(tr("Export subpage to online editor"));
QAction *exportZXNetAct = exportHashStringSubMenu->addAction(tr("Open in zxnet.co.uk")); QAction *exportZXNetAct = exportHashStringSubMenu->addAction(tr("Open in zxnet.co.uk"));
exportZXNetAct->setStatusTip("Export and open page in zxnet.co.uk online editor"); exportZXNetAct->setStatusTip("Export and open this subpage in the zxnet.co.uk online editor");
connect(exportZXNetAct, &QAction::triggered, this, &MainWindow::exportZXNet); connect(exportZXNetAct, &QAction::triggered, this, &MainWindow::exportZXNet);
QAction *exportEditTFAct = exportHashStringSubMenu->addAction(tr("Open in edit.tf")); QAction *exportEditTFAct = exportHashStringSubMenu->addAction(tr("Open in edit.tf"));
exportEditTFAct->setStatusTip("Export and open page in edit.tf online editor"); exportEditTFAct->setStatusTip("Export and open this subpage in the edit.tf online editor");
connect(exportEditTFAct, &QAction::triggered, this, &MainWindow::exportEditTF); connect(exportEditTFAct, &QAction::triggered, this, &MainWindow::exportEditTF);
fileMenu->addSeparator(); fileMenu->addSeparator();
@@ -418,6 +475,13 @@ void MainWindow::createActions()
borderGroup->addAction(m_borderActs[i]); borderGroup->addAction(m_borderActs[i]);
} }
viewMenu->addSeparator();
m_smoothTransformAction = viewMenu->addAction(tr("Smooth font scaling"));
m_smoothTransformAction->setCheckable(true);
m_smoothTransformAction->setStatusTip(tr("Toggle smooth font scaling"));
connect(m_smoothTransformAction, &QAction::toggled, this, &MainWindow::setSmoothTransform);
QAction *zoomInAct = viewMenu->addAction(tr("Zoom In")); QAction *zoomInAct = viewMenu->addAction(tr("Zoom In"));
zoomInAct->setShortcuts(QKeySequence::ZoomIn); zoomInAct->setShortcuts(QKeySequence::ZoomIn);
zoomInAct->setStatusTip(tr("Zoom in")); zoomInAct->setStatusTip(tr("Zoom in"));
@@ -555,7 +619,6 @@ void MainWindow::createActions()
void MainWindow::setSceneDimensions() void MainWindow::setSceneDimensions()
{ {
const float aspectRatioHorizontalScaling[4] = { 0.6, 0.6, 0.8, 0.5 };
const int topBottomBorders[3] = { 0, 10, 19 }; const int topBottomBorders[3] = { 0, 10, 19 };
const int pillarBoxSizes[3] = { 672, 720, 854 }; const int pillarBoxSizes[3] = { 672, 720, 854 };
const int leftRightBorders[3] = { 0, 24, 77 }; const int leftRightBorders[3] = { 0, 24, 77 };
@@ -612,6 +675,15 @@ void MainWindow::setAspectRatio(int newViewAspectRatio)
setSceneDimensions(); setSceneDimensions();
} }
void MainWindow::setSmoothTransform(bool smoothTransform)
{
m_viewSmoothTransform = smoothTransform;
if (smoothTransform)
m_textView->setRenderHints(QPainter::SmoothPixmapTransform);
else
m_textView->setRenderHints({ });
}
void MainWindow::zoomIn() void MainWindow::zoomIn()
{ {
if (m_viewZoom < 4) if (m_viewZoom < 4)
@@ -705,6 +777,10 @@ void MainWindow::readSettings()
m_viewAspectRatio = settings.value("aspectratio", 0).toInt(); m_viewAspectRatio = settings.value("aspectratio", 0).toInt();
m_viewAspectRatio = (m_viewAspectRatio < 0 || m_viewAspectRatio > 2) ? 0 : m_viewAspectRatio; m_viewAspectRatio = (m_viewAspectRatio < 0 || m_viewAspectRatio > 2) ? 0 : m_viewAspectRatio;
m_aspectRatioActs[m_viewAspectRatio]->setChecked(true); m_aspectRatioActs[m_viewAspectRatio]->setChecked(true);
m_viewSmoothTransform = settings.value("smoothTransform", 0).toBool();
m_smoothTransformAction->blockSignals(true);
m_smoothTransformAction->setChecked(m_viewSmoothTransform);
m_smoothTransformAction->blockSignals(false);
m_viewZoom = settings.value("zoom", 2).toInt(); m_viewZoom = settings.value("zoom", 2).toInt();
m_viewZoom = (m_viewZoom < 0 || m_viewZoom > 4) ? 2 : m_viewZoom; m_viewZoom = (m_viewZoom < 0 || m_viewZoom > 4) ? 2 : m_viewZoom;
@@ -743,6 +819,7 @@ void MainWindow::writeSettings()
settings.setValue("windowState", saveState()); settings.setValue("windowState", saveState());
settings.setValue("border", m_viewBorder); settings.setValue("border", m_viewBorder);
settings.setValue("aspectratio", m_viewAspectRatio); settings.setValue("aspectratio", m_viewAspectRatio);
settings.setValue("smoothTransform", m_viewSmoothTransform);
settings.setValue("zoom", m_viewZoom); settings.setValue("zoom", m_viewZoom);
} }

View File

@@ -58,6 +58,7 @@ private slots:
void open(); void open();
bool save(); bool save();
bool saveAs(); bool saveAs();
void exportPNG();
void exportZXNet(); void exportZXNet();
void exportEditTF(); void exportEditTF();
void updateRecentFileActions(); void updateRecentFileActions();
@@ -74,6 +75,7 @@ private slots:
void setSceneDimensions(); void setSceneDimensions();
void setBorder(int); void setBorder(int);
void setAspectRatio(int); void setAspectRatio(int);
void setSmoothTransform(bool);
void zoomIn(); void zoomIn();
void zoomOut(); void zoomOut();
void zoomReset(); void zoomReset();
@@ -82,6 +84,7 @@ private slots:
private: private:
enum { m_MaxRecentFiles = 10 }; enum { m_MaxRecentFiles = 10 };
const float aspectRatioHorizontalScaling[4] = { 0.6, 0.6, 0.8, 0.5 };
void init(); void init();
void createActions(); void createActions();
@@ -104,6 +107,7 @@ private:
QGraphicsView *m_textView; QGraphicsView *m_textView;
int m_viewBorder, m_viewAspectRatio, m_viewZoom; int m_viewBorder, m_viewAspectRatio, m_viewZoom;
bool m_viewSmoothTransform;
PageOptionsDockWidget *m_pageOptionsDockWidget; PageOptionsDockWidget *m_pageOptionsDockWidget;
PageEnhancementsDockWidget *m_pageEnhancementsDockWidget; PageEnhancementsDockWidget *m_pageEnhancementsDockWidget;
X26DockWidget *m_x26DockWidget; X26DockWidget *m_x26DockWidget;
@@ -115,6 +119,7 @@ private:
QAction *m_deleteSubPageAction; QAction *m_deleteSubPageAction;
QAction *m_borderActs[3]; QAction *m_borderActs[3];
QAction *m_aspectRatioActs[4]; QAction *m_aspectRatioActs[4];
QAction *m_smoothTransformAction;
QLabel *m_subPageLabel, *m_cursorPositionLabel; QLabel *m_subPageLabel, *m_cursorPositionLabel;
QToolButton *m_previousSubPageButton, *m_nextSubPageButton; QToolButton *m_previousSubPageButton, *m_nextSubPageButton;

View File

@@ -189,6 +189,8 @@ public:
void decodePage(); void decodePage();
void renderPage(); void renderPage();
void renderPage(int r); void renderPage(int r);
bool mix() const { return m_mix; };
bool showCodes() const { return m_showCodes; };
void setTeletextPage(LevelOnePage *); void setTeletextPage(LevelOnePage *);
void updateSidePanels(); void updateSidePanels();
void buildEnhanceMap(TextLayer *, int=0); void buildEnhanceMap(TextLayer *, int=0);