[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