Skip to content

Commit

Permalink
version 1.0.0-beta.1
Browse files Browse the repository at this point in the history
  • Loading branch information
archibalduk committed Feb 22, 2021
1 parent eb682bc commit cbb266c
Show file tree
Hide file tree
Showing 17 changed files with 697 additions and 0 deletions.
73 changes: 73 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# This file is used to ignore files which are generated
# ----------------------------------------------------------------------------

*~
*.autosave
*.a
*.core
*.moc
*.o
*.obj
*.orig
*.rej
*.so
*.so.*
*_pch.h.cpp
*_resource.rc
*.qm
.#*
*.*#
core
!core/
tags
.DS_Store
.directory
*.debug
Makefile*
*.prl
*.app
moc_*.cpp
ui_*.h
qrc_*.cpp
Thumbs.db
*.res
*.rc
/.qmake.cache
/.qmake.stash

# qtcreator generated files
*.pro.user*

# xemacs temporary files
*.flc

# Vim temporary files
.*.swp

# Visual Studio generated files
*.ib_pdb_index
*.idb
*.ilk
*.pdb
*.sln
*.suo
*.vcproj
*vcproj.*.*.user
*.ncb
*.sdf
*.opensdf
*.vcxproj
*vcxproj.*

# MinGW generated files
*.Debug
*.Release

# Python byte code
*.pyc

# Binaries
# --------
*.dll
*.exe

44 changes: 44 additions & 0 deletions EHM_Jersey_Generator.pro
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
QT += core gui

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

# C++17 support
CONFIG += c++17

# Disable QDebug for release builds
CONFIG(release, debug|release):DEFINES += QT_NO_DEBUG_OUTPUT

# The following define makes your compiler emit warnings if you use
# any Qt feature that has been marked deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS

# You can make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0

# Enable as many compiler warnings as possible
CONFIG += warn_on

SOURCES += \
jersey.cpp \
main.cpp \
mainwindow.cpp \
ui/colour_widget.cpp \
ui/preview_widget.cpp

HEADERS += \
dimensions.h \
jersey.h \
mainwindow.h \
ui/colour_widget.h \
ui/preview_widget.h

# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target

RESOURCES += \
EHM_Jersey_Generator.qrc
10 changes: 10 additions & 0 deletions EHM_Jersey_Generator.qrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<RCC>
<qresource prefix="/images">
<file alias="default_background.png">images/default_background.png</file>
<file alias="default_foreground.png">images/default_foreground.png</file>
<file alias="default_trim.png">images/default_trim.png</file>
</qresource>
<qresource prefix="/fonts">
<file alias="sports_jersey.ttf">fonts/sportsjersey.ttf</file>
</qresource>
</RCC>
37 changes: 37 additions & 0 deletions dimensions.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#ifndef DIMENSIONS_H
#define DIMENSIONS_H

// --- Dimensions of UI elements --- //
namespace Dimensions {
enum ENUM_JERSEY_DIMENSIONS {
// Font
FontLetterSpacing = 1,
// Image
JerseyImageWidth = 184,
JerseyImageHeight = 200,
JerseyImageVerticalPadding = 10,
// Pen
PenThickness = 1,
// Text
JerseyNameFontSize = 18,
JerseyNameVerticalPosition = 40,
JerseyNumberFontSize = 80,
JerseyNumberVerticalPosition = 70,
// Upscaled jersey name text
JerseyNameUpscaleMultiplier = 5,
JerseyNameUpscaledFontSize = JerseyNameFontSize * JerseyNameUpscaleMultiplier,
JerseyNameUpscaledWidth = JerseyImageWidth * JerseyNameUpscaleMultiplier,
JerseyNameUpscaledHeight = JerseyNameUpscaledFontSize,
};

enum ENUM_USER_INTERFACE_DIMENSIONS {
// Preview label
PreviewWidth = 200,
PreviewHeight = JerseyImageHeight,
// Application window
WindowWidth = PreviewWidth * 2,
WindowHeigth = PreviewHeight
};
} // namespace Dimensions

#endif // DIMENSIONS_H
Binary file added fonts/sportsjersey.ttf
Binary file not shown.
Binary file added images/default_background.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/default_foreground.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/default_trim.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
179 changes: 179 additions & 0 deletions jersey.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
#include "jersey.h"

// Application headers
#include "dimensions.h"

// Qt headers
#include <QDebug>
#include <QFontDatabase>
#include <QImage>
#include <QPainter>
#include <QPen>

// --- Static members --- //
bool Jersey::use_uppercase_text_ = true;

// --- Constructor --- //
Jersey::Jersey(const QString &surname, const qint32 jersey_number)
: background_colour_(defaultBackgroundColour()), foreground_colour_(defaultForegroundColour()),
trim_colour_((defaultTrimColour()))
{
// Set data
setJerseyNumber(jersey_number);
setSurname(surname);

// Output image
image_ = new QImage(Dimensions::JerseyImageWidth,
Dimensions::JerseyImageHeight,
QImage::Format_ARGB32);
image_->fill(QColor(0, 0, 0, 0)); // Fill the image in order to avoid artefacts
}

// --- Destructor --- //
Jersey::~Jersey()
{
delete image_;
}

// --- File i/o --- //
bool Jersey::save(const QString &filename) const
{
return image_->save(filename);
}

// --- Generate font --- //
QFont Jersey::font() const
{
const auto font_id{QFontDatabase::addApplicationFont(":/fonts/sports_jersey.ttf")};
const auto font_family{QFontDatabase::applicationFontFamilies(font_id).at(0)};

QFont font(font_family, Dimensions::JerseyNameFontSize, QFont::Thin);
font.setLetterSpacing(QFont::AbsoluteSpacing, Dimensions::FontLetterSpacing);
font.setStyleStrategy(QFont::PreferAntialias);
font.setStretch(QFont::Unstretched);

return font;
}

// --- Generate image --- //
void Jersey::generate()
{
// Background colour image
const QImage background_layer{
generateJerseyLayer(":/images/default_background.png", background_colour_)};

// Foreground colour image
const QImage foreground_layer{
generateJerseyLayer(":/images/default_foreground.png", foreground_colour_)};

// Trim colour image
const QImage trim_layer{generateJerseyLayer(":/images/default_trim.png", trim_colour_)};

// Font
auto font{this->font()};

// Paint/collate the jersey
QPainter jersey_painter(image_);
jersey_painter.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing);
jersey_painter.setPen(pen());

// Paint the jersey layers
jersey_painter.drawImage(0, Dimensions::JerseyImageVerticalPadding, background_layer);
jersey_painter.drawImage(0, Dimensions::JerseyImageVerticalPadding, foreground_layer);
jersey_painter.drawImage(0, Dimensions::JerseyImageVerticalPadding, trim_layer);

// Paint the jersey name text
auto name_layer{generateNameLayer()};
jersey_painter.drawImage(0,
Dimensions::JerseyNameVerticalPosition,
name_layer.scaledToHeight(Dimensions::JerseyNameFontSize,
Qt::SmoothTransformation));

// Paint the jersey number text
font.setPointSize(Dimensions::JerseyNumberFontSize);
jersey_painter.setFont(font);
jersey_painter.drawText(0,
Dimensions::JerseyNumberVerticalPosition,
Dimensions::JerseyImageWidth,
Dimensions::JerseyNumberFontSize,
Qt::AlignCenter,
QString::number(jersey_number_));

jersey_painter.end();
}

// --- Generate a layer of the jersey image --- //
QImage Jersey::generateJerseyLayer(const QString &filename, QColor colour)
{
QImage image(filename);

const auto height{image.height()};
const auto width{image.width()};

// Loop all the pixels
for (qint32 y = 0; y < height; ++y) {
for (qint32 x = 0; x < width; ++x) {
// Read the alpha value each pixel, keeping the RGB values of your color
colour.setAlpha(image.pixelColor(x, y).alpha());

// Apply the pixel color
image.setPixelColor(x, y, colour);
}
}

return image;
}

// --- Generate the name layer of the image --- //
QImage Jersey::generateNameLayer() const
{
/* The text quality generated appears rather poor at small sizes.
* This function generates a larger image when can then be scaled down,
* resulting better quality text.
*/

// Font
auto font{this->font()};
font.setPointSize(Dimensions::JerseyNameUpscaledFontSize);

// Name text
const QString name_text{(use_uppercase_text_) ? surname_.toUpper() : surname_};

// Name layer image
QImage name_layer(Dimensions::JerseyNameUpscaledWidth,
Dimensions::JerseyNameUpscaledHeight,
QImage::Format_ARGB32);
name_layer.fill(QColor(0, 0, 0, 0)); // Fill the image in order to avoid artefacts

// Name layer painter
QPainter painter(&name_layer);
painter.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing);
painter.setPen(pen());
painter.setFont(font);
painter.drawText(0,
0,
Dimensions::JerseyNameUpscaledWidth,
Dimensions::JerseyNameUpscaledHeight,
Qt::AlignCenter,
name_text);
painter.end();

qInfo() << QString("Upscaled name layer dimensions: %1 x %2")
.arg(name_layer.width())
.arg(name_layer.height());
qInfo() << QString("Downscaled name layer dimensions: %1 x %2")
.arg(name_layer.width() / Dimensions::JerseyNameUpscaleMultiplier)
.arg(name_layer.height() / Dimensions::JerseyNameUpscaleMultiplier);

return name_layer;
}

// --- Pen for use with text generation --- //
QPen Jersey::pen() const
{
QPen pen(trim_colour_, Dimensions::PenThickness);
pen.setCapStyle(Qt::RoundCap);
pen.setJoinStyle(Qt::RoundJoin);

return pen;
}
Loading

0 comments on commit cbb266c

Please sign in to comment.