Модераторы: LSD, AntonSaburov
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> GradientPaint and smoothing, Как вывести ПЛАВНЫЙ градиент 
:(
    Опции темы
Гость_carper
Дата 31.10.2005, 18:04 (ссылка)    |    (голосов: 0) Загрузка ... Загрузка ... Быстрая цитата Цитата


Unregistered











Есть такой простой код:

Код

import javax.swing.*;
import java.awt.*;

/**
 * Градиентная панель.
 */
public class JPanelGradient extends JPanel {
  Color startColor, endColor;

  protected void paintComponent(Graphics g) {
    startColor= new Color(225,225,225); //Временная заглушка для упрощения примера
    endColor= new Color(10,10,10); //Временная заглушка для упрощения примера
 

    Graphics2D g2 = (Graphics2D) g;
    int w = getWidth();
    int h = getHeight();

    //Не видно эффекта:  :(
    //g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);  
    UpperLeftBottomRightPaint(g2, w, h);
  }

  //Рисование градиента от верхнего угла к нижнему (наискосок).
  private void UpperLeftBottomRightPaint(Graphics2D g2, int w, int h){
    GradientPaint gradient = new GradientPaint(0, 0, startColor, w, h, endColor, false);
    //g2.setStroke(new BasicStroke(1)); Не видно эффекта
    g2.setPaint(gradient);
    g2.fillRect(0, 0, w, h);
  }
}


Собственно все рисуется без проблем, однако видны линии на переходах цветов, что довольно некрасиво.

Можно ли гарантировано избавиться от этого эффекта (на современных мониторах и видеокартах, разумеется) ?
По крайней мере, компоненты Delphi рисуют градиенты на этом же мониторе в нормальном виде.

Я что-то делаю не так или надо рисовать на панели самому, не полагаясь на GradientPaint?
Если даже и так, то где найти пример реализации такого алгоритма?

  Вверх
LSD
Дата 31.10.2005, 18:44 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Leprechaun Software Developer
****


Профиль
Группа: Модератор
Сообщений: 15718
Регистрация: 24.3.2004
Где: Dublin

Репутация: 38
Всего: 538



Ты уверен, что дело не в мониторе. При просмотре на CRT все нормально, а на LCD наблюдаются "ступеньки", но это уже проблема монитора.

Присоединённый файл ( Кол-во скачиваний: 26 )
Присоединённый файл  Gradient.png 22,01 Kb


--------------------
Disclaimer: this post contains explicit depictions of personal opinion. So, if it sounds sarcastic, don't take it seriously. If it sounds dangerous, do not try this at home or at all. And if it offends you, just don't read it.
PM MAIL WWW   Вверх
carper
Дата 1.11.2005, 10:02 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 227
Регистрация: 2.3.2005

Репутация: 4
Всего: 8



Цитата(LSD @ 31.10.2005, 18:44)
Ты уверен, что дело не в мониторе


Монитор CRT - Sony Multiscan G400.

Твоя картинка смотрится нормально, но если поднастроить по шкале серого в режим "рисования", то и тут появляются слегка заметные полосы в левом нижнем углу шириной около сантиметра.

Тут есть нюанс, если поиграться цветом (как самим цветом, так и диапазоном) то полос почти не видно, зато, если выставить дипазон просто от Color.GRAY до Color.DARK_GRAY, видны полосы шириной около 8мм (хорошо заметные в светлой части "спектра"). Разумеется не так отчетливо, как полосит градиент на плохих LCD, но все же видно.
Поигравшись яркостью и контрастом их можно почти убрать, да и качество самого монитора мне по барабану.
Неприятно только то, что другие градиенты (например, созданные в том же Photoshop) на этом же мониторе не требуют таких манипуляций и смотрятся абсолютно плавными.

Отсюда вывод- похоже, что станадартный алгоритм не предусматривает необходимого для визуальной плавности взаимопроникновения тонов. Просто тупо заливает полосу за полосой. Чем дипазон больше, тем кол-во полос больше и их труднее заметить, но на хорошем мониторе все равно заметно. Можно было бы и смириться, но уж больно бросается в глаза попсовость получаемого фона.

Похоже, что проблема все же решается только ручками, но у меня художественные навыки не настолько хорошо развиты, чтобы понять какой алгоритм надо использовать. Понятно, что надо делать blur, но как? smile


PM MAIL   Вверх
LSD
Дата 1.11.2005, 13:39 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Leprechaun Software Developer
****


Профиль
Группа: Модератор
Сообщений: 15718
Регистрация: 24.3.2004
Где: Dublin

Репутация: 38
Всего: 538



Как ни бейся но получить на обычном мониторе больше 256 градаций серого нельзя. Если уж тебе так интерестно чем отличается картинка созданная фотошопом от созданной Java. Создай BufferedImage, заполни его градиентом и сохрани как PNG, затем создай такой же рисунок в фотошопе, и наложи эти два рисунка друг на друга в режиме Difference.


--------------------
Disclaimer: this post contains explicit depictions of personal opinion. So, if it sounds sarcastic, don't take it seriously. If it sounds dangerous, do not try this at home or at all. And if it offends you, just don't read it.
PM MAIL WWW   Вверх
carper
Дата 1.11.2005, 16:42 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 227
Регистрация: 2.3.2005

Репутация: 4
Всего: 8



LSD
Я только что нашел алгоритм того как это сделать красиво на JAVA, но только для радиальной заливки. smile
Как оказалось ларчик открывался просто - дело тут совсем не в 256 градациях, а в правильном применении блюра.
Если будет интересно могу привести алгоритм (позаимствован из книги по 2D).
Но, насколько я понял эффект блюра получается там как бы автоматически из-за плавающего к-та пересчета цветов - ага, именно то, что нам и надо, т.к. сразу уходим от четких границ.
Но, увы, для обычной заливки сверху-вниз или слева-направо, такое не получается.
PM MAIL   Вверх
AntonSaburov
Дата 1.11.2005, 16:51 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Штурман
****


Профиль
Группа: Модератор
Сообщений: 5658
Регистрация: 2.7.2002
Где: Санкт-Петербург

Репутация: 10
Всего: 118



Цитата(carper @ 1.11.2005, 16:42)
Если будет интересно могу привести алгоритм (позаимствован из книги по 2D).

Конечно интересно - заливай smile
PM MAIL WWW ICQ   Вверх
carper
Дата 1.11.2005, 18:17 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 227
Регистрация: 2.3.2005

Репутация: 4
Всего: 8



AntonSaburov
OK.

Делаем раз (Здесь никакой хитрости нет) :

Код

import java.awt.*;
import java.awt.geom.*;
import java.awt.image.ColorModel;

public class RoundGradientPaint implements Paint {
  protected Point2D mPoint;
  protected Point2D mRadius;
  protected Color mPointColor, mBackgroundColor;

  public RoundGradientPaint(double x, double y, Color pointColor,
    Point2D radius, Color backgroundColor) {
    if (radius.distance(0, 0) <= 0) throw new IllegalArgumentException("Radius must be greater than 0.");
    mPoint = new Point2D.Double(x, y);
    mPointColor = pointColor;
    mRadius = radius;
    mBackgroundColor = backgroundColor;
  }

  public PaintContext createContext(ColorModel cm, Rectangle deviceBounds, Rectangle2D userBounds,
                                    AffineTransform xform, RenderingHints hints) {
    Point2D transformedPoint = xform.transform(mPoint, null);
    Point2D transformedRadius = xform.deltaTransform(mRadius, null);

    return new RoundGradientContext(transformedPoint, mPointColor, transformedRadius, mBackgroundColor);

  }

  public int getTransparency() {
    int a1 = mPointColor.getAlpha();
    int a2 = mBackgroundColor.getAlpha();
    return (((a1 & a2) == 0xff) ? OPAQUE : TRANSLUCENT);
  }
}




Делаем два:

Код

import java.awt.*;
import java.awt.geom.*;
import java.awt.image.*;

/** Рисует шарообразный градиент от центра.
     Интересный эффект постепенного пропадания цвета можно получить, если рисовать одним и тем же цветом,
     но с разной прозрачностью, например: startColor= new Color(255, 0, 0, 255);
                                          endColor=   new Color(255, 0, 0, 0);
     Кстати, с помощью этой же функции можно получить действительно плавный "обычный" градиент, например,
     при 0,0 - из левого верхнего угла в нижний правый, при 0,h - из левого нижнего угла в верхний правый.
     К сожалению, этот фокус с градиентами типа слева направо или сверху вниз не проходит.

   */

public class RoundGradientContext implements PaintContext {
  protected Point2D mPoint;
  protected Point2D mRadius;
  protected Color mC1, mC2;


  public RoundGradientContext(Point2D p, Color c1, Point2D r, Color c2) {
    mPoint = p;
    mC1 = c1;
    mRadius = r;
    mC2 = c2;
  }

  public void dispose() {}

  public ColorModel getColorModel() { return ColorModel.getRGBdefault(); }

 /* The get-Raster() method iterates over each point in the requested rectangle,
      calculating the distance from the center point.
      It calculates a weighting factor, from 0.0 to 1.0, based on the ratio of this
      distance and the radius. */

  public Raster getRaster(int x, int y, int w, int h) {
    WritableRaster raster =
        getColorModel().createCompatibleWritableRaster(w, h);

    int[] data = new int[w * h * 4]; //k=4, т.к. 3-и цвета + Alpha канал (важно не забыть и про него)

     double radius   = mRadius.distance(0, 0);
    for (int j = 0; j < h; j++) {
      for (int i = 0; i < w; i++) {
        double distance = mPoint.distance(x + i, y + j);
       // double radius   = mRadius.distance(0, 0);

       //Вот эта фигня плавает довольно сильно, поэтому-то и получаем "размытие"
       //Впрочем пока не разобрался из-за плавания или из-за просто более точного просчета
       //цвета (скорее всего сказывается и то и другое)
        double ratio    = distance/radius;

        if (ratio > 1.0){
          ratio = 1.0;
        }//if

        int base = (j * w + i) * 4;
        //it simply uses the weighting factor to linearly interpolate between the center color and the background color
        data[base] = (int)(mC1.getRed()       + ratio * (mC2.getRed() - mC1.getRed()));
        data[base + 1] = (int)(mC1.getGreen() + ratio * (mC2.getGreen() - mC1.getGreen()));
        data[base + 2] = (int)(mC1.getBlue()  + ratio * (mC2.getBlue()  - mC1.getBlue()));
        data[base + 3] = (int)(mC1.getAlpha() + ratio * (mC2.getAlpha() - mC1.getAlpha()));
      }
    }
    
    //Заполняем битовую матрицу. 
    raster.setPixels(0, 0, w, h, data);

    return raster;
  }
}




Пример использования:

Код

import javax.swing.*;
import java.awt.*;
import java.awt.geom.Point2D;

/**
 * Градиентная панель.
 */
public class JPanelGradient extends JPanel {
  Color startColor, endColor;
  Point start, end; //Координаты начальной и конечной позиций в которых рисуется градиент.

  protected void paintComponent(Graphics g) {
    startColor= new Color(225,225,225); //В нормальной реализации, разумеется, цвета надо
    //задавать хотя бы в конструкторе, зато в тестовом режиме так нагляднее и проще играться.
    endColor= new Color(10,10,10);

    Graphics2D g2 = (Graphics2D) g;
    int w = getWidth();
    int h = getHeight();

    //g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);-
   // нет толку на современной машине, по-крайней мере у меня от этой подсказки ничего не меняется

   if (start==null){
     start= new Point();
   }
   if (end==null){
     end= new Point();
   }

  
   start.x=0; start.y = 0; end.x=w; end.y=h;
    DrawRoundGradient(g2, w, h);

  }

//Это "СТАНДАРТНОЕ" РИСОВАНИЕ - оно у меня полосит
  private void DrawRectangleGradient(Graphics2D g2, int w, int h){
    /* RenderingHints qualityHints = new RenderingHints(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
    qualityHints.put(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
    g2.setRenderingHints(qualityHints); */
    GradientPaint gradient = new GradientPaint(start.x, start.y, startColor, end.x, end.y, endColor, false);

    g2.setPaint(gradient);
    g2.fillRect(0, 0, w, h);
  }

  /*  А вот это использует вышеприведенный алгоритм, IMHO разница кардинальная.
    Рисует шарообразный градиент от центра.
     Интересный эффект постепенного пропадания цвета можно получить, если рисовать одним и тем же цветом,
     но с разной прозрачностью, например: startColor= new Color(255, 0, 0, 255);
                                          endColor=   new Color(255, 0, 0, 0);
     Кстати, с помощью этой же функции можно получить действительно плавный "обычный" градиент, например,
     при 0,0 - из левого верхнего угла в нижний правый, при 0,h - из левого нижнего угла в верхний правый.
 (А теперь попробуйте ту же диагональную заливку, но с применением DrawRectangleGradient!)
     К сожалению, этот фокус с градиентами типа слева направо или сверху вниз не проходит.

   */
//Со стартовой точкой поиграйтесь сами.
     RoundGradientPaint rgp = new RoundGradientPaint(w/2, h/2, startColor, new Point2D.Double(w, h),endColor);
     g2.setPaint(rgp);
    g2.fillRect(0,0,w,h);

  }


}



Ну и фрагмент (собственно там смотреть нечего - просто создаем панель) main класса:
Код

 ....
 public static void main(String[] args){
    ....
    setDefaultLookAndFeelDecorated(true);
    StdMainFrameImpl tmp= new StdMainFrameImpl();
    tmp.setMyTitle("Градиент");
    
    tmp.setContentPane(new JPanelGradient());
    .......
    tmp.pack();
    tmp.setVisible(true);

  }

....



PM MAIL   Вверх
LSD
Дата 1.11.2005, 20:30 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Leprechaun Software Developer
****


Профиль
Группа: Модератор
Сообщений: 15718
Регистрация: 24.3.2004
Где: Dublin

Репутация: 38
Всего: 538



Я тоже поигрался немного с градиентами, создал картинку в фотошопе и Java 256x256 INT_RGB с градиентом из левого верхнего угла в правый нижний. У фотошопа явно более резкий переход на цветах приближенных к черному и белому, а на серых тонах наоборот переход сделан плавнее. Это прекрастно видно на гистограмме, у Java получилась идеальная пирамида, а у фотошопа перевернутая парабола. Т.е. он использует некий перцептивный алгоритм для улучшения восприятия человеком, а Java решает данную проблему влоб.

Можешь сам попробовать, создать градиент от черного (0, 0, 0) до белого (255, 255, 255) на рисунке 256x256 очень просто, и ты увидишь что у тебя будут те же проблемы что и у Java2D.


--------------------
Disclaimer: this post contains explicit depictions of personal opinion. So, if it sounds sarcastic, don't take it seriously. If it sounds dangerous, do not try this at home or at all. And if it offends you, just don't read it.
PM MAIL WWW   Вверх
carper
Дата 2.11.2005, 10:18 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 227
Регистрация: 2.3.2005

Репутация: 4
Всего: 8



Цитата(LSD @ 1.11.2005, 20:30)
Т.е. он использует некий перцептивный алгоритм для улучшения восприятия человеком, а Java решает данную проблему влоб.


Согласен, именно решение в лоб мне и не понравилось. Мало кому нужен градиент сам по себе (разве что для настройки монитора), градиент должен быть виден плавным человеческому глазу.

Что касается Photoshop, то совершенно верно - на дипазоне 0,0,0 - 255,255,255 он у меня тоже выдал полосатый градиент, который без труда убрался стандратным Gaussian Blur - вот этого размытия мне и не хватало.
Всякие там размытия, градиенты и прочие украшательства обычно не пихают в "деловой" интерфейс, а в презентационной части они весьма уместны, но тогда и выглядеть должны красиво, а не по-уродски.

Найденный вариант решения меня вполне устраивает, хотя он и не идеален (никаким Gaussian Blur там даже не пахнет), но IMHO с точки зрения сочетания производительность/красота картинки он весьма приятен.


P.S. Да, кстати, вышеприведенный код позволяет создавать очень интересные эффекты, если попробовать повращать полученную пиксельную матрицу. Например, без особого труда можно получить рисунок в виде объемного плетения не затрудняя себя загрузкой текстур. А с ними, вообще получаются очень красивые результаты. Но это уже скорее тянет на создание плагинов к Photoshop мне оно пока не интересно.
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Java"
LSD   AntonSaburov
powerOn   jk1
  • Прежде, чем задать вопрос, прочтите это!
  • Книги по Java собираются здесь.
  • Документация и ресурсы по Java находятся здесь.
  • Используйте теги [code=java][/code] для подсветки кода. Используйтe чекбокс "транслит", если у Вас нет русских шрифтов.
  • Помечайте свой вопрос как решённый, если на него получен ответ. Ссылка "Пометить как решённый" находится над первым постом.
  • Действия модераторов можно обсудить здесь.
  • FAQ раздела лежит здесь.

Если Вам помогли, и атмосфера форума Вам понравилась, то заходите к нам чаще! С уважением, LSD, AntonSaburov, powerOn, jk1.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Java: GUI и Java FX приложения | Следующая тема »


 




[ Время генерации скрипта: 0.0556 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.