Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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 CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ Le format est basé sur [Keep a Changelog](https://keepachangelog.com/) et ce pr

## [Unreleased]

### Added

- `Colorize` : Ajout d'un style colorize permettant de remplacer une couleur en une autre avec une possibilité de transparence.

## [3.0.0] - 2026-03-12

### Added
Expand Down
109 changes: 109 additions & 0 deletions include/rok4/style/Colorize.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
/*
* Copyright © (2011) Institut national de l'information
* géographique et forestière
*
* Géoportail SAV <contact.geoservices@ign.fr>
*
* This software is a computer program whose purpose is to publish geographic
* data using OGC WMS and WMTS protocol.
*
* This software is governed by the CeCILL-C license under French law and
* abiding by the rules of distribution of free software. You can use,
* modify and/ or redistribute the software under the terms of the CeCILL-C
* license as circulated by CEA, CNRS and INRIA at the following URL
* "http://www.cecill.info".
*
* As a counterpart to the access to the source code and rights to copy,
* modify and redistribute granted by the license, users are provided only
* with a limited warranty and the software's author, the holder of the
* economic rights, and the successive licensors have only limited
* liability.
*
* In this respect, the user's attention is drawn to the risks associated
* with loading, using, modifying and/or developing or reproducing the
* software by the user in light of its specific status of free software,
* that may mean that it is complicated to manipulate, and that also
* therefore means that it is reserved for developers and experienced
* professionals having in-depth computer knowledge. Users are therefore
* encouraged to load and test the software's suitability as regards their
* requirements in conditions enabling the security of their systems and/or
* data to be ensured and, more generally, to use and operate it in the
* same conditions as regards security.
*
* The fact that you are presently reading this means that you have had
*
* knowledge of the CeCILL-C license and that you accept its terms.
*/

/**
* \file Colorize.h
** \~french
* \brief D�finition de la classe Colorize
** \~english
* \brief Define class Colorize
*/


#pragma once

#include "rok4/utils/Configuration.h"

#include <stdint.h>
#include <vector>
#include <map>
#include <stddef.h>

class Colorize : public Configuration
{
public:
/** \~french
* \brief tolerance : seuil de tolérance pour gérer les teintes de blanc plus larges
** \~english
* \brief tolerance : tolerance threshold for managing wider shades of white
*/
int tolerance;

/** \~french
* \brief source : valeur visée en entrée
** \~english
* \brief source : input target value
*/
std::vector<int> source;

/** \~french
* \brief destination : valeur visée en sortie
** \~english
* \brief destination : output target value
*/
std::vector<int> destination;

/** \~french
* \brief noData : valeur de nodata pour l'image source
** \~english
* \brief noData : value of nodata for the source image
*/
std::vector<int> input_nodata_value;

/** \~french
* \brief noData : valeur de nodata pour le colorize
** \~english
* \brief noData : value of nodata for the colorize
*/
float colorize_nodata_value;

/**
* \~french
* \brief Constructeurs avec des arguments
* \~english
* \brief Constructor with arguments
*/
Colorize(json11::Json doc);

/**
* \~french
* \brief Destructeur
* \~english
* \brief Destructor
*/
virtual ~Colorize();
};
41 changes: 38 additions & 3 deletions include/rok4/style/Style.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ class Style;
#include "rok4/style/Estompage.h"
#include "rok4/style/Aspect.h"
#include "rok4/style/Terrainrgb.h"
#include "rok4/style/Colorize.h"
#include "rok4/enums/Interpolation.h"
#include "rok4/utils/Configuration.h"
#include "rok4/utils/StoragePool.h"
Expand Down Expand Up @@ -169,6 +170,11 @@ private :
* \~english \brief Define wether the server must compute a RGB terrain
*/
Terrainrgb* terrainrgb;
/**
* \~french \brief Définit si un calcul de white to alpha doit être appliqué
* \~english \brief Define wether the server must compute a white to alpha
*/
Colorize* colorize;

/**
* \~french \brief Valeur de nodata attendue dans les données en entrée
Expand Down Expand Up @@ -226,7 +232,7 @@ private :
* \~english \brief Style is allowed ?
*/
bool handle (int spp) {
if (estompage_defined() || pente_defined() || aspect_defined() || terrainrgb_defined()) {
if (estompage_defined() || pente_defined() || aspect_defined() || terrainrgb_defined() || colorize_defined()) {
return (spp == 1);
} else {
return true;
Expand Down Expand Up @@ -258,6 +264,14 @@ private :
return orig_channels;
}
}
else if (colorize_defined()){
if (orig_channels ==3 || orig_channels ==4){
return colorize->destination.size();
}
else {
return orig_channels;
}
}
else {
if (estompage_defined() || pente_defined() || aspect_defined()) {
return 1;
Expand All @@ -274,7 +288,7 @@ private :
* \~english \brief Which sample format after style
*/
SampleFormat::eSampleFormat get_sample_format (SampleFormat::eSampleFormat sf) {
if ((palette && ! palette->is_empty()) || terrainrgb_defined()) {
if ((palette && ! palette->is_empty()) || terrainrgb_defined() || colorize_defined()) {
return SampleFormat::UINT8;
} else {
return sf;
Expand Down Expand Up @@ -314,7 +328,7 @@ private :
return false;
}

if (estompage_defined() || pente_defined() || aspect_defined() || terrainrgb_defined()) {
if (estompage_defined() || pente_defined() || aspect_defined() || terrainrgb_defined() || colorize_defined()) {
return false;
} else {
return true;
Expand Down Expand Up @@ -475,6 +489,27 @@ private :
inline Terrainrgb* get_terrainrgb() {
return terrainrgb;
}

/**
* \~french
* \brief Return vrai si le style est un white to alpha
* \return bool
* \~english
* \brief Return true if the style is an white to alpha
* \return bool
*/
inline bool colorize_defined() {
return (colorize != 0);
}
/**
* \~french
* \brief Retourne le white to alpha
* \~english
* \brief Return white to alpha
*/
inline Colorize* get_colorize() {
return colorize;
}


/**
Expand Down
153 changes: 153 additions & 0 deletions src/image/StyledImage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,14 @@ StyledImage::StyledImage(Image *input_image, Style *input_style, int offset) : I
}
}

else if (style->colorize_defined()) {
if (source_image->get_channels() == 3 || source_image->get_channels() == 4) {
channels = style->get_colorize()->destination.size();
} else {
channels = input_image->get_channels();
}
}

if (style->palette_defined()){
// Il n'y aura application de la palette et modification des canaux que si
// - la palette n'est pas nulle et pas vide
Expand Down Expand Up @@ -489,6 +497,138 @@ int StyledImage::_getline(T *buffer, int line) {
space = width * sizeof ( T ) * channels;
}

else if (style->colorize_defined()) {
Colorize* wta = style->get_colorize();
switch ( channels ) {
case 3:
if (source_image->get_channels()==3){
for (int i = 0; i < source_image->get_width() ; i++ ) {
//image de départ à 3 canaux pour une arrivée en 3 canaux
int red = *(source+i*3);
int green = *(source+i*3+1);
int blue = *(source+i*3+2);
red = red < 0 ? 0 : (red > 255 ? 255 : red);
green = green < 0 ? 0 : (green > 255 ? 255 : green);
blue = blue < 0 ? 0 : (blue > 255 ? 255 : blue);
int s_red = wta->source[0];
int s_green = wta->source[1];
int s_blue = wta->source[2];

if (red>=s_red-wta->tolerance && red<=s_red+wta->tolerance &&
green>=s_green-wta->tolerance && green<=s_green+wta->tolerance &&
blue>=s_blue-wta->tolerance && blue<=s_blue+wta->tolerance){
* ( buffer+i*3 ) = (T) wta->destination[0];
* ( buffer+i*3+1 ) = (T) wta->destination[1];
* ( buffer+i*3+2 ) = (T) wta->destination[2];
}
else{
* ( buffer+i*3 ) = (T) red;
* ( buffer+i*3+1 ) = (T) green;
* ( buffer+i*3+2 ) = (T) blue;
}
}
}
if (source_image->get_channels()==4){
for (int i = 0; i < source_image->get_width() ; i++ ) {
//image de départ à 4 canaux pour une arrivée en 3 canaux
int red = *(source+i*4);
int green = *(source+i*4+1);
int blue = *(source+i*4+2);
int alpha = *(source+i*4+3);
red = red < 0 ? 0 : (red > 255 ? 255 : red);
green = green < 0 ? 0 : (green > 255 ? 255 : green);
blue = blue < 0 ? 0 : (blue > 255 ? 255 : blue);
alpha = alpha < 0 ? 0 : (alpha > 255 ? 255 : alpha);
int s_red = wta->source[0];
int s_green = wta->source[1];
int s_blue = wta->source[2];
int s_alpha = wta->source[3];

if (red>=s_red-wta->tolerance && red<=s_red+wta->tolerance &&
green>=s_green-wta->tolerance && green<=s_green+wta->tolerance &&
blue>=s_blue-wta->tolerance && blue<=s_blue+wta->tolerance &&
alpha>=s_alpha-wta->tolerance && alpha<=s_alpha+wta->tolerance){
* ( buffer+i*3 ) = (T) wta->destination[0];
* ( buffer+i*3+1 ) = (T) wta->destination[1];
* ( buffer+i*3+2 ) = (T) wta->destination[2];
}
else{
* ( buffer+i*3 ) = (T) red;
* ( buffer+i*3+1 ) = (T) green;
* ( buffer+i*3+2 ) = (T) blue;
}
}
}
break;
case 4:
if (source_image->get_channels()==3){
for (int i = 0; i < source_image->get_width() ; i++ ) {
//image de départ à 3 canaux pour une arrivée en 4 canaux
int red = *(source+i*3);
int green = *(source+i*3+1);
int blue = *(source+i*3+2);
red = red < 0 ? 0 : (red > 255 ? 255 : red);
green = green < 0 ? 0 : (green > 255 ? 255 : green);
blue = blue < 0 ? 0 : (blue > 255 ? 255 : blue);
int s_red = wta->source[0];
int s_green = wta->source[1];
int s_blue = wta->source[2];

if (red>=s_red-wta->tolerance && red<=s_red+wta->tolerance &&
green>=s_green-wta->tolerance && green<=s_green+wta->tolerance &&
blue>=s_blue-wta->tolerance && blue<=s_blue+wta->tolerance){
* ( buffer+i*4 ) = (T) wta->destination[0];
* ( buffer+i*4+1 ) = (T) wta->destination[1];
* ( buffer+i*4+2 ) = (T) wta->destination[2];
* ( buffer+i*4+3 ) = (T) wta->destination[3];
}
else{
* ( buffer+i*4 ) = (T) red;
* ( buffer+i*4+1 ) = (T) green;
* ( buffer+i*4+2 ) = (T) blue;
* ( buffer+i*4+3 ) = (T) 255;
}
}
}
if (source_image->get_channels()==4){
for (int i = 0; i < source_image->get_width() ; i++ ) {
//image de départ à 4 canaux pour une arrivée en 4 canaux
int red = *(source+i*4);
int green = *(source+i*4+1);
int blue = *(source+i*4+2);
int alpha = *(source+i*4+3);
red = red < 0 ? 0 : (red > 255 ? 255 : red);
green = green < 0 ? 0 : (green > 255 ? 255 : green);
blue = blue < 0 ? 0 : (blue > 255 ? 255 : blue);
alpha = alpha < 0 ? 0 : (alpha > 255 ? 255 : alpha);
int s_red = wta->source[0];
int s_green = wta->source[1];
int s_blue = wta->source[2];
int s_alpha = wta->source[3];

if (red>=s_red-wta->tolerance && red<=s_red+wta->tolerance &&
green>=s_green-wta->tolerance && green<=s_green+wta->tolerance &&
blue>=s_blue-wta->tolerance && blue<=s_blue+wta->tolerance &&
alpha>=s_alpha-wta->tolerance && alpha<=s_alpha+wta->tolerance){
* ( buffer+i*4 ) = (T) wta->destination[0];
* ( buffer+i*4+1 ) = (T) wta->destination[1];
* ( buffer+i*4+2 ) = (T) wta->destination[2];
* ( buffer+i*4+3 ) = (T) wta->destination[3];
}
else{
* ( buffer+i*4 ) = (T) red;
* ( buffer+i*4+1 ) = (T) green;
* ( buffer+i*4+2 ) = (T) blue;
* ( buffer+i*4+3 ) = (T) alpha;
}
}
}
break;
}

space = width * sizeof ( T ) * channels;
}

if (style->palette_defined()){
switch ( channels ) {
case 4:
Expand Down Expand Up @@ -541,6 +681,16 @@ StyledImage *StyledImage::create(Image *input_image, Style *input_style) {
return NULL;
}
}
if (input_style->colorize_defined()){
if (input_image->get_channels()!=3 && input_image->get_channels()!=4){
BOOST_LOG_TRIVIAL(error)<<"Ce style ne s'applique que sur une image source à trois ou quatre canaux";
return NULL;
}
if (input_style->palette_defined()){
BOOST_LOG_TRIVIAL(error)<<"Le style colorize n'est pas compatible avec une palette";
return NULL;
}
}
return new StyledImage(input_image,input_style,offset);

}
Expand Down Expand Up @@ -570,6 +720,9 @@ void StyledImage::print() {
if (style->terrainrgb_defined()){
BOOST_LOG_TRIVIAL(info) << "--------- Terrainrgb -----------" ;
}
if (style->colorize_defined()){
BOOST_LOG_TRIVIAL(info) << "--------- Colorize -----------" ;
}
if (style->palette_defined()){
BOOST_LOG_TRIVIAL(info) << "--------- Palette -----------" ;
}
Expand Down
Loading
Loading