[Bf-blender-cvs] [e652dcc4765] greasepencil-object: GPencil: New operator to extract Palette from Image
Antonio Vazquez
noreply at git.blender.org
Sun Nov 17 11:33:32 CET 2019
Commit: e652dcc476562a1016eb6c4a6b8bacd1bf46f2d3
Author: Antonio Vazquez
Date: Sun Nov 17 11:32:43 2019 +0100
Branches: greasepencil-object
https://developer.blender.org/rBe652dcc476562a1016eb6c4a6b8bacd1bf46f2d3
GPencil: New operator to extract Palette from Image
===================================================================
M source/blender/blenkernel/BKE_paint.h
M source/blender/blenkernel/intern/paint.c
M source/blender/editors/sculpt_paint/paint_ops.c
M source/blender/makesdna/DNA_brush_types.h
===================================================================
diff --git a/source/blender/blenkernel/BKE_paint.h b/source/blender/blenkernel/BKE_paint.h
index 92b9d383c48..2f22caa805d 100644
--- a/source/blender/blenkernel/BKE_paint.h
+++ b/source/blender/blenkernel/BKE_paint.h
@@ -30,6 +30,7 @@ struct Brush;
struct CurveMapping;
struct Depsgraph;
struct EnumPropertyItem;
+struct GHash;
struct GridPaintMask;
struct ImagePool;
struct MLoop;
@@ -51,6 +52,7 @@ struct SubdivCCG;
struct SubdivCCG;
struct Tex;
struct ToolSettings;
+struct tPaletteColorHue;
struct UnifiedPaintSettings;
struct View3D;
struct ViewLayer;
@@ -126,6 +128,9 @@ bool BKE_palette_is_empty(const struct Palette *palette);
void BKE_palette_color_remove(struct Palette *palette, struct PaletteColor *color);
void BKE_palette_clear(struct Palette *palette);
+void BKE_palette_sort_hs(struct tPaletteColorHue *color_array, const int totcol);
+bool BKE_palette_from_hash(struct Main *bmain, struct GHash *color_table);
+
/* paint curves */
struct PaintCurve *BKE_paint_curve_add(struct Main *bmain, const char *name);
void BKE_paint_curve_free(struct PaintCurve *pc);
diff --git a/source/blender/blenkernel/intern/paint.c b/source/blender/blenkernel/intern/paint.c
index ff1682910a1..3f999dfcae2 100644
--- a/source/blender/blenkernel/intern/paint.c
+++ b/source/blender/blenkernel/intern/paint.c
@@ -647,6 +647,87 @@ bool BKE_palette_is_empty(const struct Palette *palette)
return BLI_listbase_is_empty(&palette->colors);
}
+/* helper function to sort using qsort */
+static int palettecolor_compare_hue_sat(const void *a1, const void *a2)
+{
+ const tPaletteColorHue *ps1 = a1, *ps2 = a2;
+ int a = ps1->hue * 1e6 + ps1->sat * 1e3;
+ int b = ps2->hue * 1e6 + ps2->sat * 1e3;
+
+ if (a < b) {
+ return -1;
+ }
+ else if (a > b) {
+ return 1;
+ }
+
+ return 0;
+}
+
+void BKE_palette_sort_hs(tPaletteColorHue *color_array, const int totcol)
+{
+ /* Sort by Hue and saturation. */
+ qsort(color_array, totcol, sizeof(tPaletteColorHue), palettecolor_compare_hue_sat);
+}
+
+bool BKE_palette_from_hash(Main *bmain, GHash *color_table)
+{
+ tPaletteColorHue *color_array = NULL;
+ tPaletteColorHue *col_elm = NULL;
+ bool done = false;
+
+ const int totpal = BLI_ghash_len(color_table);
+
+ if (totpal > 0) {
+ color_array = MEM_calloc_arrayN(totpal, sizeof(tPaletteColorHue), __func__);
+ /* Put all colors in an array. */
+ GHashIterator gh_iter;
+ int t = 0;
+ GHASH_ITER (gh_iter, color_table) {
+ const uint col = POINTER_AS_INT(BLI_ghashIterator_getValue(&gh_iter));
+ float r, g, b;
+ float h, s, v;
+ cpack_to_rgb(col, &r, &g, &b);
+ rgb_to_hsv(r, g, b, &h, &s, &v);
+
+ col_elm = &color_array[t];
+ col_elm->rgb[0] = r;
+ col_elm->rgb[1] = g;
+ col_elm->rgb[2] = b;
+ col_elm->hue = h;
+ col_elm->sat = s;
+ t++;
+ }
+ }
+
+ /* Create the Palette. */
+ if (totpal > 0) {
+ /* Sort by Hue and saturation. */
+ BKE_palette_sort_hs(color_array, totpal);
+
+ Palette *palette = BKE_palette_add(bmain, "Palette");
+ if (palette) {
+ for (int i = 0; i < totpal; i++) {
+ col_elm = &color_array[i];
+ PaletteColor *palcol = BKE_palette_color_add(palette);
+ if (palcol) {
+ copy_v3_v3(palcol->rgb, col_elm->rgb);
+ }
+ }
+ done = true;
+ }
+ }
+ else {
+ done = false;
+ }
+
+ if (totpal > 0) {
+ MEM_SAFE_FREE(color_array);
+ }
+
+ return done;
+}
+
/* are we in vertex paint or weight paint face select mode? */
bool BKE_paint_select_face_test(Object *ob)
{
diff --git a/source/blender/editors/sculpt_paint/paint_ops.c b/source/blender/editors/sculpt_paint/paint_ops.c
index b6f99850cdd..9312b9c0487 100644
--- a/source/blender/editors/sculpt_paint/paint_ops.c
+++ b/source/blender/editors/sculpt_paint/paint_ops.c
@@ -26,6 +26,8 @@
#include "BLI_math_vector.h"
#include "BLI_string.h"
+#include "IMB_imbuf_types.h"
+
#include "DNA_customdata_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
@@ -33,9 +35,11 @@
#include "BKE_brush.h"
#include "BKE_context.h"
+#include "BKE_image.h"
#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_paint.h"
+#include "BKE_report.h"
#include "ED_paint.h"
#include "ED_screen.h"
@@ -294,6 +298,107 @@ static void PALETTE_OT_color_delete(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+/* --- Extract Palette from Image. */
+
+/* Return pixel data (rgba) at index. */
+static void get_image_pixel(const ImBuf *ibuf, const int idx, float r_col[3])
+{
+ if (ibuf->rect_float) {
+ const float *frgba = &ibuf->rect_float[idx * 4];
+ copy_v3_v3(r_col, frgba);
+ }
+ else if (ibuf->rect) {
+ float r, g, b;
+ uint *cp = &ibuf->rect[idx];
+ uint a = *cp;
+ cpack_to_rgb(a, &r, &g, &b);
+ r_col[0] = r;
+ r_col[1] = g;
+ r_col[2] = b;
+ }
+ else {
+ zero_v4(r_col);
+ }
+}
+
+static bool palette_extract_img_poll(bContext *C)
+{
+ SpaceLink *sl = CTX_wm_space_data(C);
+ if (sl->spacetype == SPACE_IMAGE) {
+ return true;
+ }
+
+ return false;
+}
+
+static int palette_extract_img_exec(bContext *C, wmOperator *op)
+{
+ const int threshold = RNA_int_get(op->ptr, "threshold");
+
+ Main *bmain = CTX_data_main(C);
+ bool done = false;
+ int totpal = 0;
+
+ SpaceImage *sima = CTX_wm_space_image(C);
+ Image *image = sima->image;
+ ImageUser iuser = sima->iuser;
+ void *lock;
+ ImBuf *ibuf;
+ GHash *color_table = BLI_ghash_int_new(__func__);
+
+ ibuf = BKE_image_acquire_ibuf(image, &iuser, &lock);
+
+ if (ibuf->rect) {
+ const int maxpixel = (ibuf->x * ibuf->y) - 1;
+
+ /* Extract all colors. */
+ for (int v = maxpixel; v != 0; v--) {
+ float col[3];
+ get_image_pixel(ibuf, v, col);
+
+ const float range = pow(10.0f, threshold);
+ col[0] = truncf(col[0] * range) / range;
+ col[1] = truncf(col[1] * range) / range;
+ col[2] = truncf(col[2] * range) / range;
+
+ uint key = rgb_to_cpack(col[0], col[1], col[2]);
+ if (!BLI_ghash_haskey(color_table, POINTER_FROM_INT(key))) {
+ BLI_ghash_insert(color_table, POINTER_FROM_INT(key), POINTER_FROM_INT(key));
+ }
+ }
+
+ done = BKE_palette_from_hash(bmain, color_table);
+ }
+
+ /* Free memory. */
+ BLI_ghash_free(color_table, NULL, NULL);
+ BKE_image_release_ibuf(image, ibuf, lock);
+
+ if (done) {
+ BKE_reportf(op->reports, RPT_INFO, "Palette created with %d swatches", totpal);
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+void PALETTE_OT_extract_from_image(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Extract Palette from Image";
+ ot->idname = "PALETTE_OT_extract_from_image";
+ ot->description = "Extract all colors used in Image and create a Palette";
+
+ /* api callbacks */
+ ot->exec = palette_extract_img_exec;
+ ot->poll = palette_extract_img_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ RNA_def_int(ot->srna, "threshold", 1, 1, 4, "Threshold", "", 1, 4);
+}
+
static int brush_reset_exec(bContext *C, wmOperator *UNUSED(op))
{
Paint *paint = BKE_paint_get_active_from_context(C);
@@ -967,6 +1072,8 @@ void ED_operatortypes_paint(void)
WM_operatortype_append(PALETTE_OT_color_add);
WM_operatortype_append(PALETTE_OT_color_delete);
+ WM_operatortype_append(PALETTE_OT_extract_from_image);
+
/* paint curve */
WM_operatortype_append(PAINTCURVE_OT_new);
WM_operatortype_append(PAINTCURVE_OT_add_point);
diff --git a/source/blender/makesdna/DNA_brush_types.h b/source/blender/makesdna/DNA_brush_types.h
index 5a4b975baaf..e7bc5eddaf7 100644
--- a/source/blender/makesdna/DNA_brush_types.h
+++ b/source/blender/makesdna/DNA_brush_types.h
@@ -368,6 +368,14 @@ typedef struct Brush {
struct BrushGpencilSettings *gpencil_settings;
} Brush;
+
+/* Struct to hold palette colors for sorting. */
+typedef struct tPaletteColorHue {
+ float rgb[3];
+ float hue;
+ float sat;
+} tPaletteColorHue;
+
typedef struct PaletteColor {
struct PaletteColor *next, *prev;
/* two values, one to store rgb, other to store values for sculpt/weight */
@@ -537,7 +545,7 @@ typedef enum eBrushUVSculptTool {
SCULPT_TOOL_POSE, \
\
/* These brushes could handle dynamic topology, \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \
- * but user feedback indicates it's better not to */ \
+ * \ but user feedback indicates it's better not to */ \
SCULPT_TOOL_SMOOTH, \
SCULPT_TOOL_MASK) == 0)
More information about the Bf-blender-cvs
mailing list