Extract background color to continue image
This commit is contained in:
parent
35d07c1aa4
commit
26c282138e
23 changed files with 218 additions and 115 deletions
|
@ -677,7 +677,7 @@ func createExercice(c *gin.Context) {
|
|||
}
|
||||
}
|
||||
|
||||
exercice, err := theme.AddExercice(ue.Title, ue.Authors, ue.Image, ue.WIP, ue.URLId, ue.Path, ue.Statement, ue.Overview, ue.Headline, depend, ue.Gain, ue.VideoURI, ue.Resolution, ue.SeeAlso, ue.Finished)
|
||||
exercice, err := theme.AddExercice(ue.Title, ue.Authors, ue.Image, ue.BackgroundColor, ue.WIP, ue.URLId, ue.Path, ue.Statement, ue.Overview, ue.Headline, depend, ue.Gain, ue.VideoURI, ue.Resolution, ue.SeeAlso, ue.Finished)
|
||||
if err != nil {
|
||||
log.Println("Unable to createExercice:", err.Error())
|
||||
c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": "An error occurs during exercice creation."})
|
||||
|
|
|
@ -1715,7 +1715,7 @@ angular.module("FICApp")
|
|||
})
|
||||
.controller("ThemeController", function($scope, Theme, $routeParams, $location, $rootScope, $http) {
|
||||
$scope.theme = Theme.get({ themeId: $routeParams.themeId });
|
||||
$scope.fields = ["name", "urlid", "locked", "authors", "headline", "intro", "image", "partner_txt", "partner_href", "partner_img"];
|
||||
$scope.fields = ["name", "urlid", "locked", "authors", "headline", "intro", "image", "background_color", "partner_txt", "partner_href", "partner_img"];
|
||||
|
||||
$scope.saveTheme = function() {
|
||||
if (this.theme.id) {
|
||||
|
@ -1893,7 +1893,7 @@ angular.module("FICApp")
|
|||
}
|
||||
});
|
||||
$scope.exercices = Exercice.query();
|
||||
$scope.fields = ["title", "urlid", "authors", "disabled", "statement", "headline", "overview", "finished", "depend", "gain", "coefficient", "videoURI", "image", "resolution", "issue", "issuekind", "wip"];
|
||||
$scope.fields = ["title", "urlid", "authors", "disabled", "statement", "headline", "overview", "finished", "depend", "gain", "coefficient", "videoURI", "image", "background_color", "resolution", "issue", "issuekind", "wip"];
|
||||
|
||||
$scope.inSync = false;
|
||||
$scope.syncExo = function() {
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
<div class="form-group row" ng-repeat="field in fields">
|
||||
<label for="{{ field }}" class="col-sm-1 col-form-label-sm">{{ field | capitalize }}</label>
|
||||
<div class="col-sm-11">
|
||||
<input type="text" class="form-control form-control-sm" id="{{ field }}" ng-model="exercice[field]" ng-if="field != 'statement' && field != 'issue' && field != 'issuekind' && field != 'overview' && field != 'resolution' && field != 'finished' && field != 'depend' && field != 'gain' && field != 'coefficient' && field != 'wip' && field != 'disabled'">
|
||||
<input type="text" class="form-control form-control-sm" id="{{ field }}" ng-model="exercice[field]" ng-if="field != 'statement' && field != 'issue' && field != 'issuekind' && field != 'overview' && field != 'resolution' && field != 'finished' && field != 'depend' && field != 'gain' && field != 'coefficient' && field != 'wip' && field != 'disabled' && field != 'background_color'">
|
||||
<input type="checkbox" id="{{ field }}" ng-model="exercice[field]" ng-if="field == 'wip' || field == 'disabled'">
|
||||
<input type="text" class="form-control form-control-sm" id="{{ field }}" ng-model="exercice[field]" ng-if="field == 'gain'" integer>
|
||||
<input type="text" class="form-control form-control-sm" id="{{ field }}" ng-model="exercice[field]" ng-if="field == 'coefficient'" float>
|
||||
|
@ -30,6 +30,7 @@
|
|||
<option value="">Aucune</option>
|
||||
</select>
|
||||
<select class="form-control form-control-sm" id="{{field}}" ng-model="exercice[field]" ng-options="v for v in ['primary', 'secondary', 'success', 'danger', 'warning', 'info', 'light', 'dark']" ng-if="field == 'issuekind'"></select>
|
||||
<input type="color" class="form-control form-control-sm" id="{{ field }}" ng-model="exercice[field]" ng-if="field == 'background_color'" color>
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-right" ng-show="exercice.id">
|
||||
|
|
|
@ -12,8 +12,9 @@
|
|||
<div ng-class="{'form-group': field != 'locked', 'form-check': field == 'locked'}" ng-repeat="field in fields">
|
||||
<input type="checkbox" class="form-check-input" id="{{ field }}" ng-model="theme[field]" ng-if="field == 'locked'">
|
||||
<label for="{{ field }}">{{ field | capitalize }}</label>
|
||||
<input type="text" class="form-control form-control-sm" id="{{ field }}" ng-model="theme[field]" ng-if="field != 'intro' && field != 'locked'">
|
||||
<input type="text" class="form-control form-control-sm" id="{{ field }}" ng-model="theme[field]" ng-if="field != 'intro' && field != 'locked' && field != 'background_color'">
|
||||
<textarea class="form-control form-control-sm" id="{{ field }}" ng-model="theme[field]" ng-if="field == 'intro'"></textarea>
|
||||
<input type="color" class="form-control form-control-sm" id="{{ field }}" ng-model="theme[field]" ng-if="field == 'background_color'" color>
|
||||
</div>
|
||||
<div class="text-right" ng-show="theme.id">
|
||||
<button type="submit" class="btn btn-success"><span class="glyphicon glyphicon-save" aria-hidden="true"></span> Save</button>
|
||||
|
|
|
@ -397,6 +397,8 @@ func SyncExercice(i Importer, theme *fic.Theme, epath string, dmap *map[int64]*f
|
|||
|
||||
e.Image = strings.TrimPrefix(filePath, fic.FilesDir)
|
||||
|
||||
e.BackgroundColor, _ = getBackgroundColor(filePath)
|
||||
|
||||
// If the theme has no image yet, use the first exercice's image found
|
||||
theme.Image = e.Image
|
||||
_, err := theme.Update()
|
||||
|
|
|
@ -13,6 +13,7 @@ import (
|
|||
"strings"
|
||||
"unicode"
|
||||
|
||||
"github.com/cenkalti/dominantcolor"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/yuin/goldmark"
|
||||
"go.uber.org/multierr"
|
||||
|
@ -86,6 +87,49 @@ func resizePicture(importedPath string, rect image.Rectangle) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
type SubImager interface {
|
||||
SubImage(r image.Rectangle) image.Image
|
||||
}
|
||||
|
||||
// getBackgroundColor retrieves the most dominant color in the bottom of the image.
|
||||
func getBackgroundColor(importedPath string) (uint32, error) {
|
||||
fl, err := os.Open(strings.TrimSuffix(importedPath, ".jpg") + ".thumb.jpg")
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
src, _, err := image.Decode(fl)
|
||||
if err != nil {
|
||||
fl.Close()
|
||||
return 0, err
|
||||
}
|
||||
|
||||
bounds := src.Bounds()
|
||||
|
||||
// Test if the right and left corner have the same color
|
||||
bottomLeft := src.(SubImager).SubImage(image.Rect(0, bounds.Dy()-10, 40, bounds.Dy()))
|
||||
bottomRight := src.(SubImager).SubImage(image.Rect(bounds.Dx()-40, bounds.Dy()-10, bounds.Dx(), bounds.Dy()))
|
||||
|
||||
colorLeft := dominantcolor.Find(bottomLeft)
|
||||
colorRight := dominantcolor.Find(bottomRight)
|
||||
if uint32(colorLeft.R>>5)<<16+uint32(colorLeft.G>>5)<<8+uint32(colorLeft.B>>5) == uint32(colorRight.R>>5)<<16+uint32(colorRight.G>>5)<<8+uint32(colorRight.B>>5) {
|
||||
return uint32(colorLeft.R)<<16 + uint32(colorLeft.G)<<8 + uint32(colorLeft.B), nil
|
||||
}
|
||||
|
||||
// Only keep the darkest color of the bottom of the image
|
||||
bottomFull := src.(SubImager).SubImage(image.Rect(0, bounds.Dy()-5, bounds.Dx(), bounds.Dy()))
|
||||
colors := dominantcolor.FindN(bottomFull, 4)
|
||||
|
||||
color := colors[0]
|
||||
for _, c := range colors {
|
||||
if uint32(color.R<<2)+uint32(color.G<<2)+uint32(color.B<<2) > uint32(c.R<<2)+uint32(c.G<<2)+uint32(c.B<<2) {
|
||||
color = c
|
||||
}
|
||||
}
|
||||
|
||||
return uint32(color.R)<<16 + uint32(color.G)<<8 + uint32(color.B), nil
|
||||
}
|
||||
|
||||
// getAuthors parses the AUTHORS file.
|
||||
func getAuthors(i Importer, tname string) ([]string, error) {
|
||||
if authors, err := GetFileContent(i, path.Join(tname, "AUTHORS.txt")); err != nil {
|
||||
|
@ -258,6 +302,7 @@ func SyncThemes(i Importer) (exceptions map[string]*CheckExceptions, errs error)
|
|||
}
|
||||
|
||||
btheme.Image = strings.TrimPrefix(filePath, fic.FilesDir)
|
||||
btheme.BackgroundColor, _ = getBackgroundColor(filePath)
|
||||
return nil, nil
|
||||
}); err != nil {
|
||||
errs = multierr.Append(errs, NewThemeError(btheme, fmt.Errorf("unable to import heading image: %w", err)))
|
||||
|
|
Reference in a new issue