コード例 #1
0
ファイル: color.cpp プロジェクト: RobertLowe/aseprite
int Color::getBlue() const
{
  switch (getType()) {

    case Color::MaskType:
      return 0;

    case Color::RgbType:
      return m_value.rgb.b;

    case Color::HsvType:
      return Rgb(Hsv(m_value.hsv.h,
                     double(m_value.hsv.s) / 100.0,
                     double(m_value.hsv.v) / 100.0)).blue();

    case Color::GrayType:
      return m_value.gray;

    case Color::IndexType: {
      int i = m_value.index;
      ASSERT(i >= 0 && i < get_current_palette()->size());

      return _rgba_getb(get_current_palette()->getEntry(i));
    }

  }

  ASSERT(false);
  return -1;
}
コード例 #2
0
ファイル: color.cpp プロジェクト: RobertLowe/aseprite
int Color::getGray() const
{
  switch (getType()) {

    case Color::MaskType:
      return 0;

    case Color::RgbType:
      return 255 * Hsv(Rgb(m_value.rgb.r,
                           m_value.rgb.g,
                           m_value.rgb.b)).valueInt() / 100;

    case Color::HsvType:
      return 255 * m_value.hsv.v / 100;

    case Color::GrayType:
      return m_value.gray;

    case Color::IndexType: {
      int i = m_value.index;
      ASSERT(i >= 0 && i < get_current_palette()->size());

      uint32_t c = get_current_palette()->getEntry(i);

      return 255 * Hsv(Rgb(_rgba_getr(c),
                           _rgba_getg(c),
                           _rgba_getb(c))).valueInt() / 100;
    }

  }

  ASSERT(false);
  return -1;
}
コード例 #3
0
ファイル: color_shades.cpp プロジェクト: webbie1887/aseprite
doc::Remap* ColorShades::createShadeRemap(bool left)
{
  base::UniquePtr<doc::Remap> remap;
  Shade colors = getShade();

  // We need two or more colors to create a shading remap. In
  // other case, the ShadingInkProcessing will use the full
  // color palette.
  if (colors.size() > 1) {
    remap.reset(new doc::Remap(get_current_palette()->size()));

    for (int i=0; i<remap->size(); ++i)
      remap->map(i, i);

    if (left) {
      for (int i=1; i<int(colors.size()); ++i)
        remap->map(colors[i].getIndex(), colors[i-1].getIndex());
    }
    else {
      for (int i=0; i<int(colors.size())-1; ++i)
        remap->map(colors[i].getIndex(), colors[i+1].getIndex());
    }
  }

  return remap.release();
}
コード例 #4
0
ファイル: cmd_change_color.cpp プロジェクト: 4144/aseprite
void ChangeColorCommand::onExecute(Context* context)
{
  ColorBar* colorbar = ColorBar::instance();
  app::Color color = m_background ? colorbar->getBgColor():
                                    colorbar->getFgColor();

  switch (m_change) {
    case None:
      // do nothing
      break;
    case IncrementIndex:
      if (color.getType() == app::Color::IndexType) {
        int index = color.getIndex();
        if (index < get_current_palette()->size()-1)
          color = app::Color::fromIndex(index+1);
      }
      else
        color = app::Color::fromIndex(0);
      break;
    case DecrementIndex:
      if (color.getType() == app::Color::IndexType) {
        int index = color.getIndex();
        if (index > 0)
          color = app::Color::fromIndex(index-1);
      }
      else
        color = app::Color::fromIndex(0);
      break;
  }

  if (m_background)
    colorbar->setBgColor(color);
  else
    colorbar->setFgColor(color);
}
コード例 #5
0
ファイル: color_utils.cpp プロジェクト: DocHoncho/aseprite
int color_utils::color_for_allegro(const app::Color& color, int depth)
{
  int c = -1;

  switch (color.getType()) {

    case app::Color::MaskType:
      c = get_mask_for_bitmap(depth);
      break;

    case app::Color::RgbType:
    case app::Color::HsvType:
      c = makeacol_depth(depth,
                         color.getRed(),
                         color.getGreen(),
                         color.getBlue(), 255);
      break;

    case app::Color::GrayType:
      c = color.getGray();
      if (depth != 8)
        c = makeacol_depth(depth, c, c, c, 255);
      break;

    case app::Color::IndexType:
      c = color.getIndex();
      if (depth != 8) {
        ASSERT(c >= 0 && c < (int)get_current_palette()->size());

        uint32_t _c = get_current_palette()->getEntry(c);
        c = makeacol_depth(depth,
                           rgba_getr(_c),
                           rgba_getg(_c),
                           rgba_getb(_c), 255);
      }
      break;

  }

  return c;
}
コード例 #6
0
ファイル: color_shades.cpp プロジェクト: webbie1887/aseprite
int ColorShades::size() const
{
  int colors = 0;
  for (const auto& color : m_shade) {
    if ((color.getIndex() >= 0 &&
         color.getIndex() < get_current_palette()->size()) ||
        (m_click == ClickWholeShade)) {
      ++colors;
    }
  }
  return colors;
}
コード例 #7
0
ファイル: color.cpp プロジェクト: RobertLowe/aseprite
// Returns false only if the color is a index and it is outside the
// valid range (outside the maximum number of colors in the current
// palette)
bool Color::isValid() const
{
  switch (getType()) {

    case Color::IndexType: {
      int i = m_value.index;
      return (i >= 0 && i < get_current_palette()->size());
    }

  }
  return true;
}
コード例 #8
0
ファイル: color_utils.cpp プロジェクト: DocHoncho/aseprite
ui::Color color_utils::color_for_ui(const app::Color& color)
{
  ui::Color c = ui::ColorNone;

  switch (color.getType()) {

    case app::Color::MaskType:
      c = ui::ColorNone;
      break;

    case app::Color::RgbType:
    case app::Color::HsvType:
      c = ui::rgba(color.getRed(),
                   color.getGreen(),
                   color.getBlue(), 255);
      break;

    case app::Color::GrayType:
      c = ui::rgba(color.getGray(),
                   color.getGray(),
                   color.getGray(), 255);
      break;

    case app::Color::IndexType: {
      int i = color.getIndex();
      ASSERT(i >= 0 && i < (int)get_current_palette()->size());

      uint32_t _c = get_current_palette()->getEntry(i);
      c = ui::rgba(rgba_getr(_c),
                   rgba_getg(_c),
                   rgba_getb(_c), 255);
      break;
    }

  }

  return c;
}
コード例 #9
0
ファイル: color_selector.cpp プロジェクト: optigon/aseprite
void ColorSelector::findBestfitIndex(const Color& color)
{
  // Find bestfit palette entry
  int r = color.getRed();
  int g = color.getGreen();
  int b = color.getBlue();

  // Search for the closest color to the RGB values
  int i = get_current_palette()->findBestfit(r, g, b);
  if (i >= 0 && i < 256) {
    m_colorPalette.clearSelection();
    m_colorPalette.selectColor(i);
  }
}
コード例 #10
0
ファイル: color_shades.cpp プロジェクト: webbie1887/aseprite
Shade ColorShades::getShade() const
{
  Shade colors;
  for (const auto& color : m_shade) {
    if ((color.getIndex() >= 0 &&
         color.getIndex() < get_current_palette()->size()) ||
        (m_click == ClickWholeShade)) {
      colors.push_back(color);
    }
    else if (m_click == ClickEntries)
      colors.push_back(color);
  }
  return colors;
}
コード例 #11
0
ファイル: palette_view.cpp プロジェクト: optigon/aseprite
Color PaletteView::getColorByPosition(int target_x, int target_y)
{
  Palette* palette = get_current_palette();
  JRect cpos = jwidget_get_child_rect(this);
  div_t d = div(Palette::MaxColors, m_columns);
  int cols = m_columns;
  int rows = d.quot + ((d.rem)? 1: 0);
  int req_w, req_h;
  int x, y, u, v;
  int c;

  request_size(&req_w, &req_h);

  y = cpos->y1;
  c = 0;

  for (v=0; v<rows; v++) {
    x = cpos->x1;

    for (u=0; u<cols; u++) {
      if (c >= palette->size())
        break;

      if ((target_x >= x) && (target_x <= x+m_boxsize) &&
          (target_y >= y) && (target_y <= y+m_boxsize))
        return Color::fromIndex(c);

      x += m_boxsize+this->child_spacing;
      c++;
    }

    y += m_boxsize+this->child_spacing;
  }

  jrect_free(cpos);
  return Color::fromMask();
}
コード例 #12
0
void ColorQuantizationCommand::onExecute(Context* context)
{
  try {
    ContextWriter writer(UIContext::instance(), 500);
    Sprite* sprite = writer.sprite();
    frame_t frame = writer.frame();
    if (sprite) {
      PalettePicks entries;
      ColorBar::instance()->getPaletteView()->getSelectedEntries(entries);

      entries.pickAllIfNeeded();
      int n = entries.picks();

      Palette palette(frame, n);
      render::create_palette_from_rgb(sprite, frame, &palette);

      Palette newPalette(*get_current_palette());

      int i = 0, j = 0;
      for (bool state : entries) {
        if (state)
          newPalette.setEntry(i, palette.getEntry(j++));
        ++i;
      }

      Transaction transaction(writer.context(), "Color Quantization", ModifyDocument);
      transaction.execute(new cmd::SetPalette(sprite, frame, &newPalette));
      transaction.commit();

      set_current_palette(&newPalette, false);
      ui::Manager::getDefault()->invalidate();
    }
  }
  catch (base::Exception& e) {
    Console::showException(e);
  }
}
コード例 #13
0
ファイル: color_utils.cpp プロジェクト: DocHoncho/aseprite
raster::color_t color_utils::color_for_image(const app::Color& color, PixelFormat format)
{
  if (color.getType() == app::Color::MaskType)
    return 0;

  raster::color_t c = -1;

  switch (format) {
    case IMAGE_RGB:
      c = rgba(color.getRed(), color.getGreen(), color.getBlue(), 255);
      break;
    case IMAGE_GRAYSCALE:
      c = graya(color.getGray(), 255);
      break;
    case IMAGE_INDEXED:
      if (color.getType() == app::Color::IndexType)
        c = color.getIndex();
      else
        c = get_current_palette()->findBestfit(color.getRed(), color.getGreen(), color.getBlue());
      break;
  }

  return c;
}
コード例 #14
0
void ColorQuantizationCommand::onExecute(Context* context)
{
  try {
    app::gen::PaletteFromSprite window;
    PalettePicks entries;

    Sprite* sprite;
    frame_t frame;
    Palette* curPalette;
    {
      ContextReader reader(context);
      Site site = context->activeSite();
      sprite = site.sprite();
      frame = site.frame();
      curPalette = sprite->palette(frame);

      window.newPalette()->setSelected(true);
      window.alphaChannel()->setSelected(
        App::instance()->preferences().quantization.withAlpha());
      window.ncolors()->setText("256");

      ColorBar::instance()->getPaletteView()->getSelectedEntries(entries);
      if (entries.picks() > 1) {
        window.currentRange()->setTextf(
          "%s, %d color(s)",
          window.currentRange()->text().c_str(),
          entries.picks());
      }
      else
        window.currentRange()->setEnabled(false);

      window.currentPalette()->setTextf(
        "%s, %d color(s)",
        window.currentPalette()->text().c_str(),
        curPalette->size());
    }

    window.openWindowInForeground();
    if (window.closer() != window.ok())
      return;

    bool withAlpha = window.alphaChannel()->isSelected();
    App::instance()->preferences().quantization.withAlpha(withAlpha);

    bool createPal = false;
    if (window.newPalette()->isSelected()) {
      int n = window.ncolors()->textInt();
      n = MAX(1, n);
      entries = PalettePicks(n);
      entries.all();
      createPal = true;
    }
    else if (window.currentPalette()->isSelected()) {
      entries.all();
    }
    if (entries.picks() == 0)
      return;

    Palette tmpPalette(frame, entries.picks());
    ColorQuantizationJob job(sprite, withAlpha, &tmpPalette);
    job.startJob();
    job.waitJob();
    if (job.isCanceled())
      return;

    base::UniquePtr<Palette> newPalette(
      new Palette(createPal ? tmpPalette:
                              *get_current_palette()));

    if (createPal) {
      entries = PalettePicks(newPalette->size());
      entries.all();
    }

    int i = 0, j = 0;
    for (bool state : entries) {
      if (state)
        newPalette->setEntry(i, tmpPalette.getEntry(j++));
      ++i;
    }

    if (*curPalette != *newPalette) {
      ContextWriter writer(UIContext::instance(), 500);
      Transaction transaction(writer.context(), "Color Quantization", ModifyDocument);
      transaction.execute(new cmd::SetPalette(sprite, frame, newPalette.get()));
      transaction.commit();

      set_current_palette(newPalette.get(), false);
      ui::Manager::getDefault()->invalidate();
    }
  }
  catch (base::Exception& e) {
    Console::showException(e);
  }
}
コード例 #15
0
ファイル: cmd_add_color.cpp プロジェクト: aseprite/aseprite
void AddColorCommand::onExecute(Context* ctx)
{
  app::Color appColor;

  switch (m_source) {
    case Source::Fg:
      appColor = ColorBar::instance()->getFgColor();
      break;
    case Source::Bg:
      appColor = ColorBar::instance()->getBgColor();
      break;
    case Source::Color:
      appColor = m_color;
      break;
  }

  try {
    Palette* newPalette = get_current_palette(); // System current pal
    color_t color = doc::rgba(
      appColor.getRed(),
      appColor.getGreen(),
      appColor.getBlue(),
      appColor.getAlpha());
    int index = newPalette->findExactMatch(
      appColor.getRed(),
      appColor.getGreen(),
      appColor.getBlue(),
      appColor.getAlpha(), -1);

    // It should be -1, because the user has pressed the warning
    // button that is available only when the color isn't in the
    // palette.
    ASSERT(index < 0);
    if (index >= 0)
      return;

    ContextWriter writer(ctx, 500);
    Doc* document(writer.document());
    Sprite* sprite = writer.sprite();
    if (!document || !sprite) {
      ASSERT(false);
      return;
    }

    newPalette->addEntry(color);
    index = newPalette->size()-1;

    if (document) {
      frame_t frame = writer.frame();

      Tx tx(writer.context(), friendlyName(), ModifyDocument);
      tx(new cmd::SetPalette(sprite, frame, newPalette));
      tx.commit();
    }

    set_current_palette(newPalette, true);
    ui::Manager::getDefault()->invalidate();
  }
  catch (base::Exception& e) {
    Console::showException(e);
  }
}
コード例 #16
0
ファイル: color.cpp プロジェクト: RobertLowe/aseprite
std::string Color::toHumanReadableString(PixelFormat pixelFormat, HumanReadableString humanReadable) const
{
  std::stringstream result;

  if (humanReadable == LongHumanReadableString) {
    switch (getType()) {

      case Color::MaskType:
        result << "Mask";
        break;

      case Color::RgbType:
        if (pixelFormat == IMAGE_GRAYSCALE) {
          result << "Gray " << getGray();
        }
        else {
          result << "RGB "
                 << m_value.rgb.r << " "
                 << m_value.rgb.g << " "
                 << m_value.rgb.b;

          if (pixelFormat == IMAGE_INDEXED)
            result << " Index "
                   << color_utils::color_for_image(*this, pixelFormat);
        }
        break;

      case Color::HsvType:
        if (pixelFormat == IMAGE_GRAYSCALE) {
          result << "Gray " << getGray();
        }
        else {
          result << "HSB "
                 << m_value.hsv.h << "\xB0 "
                 << m_value.hsv.s << " "
                 << m_value.hsv.v;

          if (pixelFormat == IMAGE_INDEXED)
            result << " Index " << color_utils::color_for_image(*this, pixelFormat);
        }
        break;

      case Color::GrayType:
        result << "Gray " << m_value.gray;
        break;

      case Color::IndexType: {
        int i = m_value.index;
        if (i >= 0 && i < (int)get_current_palette()->size()) {
          uint32_t _c = get_current_palette()->getEntry(i);
          result << "Index " << i
                 << " (RGB "
                 << (int)_rgba_getr(_c) << " "
                 << (int)_rgba_getg(_c) << " "
                 << (int)_rgba_getb(_c) << ")";
        }
        else {
          result << "Index "
                 << i
                 << " (out of range)";
        }
        break;
      }

      default:
        ASSERT(false);
        break;
    }
  }
  else if (humanReadable == ShortHumanReadableString) {
    switch (getType()) {

      case Color::MaskType:
        result << "Mask";
        break;

      case Color::RgbType:
        if (pixelFormat == IMAGE_GRAYSCALE) {
          result << "Gry-" << getGray();
        }
        else {
          result << "#" << std::hex << std::setfill('0')
                 << std::setw(2) << m_value.rgb.r
                 << std::setw(2) << m_value.rgb.g
                 << std::setw(2) << m_value.rgb.b;
        }
        break;

      case Color::HsvType:
        if (pixelFormat == IMAGE_GRAYSCALE) {
          result << "Gry-" << getGray();
        }
        else {
          result << m_value.hsv.h << "\xB0"
                 << m_value.hsv.s << ","
                 << m_value.hsv.v;
        }
        break;

      case Color::GrayType:
        result << "Gry-" << m_value.gray;
        break;

      case Color::IndexType:
        result << "Idx-" << m_value.index;
        break;

      default:
        ASSERT(false);
        break;
    }
  }

  return result.str();
}
コード例 #17
0
ファイル: palette_view.cpp プロジェクト: optigon/aseprite
bool PaletteView::onProcessMessage(Message* msg)
{
  switch (msg->type) {

    case JM_REQSIZE:
      request_size(&msg->reqsize.w, &msg->reqsize.h);
      return true;

    case JM_DRAW: {
      div_t d = div(Palette::MaxColors, m_columns);
      int cols = m_columns;
      int rows = d.quot + ((d.rem)? 1: 0);
      int x, y, u, v;
      int c, color;
      BITMAP *bmp;
      Palette* palette = get_current_palette();
      int bordercolor = makecol(255, 255, 255);

      bmp = create_bitmap(jrect_w(this->rc), jrect_h(this->rc));
      clear_to_color(bmp, makecol(0 , 0, 0));

      y = this->border_width.t;
      c = 0;

      for (v=0; v<rows; v++) {
        x = this->border_width.l;

        for (u=0; u<cols; u++) {
          if (c >= palette->size())
            break;

          if (bitmap_color_depth(ji_screen) == 8)
            color = c;
          else
            color = makecol_depth
              (bitmap_color_depth(ji_screen),
               _rgba_getr(palette->getEntry(c)),
               _rgba_getg(palette->getEntry(c)),
               _rgba_getb(palette->getEntry(c)));

          rectfill(bmp, x, y, x+m_boxsize-1, y+m_boxsize-1, color);

          if (m_selectedEntries[c]) {
            const int max = Palette::MaxColors;
            bool top    = (c >= m_columns            && c-m_columns >= 0  ? m_selectedEntries[c-m_columns]: false);
            bool bottom = (c < max-m_columns         && c+m_columns < max ? m_selectedEntries[c+m_columns]: false);
            bool left   = ((c%m_columns)>0           && c-1         >= 0  ? m_selectedEntries[c-1]: false);
            bool right  = ((c%m_columns)<m_columns-1 && c+1         < max ? m_selectedEntries[c+1]: false);

            if (!top) hline(bmp, x-1, y-1, x+m_boxsize, bordercolor);
            if (!bottom) hline(bmp, x-1, y+m_boxsize, x+m_boxsize, bordercolor);
            if (!left) vline(bmp, x-1, y-1, y+m_boxsize, bordercolor);
            if (!right) vline(bmp, x+m_boxsize, y-1, y+m_boxsize, bordercolor);
          }

          x += m_boxsize+this->child_spacing;
          c++;
        }

        y += m_boxsize+this->child_spacing;
      }

      blit(bmp, ji_screen,
           0, 0, this->rc->x1, this->rc->y1, bmp->w, bmp->h);
      destroy_bitmap(bmp);
      return true;
    }

    case JM_BUTTONPRESSED:
      captureMouse();
      /* continue... */

    case JM_MOTION: {
      JRect cpos = jwidget_get_child_rect(this);

      int req_w, req_h;
      request_size(&req_w, &req_h);

      int mouse_x = MID(cpos->x1, msg->mouse.x, cpos->x1+req_w-this->border_width.r-1);
      int mouse_y = MID(cpos->y1, msg->mouse.y, cpos->y1+req_h-this->border_width.b-1);

      jrect_free(cpos);

      Color color = getColorByPosition(mouse_x, mouse_y);
      if (color.getType() == Color::IndexType) {
        int idx = color.getIndex();

        app_get_statusbar()->showColor(0, "", color, 255);

        if (hasCapture() && idx != m_currentEntry) {
          if (!(msg->any.shifts & KB_CTRL_FLAG))
            clearSelection();

          if (msg->any.shifts & KB_SHIFT_FLAG)
            selectRange(m_rangeAnchor, idx);
          else
            selectColor(idx);

          // Emit signals
          jwidget_emit_signal(this, SIGNAL_PALETTE_EDITOR_CHANGE);
          IndexChange(idx);
        }
      }

      if (hasCapture())
        return true;

      break;
    }

    case JM_BUTTONRELEASED:
      releaseMouse();
      return true;

    case JM_WHEEL: {
      View* view = View::getView(this);
      if (view) {
        gfx::Point scroll = view->getViewScroll();
        scroll.y += (jmouse_z(1)-jmouse_z(0)) * 3 * m_boxsize;
        view->setViewScroll(scroll);
      }
      break;
    }

    case JM_MOUSELEAVE:
      app_get_statusbar()->clearText();
      break;

  }

  return Widget::onProcessMessage(msg);
}
コード例 #18
0
void ColorQuantizationCommand::onExecute(Context* context)
{
  try {
    app::gen::PaletteFromSprite window;
    PalettePicks entries;

    Sprite* sprite;
    frame_t frame;
    Palette* curPalette;
    {
      ContextReader reader(context);
      Site site = context->activeSite();
      sprite = site.sprite();
      frame = site.frame();
      curPalette = sprite->palette(frame);

      window.newPalette()->setSelected(true);
      window.alphaChannel()->setSelected(
        App::instance()->preferences().quantization.withAlpha());
      window.ncolors()->setText("256");

      ColorBar::instance()->getPaletteView()->getSelectedEntries(entries);
      if (entries.picks() > 1) {
        window.currentRange()->setTextf(
          "%s, %d color(s)",
          window.currentRange()->text().c_str(),
          entries.picks());
      }
      else
        window.currentRange()->setEnabled(false);

      window.currentPalette()->setTextf(
        "%s, %d color(s)",
        window.currentPalette()->text().c_str(),
        curPalette->size());
    }

    window.openWindowInForeground();
    if (window.closer() != window.ok())
      return;

    bool withAlpha = window.alphaChannel()->isSelected();
    App::instance()->preferences().quantization.withAlpha(withAlpha);

    bool createPal = false;
    if (window.newPalette()->isSelected()) {
      int n = window.ncolors()->textInt();
      n = MAX(1, n);
      entries = PalettePicks(n);
      entries.all();
      createPal = true;
    }
    else if (window.currentPalette()->isSelected()) {
      entries.all();
    }
    if (entries.picks() == 0)
      return;

    Palette tmpPalette(frame, entries.picks());

    ContextReader reader(context);
    SpriteJob job(reader, "Color Quantization");
    const bool newBlend = Preferences::instance().experimental.newBlend();
    job.startJobWithCallback(
      [sprite, withAlpha, &tmpPalette, &job, newBlend]{
        render::create_palette_from_sprite(
          sprite, 0, sprite->lastFrame(),
          withAlpha, &tmpPalette,
          &job,
          newBlend);     // SpriteJob is a render::TaskDelegate
      });
    job.waitJob();
    if (job.isCanceled())
      return;

    std::unique_ptr<Palette> newPalette(
      new Palette(createPal ? tmpPalette:
                              *get_current_palette()));

    if (createPal) {
      entries = PalettePicks(newPalette->size());
      entries.all();
    }

    int i = 0, j = 0;
    for (bool state : entries) {
      if (state)
        newPalette->setEntry(i, tmpPalette.getEntry(j++));
      ++i;
    }

    if (*curPalette != *newPalette)
      job.tx()(new cmd::SetPalette(sprite, frame, newPalette.get()));

    set_current_palette(newPalette.get(), false);
    ui::Manager::getDefault()->invalidate();
  }
  catch (const base::Exception& e) {
    Console::showException(e);
  }
}
コード例 #19
0
ファイル: cmd_new_file.cpp プロジェクト: imeteora/aseprite
/**
 * Shows the "New Sprite" dialog.
 */
void NewFileCommand::onExecute(Context* context)
{
  Preferences& pref = Preferences::instance();
  int ncolors = get_default_palette()->size();
  char buf[1024];
  app::Color bg_table[] = {
    app::Color::fromMask(),
    app::Color::fromRgb(255, 255, 255),
    app::Color::fromRgb(0, 0, 0),
  };

  // Load the window widget
  app::gen::NewSprite window;

  // Default values: Indexed, 320x240, Background color
  PixelFormat format = pref.newFile.colorMode();
  // Invalid format in config file.
  if (format != IMAGE_RGB &&
      format != IMAGE_INDEXED &&
      format != IMAGE_GRAYSCALE) {
    format = IMAGE_INDEXED;
  }
  int w = pref.newFile.width();
  int h = pref.newFile.height();
  int bg = pref.newFile.backgroundColor();
  bg = MID(0, bg, 2);

  // If the clipboard contains an image, we can show the size of the
  // clipboard as default image size.
  gfx::Size clipboardSize;
  if (clipboard::get_image_size(clipboardSize)) {
    w = clipboardSize.w;
    h = clipboardSize.h;
  }

  window.width()->setTextf("%d", MAX(1, w));
  window.height()->setTextf("%d", MAX(1, h));

  // Select image-type
  window.colorMode()->setSelectedItem(format);

  // Select background color
  window.bgColor()->setSelectedItem(bg);

  // Advance options
  bool advanced = pref.newFile.advanced();
  window.advancedCheck()->setSelected(advanced);
  window.advancedCheck()->Click.connect(
    base::Bind<void>(
      [&]{
        gfx::Rect bounds = window.bounds();
        window.advanced()->setVisible(window.advancedCheck()->isSelected());
        window.setBounds(gfx::Rect(window.bounds().origin(),
                                   window.sizeHint()));
        window.layout();

        window.manager()->invalidateRect(bounds);
      }));
  window.advanced()->setVisible(advanced);
  if (advanced)
    window.pixelRatio()->setValue(pref.newFile.pixelRatio());
  else
    window.pixelRatio()->setValue("1:1");

  // Open the window
  window.openWindowInForeground();

  if (window.closer() == window.okButton()) {
    bool ok = false;

    // Get the options
    format = (doc::PixelFormat)window.colorMode()->selectedItem();
    w = window.width()->textInt();
    h = window.height()->textInt();
    bg = window.bgColor()->selectedItem();

    static_assert(IMAGE_RGB == 0, "RGB pixel format should be 0");
    static_assert(IMAGE_INDEXED == 2, "Indexed pixel format should be 2");

    format = MID(IMAGE_RGB, format, IMAGE_INDEXED);
    w = MID(1, w, DOC_SPRITE_MAX_WIDTH);
    h = MID(1, h, DOC_SPRITE_MAX_HEIGHT);
    bg = MID(0, bg, 2);

    // Select the color
    app::Color color = app::Color::fromMask();

    if (bg >= 0 && bg <= 3) {
      color = bg_table[bg];
      ok = true;
    }

    if (ok) {
      // Save the configuration
      pref.newFile.width(w);
      pref.newFile.height(h);
      pref.newFile.colorMode(format);
      pref.newFile.backgroundColor(bg);
      pref.newFile.advanced(window.advancedCheck()->isSelected());
      pref.newFile.pixelRatio(window.pixelRatio()->getValue());

      // Create the new sprite
      ASSERT(format == IMAGE_RGB || format == IMAGE_GRAYSCALE || format == IMAGE_INDEXED);
      ASSERT(w > 0 && h > 0);

      std::unique_ptr<Sprite> sprite(Sprite::createBasicSprite(format, w, h, ncolors));

      if (window.advancedCheck()->isSelected()) {
        sprite->setPixelRatio(
          base::convert_to<PixelRatio>(window.pixelRatio()->getValue()));
      }

      if (sprite->pixelFormat() != IMAGE_GRAYSCALE)
        get_default_palette()->copyColorsTo(sprite->palette(frame_t(0)));

      // If the background color isn't transparent, we have to
      // convert the `Layer 1' in a `Background'
      if (color.getType() != app::Color::MaskType) {
        Layer* layer = sprite->root()->firstLayer();

        if (layer && layer->isImage()) {
          LayerImage* layerImage = static_cast<LayerImage*>(layer);
          layerImage->configureAsBackground();

          Image* image = layerImage->cel(frame_t(0))->image();

          // TODO Replace this adding a new parameter to color utils
          Palette oldPal = *get_current_palette();
          set_current_palette(get_default_palette(), false);

          doc::clear_image(image,
            color_utils::color_for_target(color,
              ColorTarget(
                ColorTarget::BackgroundLayer,
                sprite->pixelFormat(),
                sprite->transparentColor())));

          set_current_palette(&oldPal, false);
        }
      }

      // Show the sprite to the user
      std::unique_ptr<Doc> doc(new Doc(sprite.get()));
      sprite.release();
      sprintf(buf, "Sprite-%04d", ++_sprite_counter);
      doc->setFilename(buf);
      doc->setContext(context);
      doc.release();
    }
  }
}