3
$\begingroup$

Image editor allows you to extract a palette via Image-->extract Palette. Is there a way to set the number of color the image gets reduced to?

Python gives you a threshold value at least.

bpy.ops.palette.extract_from_image(threshold=10)  

But setting it manually gives me a context error
Operator bpy.ops.palette.extract_from_image.poll() failed, context is incorrect

I tried setting the area with

bpy.context.area.type='IMAGE_EDITOR'
bpy.ops.palette.extract_from_image(threshold=10)

But still get the same context error.

$\endgroup$

1 Answer 1

7
$\begingroup$

Your question actually has two parts. How one can override the operator, and how one can set the number of colors in the palette.

I'll answer the override part after that, but I'm afraid you cannot set a number of colors in the palette in the manner you're looking for, at least not using this operator.

You'll need to override the operator area.

TLDR :

import bpy

try:  # Assume we have an image editor open and an image is selected
    image_area = next(a for a in bpy.context.screen.areas if a.type == "IMAGE_EDITOR")
    with bpy.context.temp_override(area=area):
        bpy.ops.palette.extract_from_image(threshold=10)    
except StopIteration:  # We don't have an opened image editor
    image = bpy.data.images["MyImageName.PNG"]  # This is case sensitive !
    area = bpy.context.screen.areas[0]
    old_type = area.type  # Store the overriden area type to set it back later
    area.type = "IMAGE_EDITOR"
    area.spaces[0].image = image  # This is what you missed in your override
    with bpy.context.temp_override(area=area):
        bpy.ops.palette.extract_from_image(threshold=10)    
    area.type = old_type  # Restore the area type

Details :

I will try to explain as best as I can without being too technical since the next part will contain C code. Understanding these two lines of code will help you know how you should structure your override :

SpaceImage *sima = CTX_wm_space_image(C);

CTX_wm_space_image is defined like so :

struct SpaceImage *CTX_wm_space_image(const bContext *C)
{
  ScrArea *area = CTX_wm_area(C);
  if (area && area->spacetype == SPACE_IMAGE) {
    return area->spacedata.first;
  }
  return NULL;
}

CTX_wm_area is defined like so :

ScrArea *CTX_wm_area(const bContext *C)
{
  return ctx_wm_python_context_get(C, "area", &RNA_Area, C->wm.area);
}

This means the override you provide should have a key named "area" of type SPACE_IMAGE (which is "IMAGE_EDITOR" in python)

Image *image = sima->image;

This means your image editor's space should have its attribute image set to the image you want to create the palette for.

You should also note that the threshold parameter is not really a straightforward number of palette items :

It's used to fine tune how many colors will be exported in relation to how different they are from each other. Lower values will yield lower number of palette items.

const int range = (int)pow(10.0f, threshold);
    for (int row = 0; row < ibuf->y; row++) {
      for (int col = 0; col < ibuf->x; col++) {
        float color[4];
        IMB_sampleImageAtLocation(ibuf, (float)col, (float)row, false, color);
        for (int i = 0; i < 3; i++) {
          color[i] = truncf(color[i] * range) / range;
        }

        uint key = rgb_to_cpack(color[0], color[1], color[2]);
        if (!BLI_ghash_haskey(color_table, POINTER_FROM_INT(key))) {
          BLI_ghash_insert(color_table, POINTER_FROM_INT(key), POINTER_FROM_INT(key));
        }
      }
    }
$\endgroup$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .