Skip to content

Commit

Permalink
version 1.0.0-beta.6
Browse files Browse the repository at this point in the history
  • Loading branch information
archibalduk committed Mar 11, 2021
1 parent 0d3a152 commit 77e5465
Show file tree
Hide file tree
Showing 13 changed files with 283 additions and 96 deletions.
45 changes: 28 additions & 17 deletions batch_generator/batch_generator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include <QMessageBox>
#include <QProgressDialog>
#include <QSettings>
#include <QStringList>
#include <QtConcurrent>

/* ========================= */
Expand Down Expand Up @@ -110,10 +111,18 @@ bool BatchGenerator::generate()
for (qint32 i = first_row; i < final_row; ++i)
buffer.push_back(i);

// Error tracker
QStringList error_list;

// Settings
QSettings settings;
const auto generic_design_method{settings.value("generic_design_method").toInt()};

// Jersey generation lambda
std::function<bool(int &)> generate =
[this, &spreadsheet, &progress, &futureWatcher](const int &i) {
[this, &spreadsheet, &error_list, &generic_design_method](const int &i) {
const auto player_surname{spreadsheet.read(i, PLAYER_SECOND_NAME).toString().trimmed()};

if (player_surname.isEmpty())
return true;

Expand All @@ -125,27 +134,23 @@ bool BatchGenerator::generate()
jersey.setImages(Text(spreadsheet.read(i, CLUB_NAME).toString()),
generic_jersey_designs_,
team_jersey_designs_,
*preset_jersey_images_);
*preset_jersey_images_,
generic_design_method);
jersey.generate();

const auto output_file_path{
QString("%1/%2_%3_%4.png")
.arg(output_folder_path_,
spreadsheet.read(i, PLAYER_FIRST_NAME).toString().trimmed(),
//const Text safe_file_name

const auto output_file_path{Text::toSafeFilePath(
output_folder_path_,
QString("%1_%2_%3")
.arg(spreadsheet.read(i, PLAYER_FIRST_NAME).toString().trimmed(),
player_surname,
spreadsheet.read(i, PLAYER_DATE_OF_BIRTH)
.toString()
.replace(".", "_")
.replace("/", "_"))};
spreadsheet.read(i, PLAYER_DATE_OF_BIRTH).toString()),
"png")};
const auto result{jersey.save(output_file_path)};

if (!result) {
futureWatcher.cancel();
progress.cancel();
QMessageBox::critical(nullptr,
QObject::tr("File write error (row %L1").arg(i),
QObject::tr("Unable to save %1 to the disk.")
.arg(output_file_path));
error_list << output_file_path;
return false;
}

Expand All @@ -172,7 +177,13 @@ bool BatchGenerator::generate()

return true;
}
/*
// Progress dialog
void updateProgressDialog(QProgressDialog &progress,
const qint32 &total_rows_processed,
QElapsedTimer &timer) const;
// --- Increment the progress dialog
void BatchGenerator::updateProgressDialog(QProgressDialog &progress,
const qint32 &total_rows_processed,
Expand All @@ -190,7 +201,7 @@ void BatchGenerator::updateProgressDialog(QProgressDialog &progress,
.arg(static_cast<qint32>(remaining)));
progress.setValue(total_rows_processed);
QApplication::processEvents();
}
}*/

/* OLD ITERATION CODE BELOW */
/*
Expand Down
5 changes: 0 additions & 5 deletions batch_generator/batch_generator.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,6 @@ class BatchGenerator
JerseyImageServer *preset_jersey_images_{nullptr};
TeamDesignServer team_jersey_designs_;

// Progress dialog
void updateProgressDialog(QProgressDialog &progress,
const qint32 &total_rows_processed,
QElapsedTimer &timer) const;

enum ENUM_SPREADSHEET_COLUMNS {
PLAYER_FIRST_NAME = 1,
PLAYER_SECOND_NAME,
Expand Down
9 changes: 3 additions & 6 deletions common/dimensions.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,19 +19,16 @@ enum ENUM_JERSEY_DIMENSIONS {
JerseyNumberVerticalPosition = 74,
// Upscaled jersey name text
JerseyNameAvailableNameTextWidth = JerseyImageWidth - (JerseyImageVerticalPadding * 3),
JerseyNameUpscaleMultiplier = 4,
JerseyNameUpscaledFontSize = JerseyNameFontSize * JerseyNameUpscaleMultiplier,
JerseyNameUpscaledWidth = JerseyImageWidth * JerseyNameUpscaleMultiplier,
JerseyNameUpscaledHeight = JerseyNameUpscaledFontSize,
DefaultJerseyNameUpscaleMultiplier = 4
};

enum ENUM_USER_INTERFACE_DIMENSIONS {
// Preview label
PreviewWidth = 220,
PreviewWidth = 250,
PreviewHeight = JerseyImageHeight,
// Widget panel
WidgetPanelCount = 2,
WidgetPanelWidth = 300,
WidgetPanelWidth = 350,
// Application window
WindowPadding = 10,
WindowWidth = PreviewWidth + (WidgetPanelWidth * WidgetPanelCount)
Expand Down
11 changes: 11 additions & 0 deletions common/text.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,17 @@ QString Text::simpleString() const
return text;
}

// --- Return a file path, name and extension with any erroneous characters removed --- //
QString Text::toSafeFilePath(const QString &file_path,
QString file_name,
const QString &file_extension)
{
file_name.remove(QRegularExpression("[<>:\"/\\|?*]"));
file_name.squeeze();

return QString("%1/%2.%3").arg(file_path, file_name, file_extension);
}

// --- Convert text to a simple string with no accents --- //
void Text::toSimpleString(QString &text)
{
Expand Down
3 changes: 3 additions & 0 deletions common/text.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ class Text
QString simpleString() const;
QString simpleStringLowerCase() const { return simpleString().toLower(); }
inline QString text() const { return text_string_; }
static QString toSafeFilePath(const QString &file_path,
QString file_name,
const QString &file_extension);
static void toSimpleString(QString &text);

// Random seed
Expand Down
76 changes: 53 additions & 23 deletions jersey/jersey.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
// --- Static data --- //
std::default_random_engine Jersey::random_generator_(
std::chrono::system_clock::now().time_since_epoch().count());
qint32 Jersey::default_foreground_layer_image_id_{0};
qint32 Jersey::default_trim_layer_image_id_{0};

/* ================================ */
/* Jersey Image Generator */
Expand Down Expand Up @@ -176,12 +178,13 @@ void Jersey::selectRandomLayersByClubName(const Text &club_name)
/* ================ */
/* Images */
/* ================ */

#include <QDebug>
// --- Set images based on club name --- //
void Jersey::setImages(const Text &club_name,
const GenericDesignServer &generic_jersey_designs,
const TeamDesignServer &team_jersey_designs,
const JerseyImageServer &preset_images)
const JerseyImageServer &preset_images,
const qint32 generic_design_method)
{
// FIRST: Check for a preset
preset_image_id_ = preset_images.find(club_name.simpleStringLowerCase());
Expand All @@ -200,13 +203,23 @@ void Jersey::setImages(const Text &club_name,
}

// THIRD: Use a random jersey
selectGenericLayersByClubName(club_name, generic_jersey_designs);

// Purely random designs (could result in some weird designs)
//selectPureRandomLayers();

// Random designs based on club name (could result in some weird designs)
//selectRandomLayersByClubName(club_name);
switch (generic_design_method) {
case FIXED_LAYERS:
foreground_layer_image_id_ = default_foreground_layer_image_id_;
trim_layer_image_id_ = default_trim_layer_image_id_;
qInfo() << foreground_layer_image_id_ << trim_layer_image_id_;
break;
case PURE_RANDOM:
selectPureRandomLayers();
break;
case RANDOM_LAYERS_BY_CLUB_NAME:
selectRandomLayersByClubName(club_name);
break;
case GENERIC_LAYERS_BY_CLUB_NAME:
default:
selectGenericLayersByClubName(club_name, generic_jersey_designs);
break;
}
}

/* ======================= */
Expand Down Expand Up @@ -261,14 +274,24 @@ QImage Jersey::generateNameLayer() const
else if (font_size_ratio < DEFAULT_MINIMUM_FONT_SIZE_RATIO)
font_size_ratio = DEFAULT_MINIMUM_FONT_SIZE_RATIO;

// Upscale multiplier values
const auto jersey_name_upscale_multiplier{
settings.value("name_text_upscale_factor", Dimensions::DefaultJerseyNameUpscaleMultiplier)
.toInt()};
const auto jersey_name_upscaled_font_size{Dimensions::JerseyNameFontSize
* jersey_name_upscale_multiplier};
const auto jersey_name_upscaled_width{Dimensions::JerseyImageWidth
* jersey_name_upscale_multiplier};
const auto jersey_name_upscaled_height{jersey_name_upscaled_font_size};

// Font
FontServer font_server;
auto font{font_server.font()};
font.setPointSize(Dimensions::JerseyNameUpscaledFontSize * font_size_ratio);
font.setPointSize(jersey_name_upscaled_font_size * font_size_ratio);

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

Expand All @@ -282,13 +305,12 @@ QImage Jersey::generateNameLayer() const
// Name bounding rectangle
auto name_bounds{painter.boundingRect(0,
0,
Dimensions::JerseyNameUpscaledWidth,
Dimensions::JerseyNameUpscaledHeight,
jersey_name_upscaled_width,
jersey_name_upscaled_height,
Qt::AlignCenter,
name_text)};
name_bounds.setWidth(Dimensions::JerseyNameUpscaledWidth);
const QPoint centre(Dimensions::JerseyNameUpscaledWidth / 2,
Dimensions::JerseyNameUpscaledHeight / 2);
name_bounds.setWidth(jersey_name_upscaled_width);
const QPoint centre(jersey_name_upscaled_width / 2, jersey_name_upscaled_height / 2);
name_bounds.moveCenter(centre);

// Draw the text
Expand Down Expand Up @@ -354,6 +376,11 @@ void Jersey::paintPresetImage(QPainter &jersey_painter)
preset_image.scaledToHeight(Dimensions::JerseyImageHeight
- Dimensions::JerseyImageVerticalPadding,
Qt::SmoothTransformation));

// Update the background colour to reflect a sample of the preset image colour taken at the centre of the image
// This can later be used to determine whether the trim is too similar to the preset background
background_colour_ = preset_image.pixelColor(preset_image.width() / 2,
preset_image.height() / 2);
}

/* ============= */
Expand All @@ -363,7 +390,8 @@ void Jersey::paintPresetImage(QPainter &jersey_painter)
// --- Pen for use with text generation --- //
QPen Jersey::pen() const
{
// Validate the colour (trim colours similar to the background will result in the foreground colour being used)
// Validate the colour
// (trim colours similar to the background will result in the foreground colour being used)
QSettings settings;
const auto trim_colour_threshold{
settings.value("trim_colour_threshold", DEFAULT_TRIM_COLOUR_THRESHOLD).toInt()};
Expand All @@ -375,15 +403,17 @@ QPen Jersey::pen() const
auto bad_count{0};

for (const auto &itr : trim_gap) {
if (itr <= trim_colour_threshold) // Bad = channel difference within trim colour threshold
// Bad = channel difference within trim colour threshold
if (itr <= trim_colour_threshold)
++bad_count;
else if (itr
>= SAFE_TRIM_COLOUR_GAP) // Good = channel difference is at least the same as the safe colour gap
// Good = channel difference is at least the same as the safe colour gap
else if (itr >= SAFE_TRIM_COLOUR_GAP)
--bad_count;
}

if (bad_count
> 1) // Use the foreground colour if more than one trim colour channel is within the threshold of the background channels
// Use the foreground colour if more than one trim colour channel is within the threshold of
// the background channels
if (bad_count > 1)
colour = &foreground_colour_;

// Set the pen
Expand Down
38 changes: 29 additions & 9 deletions jersey/jersey.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,23 @@ class QImage;
class Jersey
{
public:
enum ENUM_FLAGS {
MINIMUM_JERSEY_NUMBER = 1,
MAXIMUM_JERSEY_NUMBER = 99,
DEFAULT_JERSEY_TEXT_CHARACTER_LIMIT = 14,
DEFAULT_JERSEY_TEXT_UPSCALE_FACTOR = 14,
DEFAULT_TRIM_COLOUR_THRESHOLD = 60,
SAFE_TRIM_COLOUR_GAP = 70
};

enum ENUM_GENERIC_DESIGN_METHOD_INDEXES {
FIXED_LAYERS,
GENERIC_LAYERS_BY_CLUB_NAME,
PURE_RANDOM,
RANDOM_LAYERS_BY_CLUB_NAME,
GENERIC_DESIGN_METHOD_SELECTOR_INDEX_COUNT
};

// Constructor
Jersey(const QString &surname = "Smith", const qint32 jersey_number = 99);
~Jersey();
Expand All @@ -46,11 +63,18 @@ class Jersey
foreground_colour_ = foreground;
trim_colour_ = trim;
}
inline static void setDefaultImages(const qint32 foreground_layer_image,
const qint32 trim_layer_image)
{
default_foreground_layer_image_id_ = foreground_layer_image;
default_trim_layer_image_id_ = trim_layer_image;
}
inline void setJerseyNumber(const qint16 jersey_number) { jersey_number_ = jersey_number; }
void setImages(const Text &club_name,
const GenericDesignServer &generic_jersey_designs,
const TeamDesignServer &team_jersey_designs,
const JerseyImageServer &preset_images);
const JerseyImageServer &preset_images,
const qint32 generic_design_method = GENERIC_LAYERS_BY_CLUB_NAME);
inline void setImages(const qint32 foreground_layer_image,
const qint32 trim_layer_image,
const qint32 preset_image)
Expand All @@ -62,14 +86,6 @@ class Jersey
inline void setSurname(const QString &surname) { surname_ = surname; }
inline void usePresetImage(const bool b) { use_preset_image_ = b; }

enum ENUM_FLAGS {
MINIMUM_JERSEY_NUMBER = 1,
MAXIMUM_JERSEY_NUMBER = 99,
DEFAULT_JERSEY_TEXT_CHARACTER_LIMIT = 14,
DEFAULT_TRIM_COLOUR_THRESHOLD = 60,
SAFE_TRIM_COLOUR_GAP = 70
};

private:
// Colours
qint32 createColourValue(const qint32 value);
Expand All @@ -90,6 +106,10 @@ class Jersey
void paintLayeredImage(QPainter &jersey_painter);
void paintPresetImage(QPainter &jersey_painter);

// Default layer image designs
static qint32 default_foreground_layer_image_id_;
static qint32 default_trim_layer_image_id_;

// Layer image designs
qint32 background_layer_image_id_{0};
qint32 foreground_layer_image_id_{0};
Expand Down
Loading

0 comments on commit 77e5465

Please sign in to comment.