Color wheel: Difference between revisions
(julia example) |
|||
(85 intermediate revisions by 30 users not shown) | |||
Line 1: | Line 1: | ||
{{ |
{{task|Basic language learning}} |
||
;Task: |
;Task: |
||
Write a function to draw a HSV color wheel |
Write a function to draw a [[wp:HSL_and_HSV|HSV]] color wheel completely with code. |
||
This is strictly for learning purposes only. It's highly recommended that you use an image in an actual application to actually draw the color wheel (as procedurally drawing is super slow). This does help you understand how color wheels work and this can easily be used to determine a color value based on a position within a circle. |
This is strictly for learning purposes only. It's highly recommended that you use an image in an actual application to actually draw the color wheel (as procedurally drawing is super slow). This does help you understand how color wheels work and this can easily be used to determine a color value based on a position within a circle. |
||
<br><br> |
|||
=={{header|Applesoft BASIC}}== |
|||
The lo-resolution GRaphics screen is limited to 16 colors. Ordered dithering is used for the saturation. Pink is mixed with violet and magenta, and aqua is mixed with light blue and green. These lighter colors are randomly mixed with the saturation dither. Note that the four Apple II colors can be seen at the 90 degree marks: orange at 30 degrees, green at 120 degrees, cyan (blue) at 210 degrees, and violet at 300 degrees. |
|||
<syntaxhighlight lang="gwbasic"> 100 LET R = 3.1415926535 / 180 |
|||
110 LET YO = 20 |
|||
120 LET XO = YO |
|||
130 LET MS = INT (YO * 7 / 8) |
|||
140 LET O$ = "1111111111.1111111110.1111011110.1101110110.1101010110.1010101010.0010101001.0010001001.0000100001.0000000001.0000000000" |
|||
150 GR |
|||
160 FOR S = 0 TO MS |
|||
170 LET D = S / MS |
|||
180 LET P$ = MID$ (O$, INT (D * 10) * 11 + 1,11) |
|||
190 LET SY = S |
|||
200 LET SX = S * 4 / 7 |
|||
210 LET P = 0 |
|||
220 FOR I = 0 TO 360 |
|||
230 LET X = XO + SIN (I * R) * SX |
|||
240 LET Y = YO + COS (I * R) * SY |
|||
250 LET W = 15 |
|||
260 IF I > = 30 - 22.4 AND I < 30 + 22.5 THEN COLOR= 9 |
|||
270 IF I > = 75 - 22.5 AND I < 75 + 22.5 THEN COLOR= 13 |
|||
280 IF I > = 120 - 22.5 AND I < 120 + 22.5 THEN COLOR= 12:W = 14 |
|||
290 IF I > = 165 - 22.5 AND I < 165 + 22.5 THEN COLOR= 7:W = 14 |
|||
300 IF I > = 210 - 22.5 AND I < 210 + 22.5 THEN COLOR= 6 |
|||
310 IF I > = 255 - 22.5 AND I < 255 + 22.5 THEN COLOR= 2 |
|||
320 IF I > = 300 - 22.5 AND I < 300 + 22.5 THEN COLOR= 3:W = 11 |
|||
330 IF I > = 345 - 22.5 OR I < 345 + 22.5 - 360 THEN COLOR= 1:W = 11 |
|||
340 IF D < .2 THEN W = 15 |
|||
350 IF RND (1) < D THEN W = 15 |
|||
360 IF VAL ( MID$ (P$,P + 1,1)) THEN COLOR= W |
|||
370 IF SCRN( X,Y) = 0 THEN PLOT X,Y:P = P + 1: IF P > = 9 THEN P = 0 |
|||
380 NEXT I,S</syntaxhighlight> |
|||
=={{header|AppleScript}}== |
=={{header|AppleScript}}== |
||
<syntaxhighlight lang="applescript"> |
|||
<lang AppleScript> |
|||
choose color default color {0, 0, 0, 0} |
choose color default color {0, 0, 0, 0} |
||
</syntaxhighlight> |
|||
</lang> |
|||
=={{header|C++}}== |
|||
{{libheader|Qt}} |
|||
This program draws an HSV color wheel in a window. |
|||
<syntaxhighlight lang="cpp">// colorwheelwidget.cpp |
|||
#include "colorwheelwidget.h" |
|||
#include <QPainter> |
|||
#include <QPaintEvent> |
|||
#include <cmath> |
|||
namespace { |
|||
QColor hsvToRgb(int h, double s, double v) { |
|||
double hp = h/60.0; |
|||
double c = s * v; |
|||
double x = c * (1 - std::abs(std::fmod(hp, 2) - 1)); |
|||
double m = v - c; |
|||
double r = 0, g = 0, b = 0; |
|||
if (hp <= 1) { |
|||
r = c; |
|||
g = x; |
|||
} else if (hp <= 2) { |
|||
r = x; |
|||
g = c; |
|||
} else if (hp <= 3) { |
|||
g = c; |
|||
b = x; |
|||
} else if (hp <= 4) { |
|||
g = x; |
|||
b = c; |
|||
} else if (hp <= 5) { |
|||
r = x; |
|||
b = c; |
|||
} else { |
|||
r = c; |
|||
b = x; |
|||
} |
|||
r += m; |
|||
g += m; |
|||
b += m; |
|||
return QColor(r * 255, g * 255, b * 255); |
|||
} |
|||
} |
|||
ColorWheelWidget::ColorWheelWidget(QWidget *parent) |
|||
: QWidget(parent) { |
|||
setWindowTitle(tr("Color Wheel")); |
|||
resize(400, 400); |
|||
} |
|||
void ColorWheelWidget::paintEvent(QPaintEvent *event) { |
|||
QPainter painter(this); |
|||
painter.setRenderHint(QPainter::Antialiasing); |
|||
const QColor backgroundColor(0, 0, 0); |
|||
const QColor white(255, 255, 255); |
|||
painter.fillRect(event->rect(), backgroundColor); |
|||
const int margin = 10; |
|||
const double diameter = std::min(width(), height()) - 2*margin; |
|||
QPointF center(width()/2.0, height()/2.0); |
|||
QRectF rect(center.x() - diameter/2.0, center.y() - diameter/2.0, |
|||
diameter, diameter); |
|||
for (int angle = 0; angle < 360; ++angle) { |
|||
QColor color(hsvToRgb(angle, 1.0, 1.0)); |
|||
QRadialGradient gradient(center, diameter/2.0); |
|||
gradient.setColorAt(0, white); |
|||
gradient.setColorAt(1, color); |
|||
QBrush brush(gradient); |
|||
QPen pen(brush, 1.0); |
|||
painter.setPen(pen); |
|||
painter.setBrush(brush); |
|||
painter.drawPie(rect, angle * 16, 16); |
|||
} |
|||
}</syntaxhighlight> |
|||
<syntaxhighlight lang="cpp">// colorwheelwidget.h |
|||
#ifndef COLORWHEELWIDGET_H |
|||
#define COLORWHEELWIDGET_H |
|||
#include <QWidget> |
|||
class ColorWheelWidget : public QWidget { |
|||
Q_OBJECT |
|||
public: |
|||
ColorWheelWidget(QWidget *parent = nullptr); |
|||
protected: |
|||
void paintEvent(QPaintEvent *event) override; |
|||
}; |
|||
#endif // COLORWHEELWIDGET_H</syntaxhighlight> |
|||
<syntaxhighlight lang="cpp">// main.cpp |
|||
#include "colorwheelwidget.h" |
|||
#include <QApplication> |
|||
int main(int argc, char *argv[]) { |
|||
QApplication app(argc, argv); |
|||
ColorWheelWidget widget; |
|||
widget.show(); |
|||
return app.exec(); |
|||
}</syntaxhighlight> |
|||
{{out}} |
|||
[[Media:Colorwheel cpp.png]] |
|||
=={{header|C#}}== |
|||
<syntaxhighlight lang="csharp"> |
|||
// constructor of main window |
|||
// in MainWindow.xaml just create <Image Name="imgMain" /> |
|||
public MainWindow() |
|||
{ |
|||
InitializeComponent(); |
|||
RenderOptions.SetBitmapScalingMode(imgMain, BitmapScalingMode.HighQuality); |
|||
imgMain.Source = new WriteableBitmap(480, 480, 96, 96, PixelFormats.Bgr32, null); |
|||
// using slider you can change saturation and call DrawHue with different level |
|||
DrawHue(100); |
|||
} |
|||
void DrawHue(int saturation) |
|||
{ |
|||
var bmp = (WriteableBitmap)imgMain.Source; |
|||
int centerX = (int)bmp.Width / 2; |
|||
int centerY = (int)bmp.Height / 2; |
|||
int radius = Math.Min(centerX, centerY); |
|||
int radius2 = radius - 40; |
|||
bmp.Lock(); |
|||
unsafe{ |
|||
var buf = bmp.BackBuffer; |
|||
IntPtr pixLineStart; |
|||
for(int y=0; y < bmp.Height; y++){ |
|||
pixLineStart = buf + bmp.BackBufferStride * y; |
|||
double dy = (y - centerY); |
|||
for(int x=0; x < bmp.Width; x++){ |
|||
double dx = (x - centerX); |
|||
double dist = Math.Sqrt(dx * dx + dy * dy); |
|||
if (radius2 <= dist && dist <= radius) { |
|||
double theta = Math.Atan2(dy, dx); |
|||
double hue = (theta + Math.PI) / (2.0 * Math.PI); |
|||
*((int*)(pixLineStart + x * 4)) = HSB_to_RGB((int)(hue * 360), saturation, 100); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
bmp.AddDirtyRect(new Int32Rect(0, 0, 480, 480)); |
|||
bmp.Unlock(); |
|||
} |
|||
static int HSB_to_RGB(int h, int s, int v) |
|||
{ |
|||
var rgb = new int[3]; |
|||
var baseColor = (h + 60) % 360 / 120; |
|||
var shift = (h + 60) % 360 - (120 * baseColor + 60 ); |
|||
var secondaryColor = (baseColor + (shift >= 0 ? 1 : -1) + 3) % 3; |
|||
//Setting Hue |
|||
rgb[baseColor] = 255; |
|||
rgb[secondaryColor] = (int) ((Math.Abs(shift) / 60.0f) * 255.0f); |
|||
//Setting Saturation |
|||
for (var i = 0; i < 3; i++) |
|||
rgb[i] += (int) ((255 - rgb[i]) * ((100 - s) / 100.0f)); |
|||
//Setting Value |
|||
for (var i = 0; i < 3; i++) |
|||
rgb[i] -= (int) (rgb[i] * (100-v) / 100.0f); |
|||
return RGB2int(rgb[0], rgb[1], rgb[2]); |
|||
} |
|||
public static int RGB2int(int r, int g, int b) => r << 16 | g << 8 | b; |
|||
</syntaxhighlight> |
|||
{{out}} |
|||
[[File:ColorRing.PNG]] |
|||
=={{header|Delphi}}== |
|||
{{libheader| Winapi.Windows}} |
|||
{{libheader| System.SysUtils}} |
|||
{{libheader| Vcl.Graphics}} |
|||
{{libheader| System.Math}} |
|||
{{libheader| Vcl.Imaging.pngimage}} |
|||
{{Trans|Kotlin}} |
|||
<syntaxhighlight lang="delphi"> |
|||
program Color_wheel; |
|||
{$APPTYPE CONSOLE} |
|||
uses |
|||
Winapi.Windows, |
|||
System.SysUtils, |
|||
Vcl.Graphics, |
|||
System.Math, |
|||
Vcl.Imaging.pngimage; |
|||
const |
|||
TAU = 2 * PI; |
|||
function HSBtoColor(hue, sat, bri: Double): TColor; |
|||
var |
|||
f, h: Double; |
|||
u, p, q, t: Byte; |
|||
begin |
|||
u := Trunc(bri * 255 + 0.5); |
|||
if sat = 0 then |
|||
Exit(rgb(u, u, u)); |
|||
h := (hue - Floor(hue)) * 6; |
|||
f := h - Floor(h); |
|||
p := Trunc(bri * (1 - sat) * 255 + 0.5); |
|||
q := Trunc(bri * (1 - sat * f) * 255 + 0.5); |
|||
t := Trunc(bri * (1 - sat * (1 - f)) * 255 + 0.5); |
|||
case Trunc(h) of |
|||
0: |
|||
result := rgb(u, t, p); |
|||
1: |
|||
result := rgb(q, u, p); |
|||
2: |
|||
result := rgb(p, u, t); |
|||
3: |
|||
result := rgb(p, q, u); |
|||
4: |
|||
result := rgb(t, p, u); |
|||
5: |
|||
result := rgb(u, p, q); |
|||
else |
|||
result := clwhite; |
|||
end; |
|||
end; |
|||
function ColorWheel(Width, Height: Integer): TPngImage; |
|||
var |
|||
Center: TPoint; |
|||
Radius: Integer; |
|||
x, y: Integer; |
|||
Hue, dy, dx, dist, theta: Double; |
|||
Bmp: TBitmap; |
|||
begin |
|||
Bmp := TBitmap.Create; |
|||
Bmp.SetSize(Width, Height); |
|||
with Bmp.Canvas do |
|||
begin |
|||
Brush.Color := clWhite; |
|||
FillRect(ClipRect); |
|||
Center := ClipRect.CenterPoint; |
|||
Radius := Center.X; |
|||
if Center.Y < Radius then |
|||
Radius := Center.Y; |
|||
for y := 0 to Height - 1 do |
|||
begin |
|||
dy := y - Center.y; |
|||
for x := 0 to Width - 1 do |
|||
begin |
|||
dx := x - Center.x; |
|||
dist := Sqrt(Sqr(dx) + Sqr(dy)); |
|||
if dist <= Radius then |
|||
begin |
|||
theta := ArcTan2(dy, dx); |
|||
Hue := (theta + PI) / TAU; |
|||
Pixels[x, y] := HSBtoColor(Hue, 1, 1); |
|||
end; |
|||
end; |
|||
end; |
|||
end; |
|||
Result := TPngImage.Create; |
|||
Result.Assign(Bmp); |
|||
Bmp.Free; |
|||
end; |
|||
begin |
|||
with ColorWheel(500, 500) do |
|||
begin |
|||
SaveToFile('ColorWheel.png'); |
|||
Free; |
|||
end; |
|||
end.</syntaxhighlight> |
|||
{{out}} |
|||
Png Image [https://ibb.co/T0w8KyF]. |
|||
=={{header|EasyLang}}== |
|||
[https://easylang.dev/show/#cod=bZLdboMwDIXveYpzSagaCrTVqi4Pw08CSHSBkG3w9pOBCjK4AKJzPtvBdmt0jqrPYlNmqL4l+tQiMzU4DEpk4B6ACgI+uWeoRmtDJEOAO5kKAtXqkNRCTEkC+BHOlJOR3O1kBFCTZY+s6agYe19hU6FWk3KhMwCzhD9RQsDiiQwCLbmyWdhow3YLOcfs2XjDtjvWOmxywHYLmZnaYa8b1i5s+5/t5eFfvbmOXO5xr6XZ5b+VlA34PCilDUbqC6zG9fFYEhWkjTgjvr07RuSwJwkmeXBgUuueZtR3xsIvBgTEnShzgGJkK1irmf0UbgIaciVtCoHUpl8xhRaD49OGCfgzdkL0cWEIkdzdLNtt9adSIVViiOaVdeBcN9okB8ZL/0gMCHHDSG/HNDK3uPCEntXg3uZLA5h773l/ Run it] |
|||
{{trans|Go}} |
|||
<syntaxhighlight> |
|||
proc hsb2rgb hue sat bri . r g b . |
|||
h = (hue - floor hue) * 6 |
|||
f = h - floor h |
|||
p = bri * (1 - sat) |
|||
q = bri * (1 - sat * f) |
|||
t = bri * (1 - sat * (1 - f)) |
|||
h = floor h |
|||
if h = 0 |
|||
r = bri ; g = t ; b = p |
|||
elif h = 1 |
|||
r = q ; g = bri ; b = p |
|||
elif h = 2 |
|||
r = p ; g = bri ; b = t |
|||
elif h = 3 |
|||
r = p ; g = q ; b = bri |
|||
elif h = 4 |
|||
r = t ; g = p ; b = bri |
|||
else |
|||
r = bri ; g = p ; b = q |
|||
. |
|||
. |
|||
proc cwheel . . |
|||
for y = 0 to 499 |
|||
dy = y - 250 |
|||
for x = 0 to 499 |
|||
dx = x - 250 |
|||
dist = sqrt (dx * dx + dy * dy) |
|||
if dist <= 250 |
|||
theta = atan2 dy dx |
|||
hue = (theta + 180) / 360 |
|||
hsb2rgb hue (dist / 250) 1 r g b |
|||
color3 r g b |
|||
move x / 5 y / 5 |
|||
rect 0.3 0.3 |
|||
. |
|||
. |
|||
. |
|||
. |
|||
cwheel |
|||
</syntaxhighlight> |
|||
=={{header|Fōrmulæ}}== |
|||
{{FormulaeEntry|page=https://formulae.org/?script=examples/Color_wheel}} |
|||
'''Solution''' |
|||
[[File:Fōrmulæ - Color wheel 01.png]] |
|||
'''Test case''' |
|||
Generating a color wheel of 300x300 pixels: |
|||
[[File:Fōrmulæ - Color wheel 02.png]] |
|||
[[File:Fōrmulæ - Color wheel 03.png]] |
|||
=={{header|FreeBASIC}}== |
|||
<syntaxhighlight lang="freebasic">#include "fbgfx.bi" |
|||
Sub HSVtoRGB(h As Single, s As Integer, v As Integer, Byref r As Integer, Byref g As Integer, Byref b As Integer) |
|||
If s = 0 Then |
|||
r = v |
|||
g = v |
|||
b = v |
|||
Return |
|||
End If |
|||
h = h Mod 360 |
|||
Dim As Single hue = h |
|||
Select Case h |
|||
Case 0f To 51.5f |
|||
hue = ((hue ) * (30f / (51.5f ))) |
|||
Case 51.5f To 122f |
|||
hue = ((hue - 51.5f) * (30f / (122f - 51.5f))) + 30 |
|||
Case 122f To 142.5f |
|||
hue = ((hue - 122f) * (30f / (142.5f - 122f))) + 60 |
|||
Case 142.5f To 165.5f |
|||
hue = ((hue - 142.5f) * (30f / (165.5f - 142.5f))) + 90 |
|||
Case 165.5f To 192f |
|||
hue = ((hue - 165.5f) * (30f / (192f - 165.5f))) + 120 |
|||
Case 192f To 218.5f |
|||
hue = ((hue - 192f) * (30f / (218.5f - 192f))) + 150 |
|||
Case 218.5f To 247f |
|||
hue = ((hue - 218.5f) * (30f / (247f - 218.5f))) + 180 |
|||
Case 247f To 275.5f |
|||
hue = ((hue - 247f) * (30f / (275.5f - 247f))) + 210 |
|||
Case 275.5f To 302.5f |
|||
hue = ((hue - 275.5f) * (30f / (302.5f - 275.5f))) + 240 |
|||
Case 302.5f To 330f |
|||
hue = ((hue - 302.5f) * (30f / (330f - 302.5f))) + 270 |
|||
Case 330f To 344.5f |
|||
hue = ((hue - 330f) * (30f / (344.5f - 330f))) + 300 |
|||
Case 344.5f To 360f |
|||
hue = ((hue - 344.5f) * (30f / (360f - 344.5f))) + 330 |
|||
End Select |
|||
h = hue |
|||
h = h Mod 360 |
|||
Dim As Single h1 = h / 60 |
|||
Dim As Integer i = Int(h1) |
|||
Dim As Single f = h1 - i |
|||
Dim As Integer p = v * (255 - s) / 256 |
|||
Dim As Integer q = v * (255 - f * s) / 256 |
|||
Dim As Integer t = v * (255 - (1 - f) * s) / 256 |
|||
Select Case As Const i |
|||
Case 0 |
|||
r = v |
|||
g = t |
|||
b = p |
|||
Return |
|||
Case 1 |
|||
r = q |
|||
g = v |
|||
b = p |
|||
Return |
|||
Case 2 |
|||
r = p |
|||
g = v |
|||
b = t |
|||
Return |
|||
Case 3 |
|||
r = p |
|||
g = q |
|||
b = v |
|||
Return |
|||
Case 4 |
|||
r = t |
|||
g = p |
|||
b = v |
|||
Return |
|||
Case 5 |
|||
r = v |
|||
g = p |
|||
b = q |
|||
Return |
|||
End Select |
|||
End Sub |
|||
Const pi As Single = 4 * Atn(1) |
|||
Const radius = 160 |
|||
Const xres = (radius * 2) + 1, yres = xres |
|||
Screenres xres, yres, 32 |
|||
Windowtitle "Color wheel" |
|||
Dim As Integer r,g,b |
|||
Dim As Single dx, dy, dist, angle |
|||
Do |
|||
Screenlock |
|||
Cls |
|||
For x As Integer = 0 To (radius * 2) - 1 |
|||
For y As Integer = 0 To (radius * 2) - 1 |
|||
dx = x - radius |
|||
dy = radius - y |
|||
dist = Sqr(dx * dx + dy * dy) |
|||
If dist < radius Then |
|||
angle = Atan2(dy, dx) * (180/pi) |
|||
If angle < 0 Then angle += 360 |
|||
If angle > 360 Then angle -= 360 |
|||
HSVtoRGB(angle, (dist / radius) * 255, 255, r, g, b) |
|||
Pset(x, y), Rgb(r, g, b) |
|||
End If |
|||
Next y |
|||
Next x |
|||
Screenunlock |
|||
Loop Until Inkey = Chr(27)</syntaxhighlight> |
|||
=={{header|FutureBasic}}== |
|||
FB has native functions for programmatically building color wheels. |
|||
<syntaxhighlight lang="futurebasic"> |
|||
_window = 1 |
|||
begin enum output 1 |
|||
_colorwheelImageView |
|||
end enum |
|||
void local fn BuildWindow |
|||
CGRect r = fn CGRectMake( 0, 0, 400, 400 ) |
|||
window _window, @"Programmatic Color Wheel", r, NSWindowStyleMaskTitled + NSWindowStyleMaskClosable |
|||
r = fn CGRectMake( 20, 20, 360, 360 ) |
|||
imageview _colorwheelImageView, YES, , r, NSImageScaleProportionallyUpOrDown, NSImageAlignCenter, NSImageFrameNone, _window |
|||
end fn |
|||
local fn CIImageToImageRef( ciImage as CIImageRef ) as ImageRef |
|||
CIImageRepRef rep = fn CIImageRepWithCIImage( ciImage ) |
|||
CGSize size = fn ImageRepSize( rep ) |
|||
ImageRef image = fn ImageWithSize( size ) |
|||
ImageAddRepresentation( image, rep ) |
|||
end fn = image |
|||
local fn ColorWheelImage( colorSpace as CGColorSpaceRef, dither as CFNumberRef, radius as CFNumberRef, softness as CFNumberRef, lightness as CFNumberRef ) as CIImageRef |
|||
CIFilterRef filter = fn CIFilterWithName( @"CIHueSaturationValueGradient" ) |
|||
ObjectSetValueForkey( filter, colorSpace, @"inputColorSpace" ) |
|||
ObjectSetValueForkey( filter, dither, @"inputDither" ) |
|||
ObjectSetValueForkey( filter, radius, @"inputRadius" ) |
|||
ObjectSetValueForkey( filter, softness, @"inputSoftness" ) |
|||
ObjectSetValueForkey( filter, lightness, @"inputValue" ) |
|||
CIImageRef outputCIImage = fn CIFilterOutputImage( filter ) |
|||
end fn = outputCIImage |
|||
local fn BuildColorWheel |
|||
CIImageRef colorWheelCIImage = fn ColorWheelImage( fn CGColorSpaceCreateDeviceRGB, @0, @160, @0, @1 ) |
|||
ImageRef colorWheelImage = fn CIImageToImageRef( colorWheelCIImage ) |
|||
ImageViewSetImage( _colorwheelImageView, colorWheelImage ) |
|||
end fn |
|||
fn BuildWindow |
|||
fn BuildColorWheel |
|||
HandleEvents |
|||
</syntaxhighlight> |
|||
{{output}} |
|||
[[File:Programmatic Color Wheel.png]] |
|||
=={{header|GML}}== |
=={{header|GML}}== |
||
<syntaxhighlight lang="gml"> |
|||
<lang GML> |
|||
for (var i = 1; i <= 360; i++) { |
for (var i = 1; i <= 360; i++) { |
||
for (var j = 0; j < 255; j++) { |
for (var j = 0; j < 255; j++) { |
||
Line 34: | Line 579: | ||
} |
} |
||
} |
} |
||
</syntaxhighlight> |
|||
</lang> |
|||
=={{header|Go}}== |
=={{header|Go}}== |
||
{{libheader|Go Graphics}} |
{{libheader|Go Graphics}} |
||
{{trans|Kotlin}} |
{{trans|Kotlin}} |
||
< |
<syntaxhighlight lang="go">package main |
||
import ( |
import ( |
||
Line 106: | Line 651: | ||
colorWheel(dc) |
colorWheel(dc) |
||
dc.SavePNG("color_wheel.png") |
dc.SavePNG("color_wheel.png") |
||
}</ |
}</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 113: | Line 658: | ||
</pre> |
</pre> |
||
=={{header|J}}== |
|||
<syntaxhighlight lang="j">rgbc=: {{1-x*0>.1<.(<.4&-)6|m+y%60}} |
|||
hsv=: 5 rgbc(,"0 1) 3 rgbc(,"0) 1 rgbc |
|||
degrees=: {{180p_1*{:"1+.^.y}} |
|||
wheel=: {{((1>:|)*|hsv degrees)j./~y%~i:y}} |
|||
require'viewmat' |
|||
'rgb' viewmat 256#.<.255*wheel 400</syntaxhighlight> |
|||
The right argument to wheel determines the radius (in pixels) of the color wheel (with a white pixel in the center), so the diameter of the above color wheel is 801 pixels. |
|||
Here's a representation of wheel 5: |
|||
<div style="text-align: center; vertical-align: middle; background-color: #000; width: 80px; height: 80px"><br /><div style="font-family: monospace; font-size: 8px; line-height: 0.5em"><span style="background-color: #000"> </span><span style="background-color: #000"> </span><span style="background-color: #000"> </span><span style="background-color: #000"> </span><span style="background-color: #000"> </span><span style="background-color: #00ffff"> </span><span style="background-color: #000"> </span><span style="background-color: #000"> </span><span style="background-color: #000"> </span><span style="background-color: #000"> </span><span style="background-color: #000"> </span><br /><span style="background-color: #000"> </span><span style="background-color: #000"> </span><span style="background-color: #0062ff"> </span><span style="background-color: #1a9aff"> </span><span style="background-color: #2ccdff"> </span><span style="background-color: #33ffff"> </span><span style="background-color: #2cffcd"> </span><span style="background-color: #1aff9a"> </span><span style="background-color: #00ff62"> </span><span style="background-color: #000"> </span><span style="background-color: #000"> </span><br /><span style="background-color: #000"> </span><span style="background-color: #001dff"> </span><span style="background-color: #265cff"> </span><span style="background-color: #4797ff"> </span><span style="background-color: #5dcdff"> </span><span style="background-color: #66ffff"> </span><span style="background-color: #5dffcd"> </span><span style="background-color: #47ff97"> </span><span style="background-color: #26ff5c"> </span><span style="background-color: #00ff1d"> </span><span style="background-color: #000"> </span><br /><span style="background-color: #000"> </span><span style="background-color: #271aff"> </span><span style="background-color: #4752ff"> </span><span style="background-color: #6e92ff"> </span><span style="background-color: #8cccff"> </span><span style="background-color: #99ffff"> </span><span style="background-color: #8cffcc"> </span><span style="background-color: #6eff92"> </span><span style="background-color: #47ff52"> </span><span style="background-color: #27ff1a"> </span><span style="background-color: #000"> </span><br /><span style="background-color: #000"> </span><span style="background-color: #642cff"> </span><span style="background-color: #7c5dff"> </span><span style="background-color: #938cff"> </span><span style="background-color: #b6c8ff"> </span><span style="background-color: #ccffff"> </span><span style="background-color: #b6ffc8"> </span><span style="background-color: #93ff8c"> </span><span style="background-color: #7cff5d"> </span><span style="background-color: #64ff2c"> </span><span style="background-color: #000"> </span><br /><span style="background-color: #7f00ff"> </span><span style="background-color: #9933ff"> </span><span style="background-color: #b266ff"> </span><span style="background-color: #cc99ff"> </span><span style="background-color: #e5ccff"> </span><span style="background-color: #ffffff"> </span><span style="background-color: #e5ffcc"> </span><span style="background-color: #ccff99"> </span><span style="background-color: #b2ff66"> </span><span style="background-color: #99ff33"> </span><span style="background-color: #7fff00"> </span><br /><span style="background-color: #000"> </span><span style="background-color: #c72cff"> </span><span style="background-color: #df5dff"> </span><span style="background-color: #f88cff"> </span><span style="background-color: #ffb6ec"> </span><span style="background-color: #ffcccc"> </span><span style="background-color: #ffecb6"> </span><span style="background-color: #f8ff8c"> </span><span style="background-color: #dfff5d"> </span><span style="background-color: #c7ff2c"> </span><span style="background-color: #000"> </span><br /><span style="background-color: #000"> </span><span style="background-color: #f11aff"> </span><span style="background-color: #ff47f3"> </span><span style="background-color: #ff6eda"> </span><span style="background-color: #ff8cbf"> </span><span style="background-color: #ff9999"> </span><span style="background-color: #ffbf8c"> </span><span style="background-color: #ffda6e"> </span><span style="background-color: #fff347"> </span><span style="background-color: #f1ff1a"> </span><span style="background-color: #000"> </span><br /><span style="background-color: #000"> </span><span style="background-color: #ff00e1"> </span><span style="background-color: #ff26c8"> </span><span style="background-color: #ff47ae"> </span><span style="background-color: #ff5d8f"> </span><span style="background-color: #ff6666"> </span><span style="background-color: #ff8f5d"> </span><span style="background-color: #ffae47"> </span><span style="background-color: #ffc826"> </span><span style="background-color: #ffe100"> </span><span style="background-color: #000"> </span><br /><span style="background-color: #000"> </span><span style="background-color: #000"> </span><span style="background-color: #ff009c"> </span><span style="background-color: #ff1a7f"> </span><span style="background-color: #ff2c5d"> </span><span style="background-color: #ff3333"> </span><span style="background-color: #ff5d2c"> </span><span style="background-color: #ff7f1a"> </span><span style="background-color: #ff9c00"> </span><span style="background-color: #000"> </span><span style="background-color: #000"> </span><br /><span style="background-color: #000"> </span><span style="background-color: #000"> </span><span style="background-color: #000"> </span><span style="background-color: #000"> </span><span style="background-color: #000"> </span><span style="background-color: #ff0000"> </span><span style="background-color: #000"> </span><span style="background-color: #000"> </span><span style="background-color: #000"> </span><span style="background-color: #000"> </span><span style="background-color: #000"> </span><br /><span style="background-color: #000"> </span><span style="background-color: #000"> </span><span style="background-color: #000"> </span><span style="background-color: #000"> </span><span style="background-color: #000"> </span><span style="background-color: #000"> </span><span style="background-color: #000"> </span><span style="background-color: #000"> </span><span style="background-color: #000"> </span><span style="background-color: #000"> </span><span style="background-color: #000"> </span><br /></div></div> |
|||
<hr /> |
|||
Here's an online implementation for [https://jsoftware.github.io/j-playground/bin/html2/#code=rgbc%3D%3A%20%7B%7B1-x*0%3E.1%3C.%28%3C.4%26-%296%7Cm%2By%2560%7D%7D%0Ahsv%3D%3A%205%20rgbc%28%2C%220%201%29%203%20rgbc%28%2C%220%29%201%20rgbc%0Adegrees%3D%3A%20%7B%7B180p_1*%7B%3A%221%2B.%5E.y%7D%7D%0Awheel%3D%3A%20%7B%7B%28%281%3E%3A%7C%29*%7Chsv%20degrees%29j.%2F~y%25~i%3Ay%7D%7D%0Arequire'viewmat'%0A'rgb'%20viewmat%20256%23.%3C.255*wheel%2080 wheel 80] (hit "Run" in the upper right corner). |
|||
=={{header|Java}}== |
|||
This program draws a color wheel in a window. |
|||
<syntaxhighlight lang="java">import java.awt.*; |
|||
import javax.swing.*; |
|||
public class ColorWheel { |
|||
public static void main(String[] args) { |
|||
SwingUtilities.invokeLater(new Runnable() { |
|||
public void run() { |
|||
ColorWheelFrame frame = new ColorWheelFrame(); |
|||
frame.setVisible(true); |
|||
} |
|||
}); |
|||
} |
|||
private static class ColorWheelFrame extends JFrame { |
|||
private ColorWheelFrame() { |
|||
super("Color Wheel"); |
|||
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); |
|||
getContentPane().add(new ColorWheelPanel()); |
|||
pack(); |
|||
} |
|||
} |
|||
private static class ColorWheelPanel extends JComponent { |
|||
private ColorWheelPanel() { |
|||
setPreferredSize(new Dimension(400, 400)); |
|||
} |
|||
public void paint(Graphics g) { |
|||
Graphics2D g2 = (Graphics2D)g; |
|||
int w = getWidth(); |
|||
int h = getHeight(); |
|||
int margin = 10; |
|||
int radius = (Math.min(w, h) - 2 * margin)/2; |
|||
int cx = w/2; |
|||
int cy = h/2; |
|||
float[] dist = {0.F, 1.0F}; |
|||
g2.setColor(Color.BLACK); |
|||
g2.fillRect(0, 0, w, h); |
|||
for (int angle = 0; angle < 360; ++angle) { |
|||
Color color = hsvToRgb(angle, 1.0, 1.0); |
|||
Color[] colors = {Color.WHITE, color}; |
|||
RadialGradientPaint paint = new RadialGradientPaint(cx, cy, |
|||
radius, dist, colors); |
|||
g2.setPaint(paint); |
|||
g2.fillArc(cx - radius, cy - radius, radius*2, radius*2, |
|||
angle, 1); |
|||
} |
|||
} |
|||
} |
|||
private static Color hsvToRgb(int h, double s, double v) { |
|||
double hp = h/60.0; |
|||
double c = s * v; |
|||
double x = c * (1 - Math.abs(hp % 2.0 - 1)); |
|||
double m = v - c; |
|||
double r = 0, g = 0, b = 0; |
|||
if (hp <= 1) { |
|||
r = c; |
|||
g = x; |
|||
} else if (hp <= 2) { |
|||
r = x; |
|||
g = c; |
|||
} else if (hp <= 3) { |
|||
g = c; |
|||
b = x; |
|||
} else if (hp <= 4) { |
|||
g = x; |
|||
b = c; |
|||
} else if (hp <= 5) { |
|||
r = x; |
|||
b = c; |
|||
} else { |
|||
r = c; |
|||
b = x; |
|||
} |
|||
r += m; |
|||
g += m; |
|||
b += m; |
|||
return new Color((int)(r * 255), (int)(g * 255), (int)(b * 255)); |
|||
} |
|||
}</syntaxhighlight> |
|||
{{out}} |
|||
[[Media:Color_wheel_java.png]] |
|||
=={{header|Julia}}== |
=={{header|Julia}}== |
||
< |
<syntaxhighlight lang="julia">using Gtk, Graphics, Colors |
||
const win = GtkWindow("Color Wheel", |
const win = GtkWindow("Color Wheel", 450, 450) |> (const can = @GtkCanvas()) |
||
set_gtk_property!(can, :expand, true) |
set_gtk_property!(can, :expand, true) |
||
Line 126: | Line 775: | ||
center = (x = w / 2, y = h / 2) |
center = (x = w / 2, y = h / 2) |
||
anglestep = 1/w |
anglestep = 1/w |
||
for θ in 0:1:360 |
for θ in 0:0.1:360 |
||
rgb = RGB(HSV(θ, 1, 1)) |
rgb = RGB(HSV(θ, 1, 1)) |
||
set_source_rgb(ctx, rgb.r, rgb.g, rgb.b) |
set_source_rgb(ctx, rgb.r, rgb.g, rgb.b) |
||
line_to(ctx, center...) |
line_to(ctx, center...) |
||
arc(ctx, center.x, center.y, w/2.2, |
arc(ctx, center.x, center.y, w/2.2, 2π * θ / 360, anglestep) |
||
line_to(ctx, center...) |
line_to(ctx, center...) |
||
stroke(ctx) |
stroke(ctx) |
||
Line 141: | Line 790: | ||
signal_connect(endit, win, :destroy) |
signal_connect(endit, win, :destroy) |
||
wait(condition) |
wait(condition) |
||
</syntaxhighlight> |
|||
</lang> |
|||
=={{header|Kotlin}}== |
=={{header|Kotlin}}== |
||
We reuse the class in the Bitmap task for this and add a member function to draw the color wheel. To give a more 'wheel-like' image, a constant 'saturation' of 1.0 has been used rather than one which varies in line with distance from the center. |
We reuse the class in the Bitmap task for this and add a member function to draw the color wheel. To give a more 'wheel-like' image, a constant 'saturation' of 1.0 has been used rather than one which varies in line with distance from the center. |
||
< |
<syntaxhighlight lang="scala">// Version 1.2.41 |
||
import java.awt.Color |
import java.awt.Color |
||
Line 197: | Line 845: | ||
} |
} |
||
} |
} |
||
</syntaxhighlight> |
|||
</lang> |
|||
{{output}} |
{{output}} |
||
Line 203: | Line 851: | ||
Looks like mirror image of Smart BASIC entry |
Looks like mirror image of Smart BASIC entry |
||
</pre> |
</pre> |
||
=={{header|Lua}}== |
|||
{{libheader|LÖVE}} |
|||
<syntaxhighlight lang="lua"> |
|||
local function hsv_to_rgb (h, s, v) -- values in ranges: [0, 360], [0, 1], [0, 1] |
|||
local r = math.min (math.max (3*math.abs (((h )/180)%2-1)-1, 0), 1) |
|||
local g = math.min (math.max (3*math.abs (((h -120)/180)%2-1)-1, 0), 1) |
|||
local b = math.min (math.max (3*math.abs (((h +120)/180)%2-1)-1, 0), 1) |
|||
local k1 = v*(1-s) |
|||
local k2 = v - k1 |
|||
return k1+k2*r, k1+k2*g, k1+k2*b -- values in ranges: [0, 1], [0, 1], [0, 1] |
|||
end |
|||
function love.load() |
|||
local w, h, r = 256, 256, 128-0.5 |
|||
local cx, cy = w/2, h/2 |
|||
canvas = love.graphics.newCanvas () |
|||
love.graphics.setCanvas(canvas) |
|||
for x = 0, w do |
|||
for y = 0, h do |
|||
local dx, dy = x-cx, y-cy |
|||
if dx*dx + dy*dy <= r*r then |
|||
local h = math.deg(math.atan2(dy, dx)) |
|||
local s = (dx*dx + dy*dy)^0.5/r |
|||
local v = 1 |
|||
love.graphics.setColor (hsv_to_rgb (h, s, v)) |
|||
love.graphics.points (x, y) |
|||
end |
|||
end |
|||
end |
|||
love.graphics.setCanvas() |
|||
end |
|||
function love.draw() |
|||
love.graphics.setColor (1,1,1) |
|||
love.graphics.draw (canvas) |
|||
end |
|||
</syntaxhighlight> |
|||
=={{header|M2000 Interpreter}}== |
=={{header|M2000 Interpreter}}== |
||
<syntaxhighlight lang="m2000 interpreter"> |
|||
<lang M2000 Interpreter> |
|||
Module Check { |
Module Check { |
||
\\ we use an internal object for Math functions (here for Atan2) |
\\ we use an internal object for Math functions (here for Atan2) |
||
Line 284: | Line 972: | ||
} |
} |
||
Check |
Check |
||
</syntaxhighlight> |
|||
</lang> |
|||
{{out}} |
{{out}} |
||
see [https://4.bp.blogspot.com/-0swVvNDaTjE/XDlPfuGQkBI/AAAAAAAAHno/wU3eyo1BUIEtPjZMyjGXkbN425zHJlc7wCLcBGAs/s1600/colorwheel.png this image] |
see [https://4.bp.blogspot.com/-0swVvNDaTjE/XDlPfuGQkBI/AAAAAAAAHno/wU3eyo1BUIEtPjZMyjGXkbN425zHJlc7wCLcBGAs/s1600/colorwheel.png this image] |
||
=={{header|Mathematica}}/{{header|Wolfram Language}}== |
|||
<syntaxhighlight lang="mathematica">r = 100; |
|||
Image[Table[ |
|||
If[x^2 + y^2 <= r^2, |
|||
angle = Mod[ArcTan[N@x, y]/(2 Pi), 1]; |
|||
List @@ RGBColor[Hue[angle, Sqrt[x^2 + y^2]/N[r], 1.0]] |
|||
, |
|||
{1, 1, 1} |
|||
], {x, -r, r}, {y, -r, r}] |
|||
]</syntaxhighlight> |
|||
{{out}} |
|||
Outputs an image. |
|||
=={{header|Nim}}== |
|||
{{trans|Rust}} |
|||
{{libheader|imageman}} |
|||
As Rust code does, we store the color wheel in a PNG image. |
|||
<syntaxhighlight lang="nim">import math |
|||
import imageman |
|||
#--------------------------------------------------------------------------------------------------- |
|||
func hsvToRgb(h, s, v: float): ColorRGBU = |
|||
## Convert HSV values to RGB values. |
|||
let hp = h / 60 |
|||
let c = s * v |
|||
let x = c * (1 - abs(hp mod 2 - 1)) |
|||
let m = v - c |
|||
var r, g, b = 0.0 |
|||
if hp <= 1: |
|||
r = c |
|||
g = x |
|||
elif hp <= 2: |
|||
r = x |
|||
g = c |
|||
elif hp <= 3: |
|||
g = c |
|||
b = x |
|||
elif hp <= 4: |
|||
g = x |
|||
b= c |
|||
elif hp <= 5: |
|||
r = x |
|||
b = c |
|||
else: |
|||
r = c |
|||
b = x |
|||
r += m |
|||
g += m |
|||
b += m |
|||
result = ColorRGBU [byte(r * 255), byte(g * 255), byte(b * 255)] |
|||
#--------------------------------------------------------------------------------------------------- |
|||
func buildColorWheel(image: var Image) = |
|||
## Build a color wheel into the image. |
|||
const Margin = 10 |
|||
let diameter = min(image.w, image.h) - 2 * Margin |
|||
let xOffset = (image.w - diameter) div 2 |
|||
let yOffset = (image.h - diameter) div 2 |
|||
let radius = diameter / 2 |
|||
for x in 0..diameter: |
|||
let rx = x.toFloat - radius |
|||
for y in 0..diameter: |
|||
let ry = y.toFloat - radius |
|||
let r = hypot(rx, ry) / radius |
|||
if r > 1: continue |
|||
let a = 180 + arctan2(ry, -rx).radToDeg() |
|||
image[x + xOffset, y + yOffset] = hsvToRgb(a, r, 1) |
|||
#——————————————————————————————————————————————————————————————————————————————————————————————————— |
|||
const |
|||
Side = 400 |
|||
Output = "color_wheel.png" |
|||
var image = initImage[ColorRGBU](Side, Side) |
|||
image.buildColorWheel() |
|||
image.savePNG(Output, compression = 9)</syntaxhighlight> |
|||
=={{header|Perl}}== |
=={{header|Perl}}== |
||
{{trans|Sidef}} |
{{trans|Sidef}} |
||
< |
<syntaxhighlight lang="perl">use Imager; |
||
use Math::Complex qw(cplx i pi); |
use Math::Complex qw(cplx i pi); |
||
Line 311: | Line 1,086: | ||
} |
} |
||
$img->write(file => 'color_wheel.png');</ |
$img->write(file => 'color_wheel.png');</syntaxhighlight> |
||
=={{header| |
=={{header|Phix}}== |
||
{{libheader|Phix/pGUI}} |
|||
{{works with|Rakudo|2016.08}} |
|||
{{libheader|Phix/online}} |
|||
You can run this online [http://phix.x10.mx/p2js/Colour_wheel.htm here]. |
|||
<!--<syntaxhighlight lang="phix">(phixonline)--> |
|||
<span style="color: #000080;font-style:italic;">-- |
|||
-- demo\rosetta\Colour_wheel.exw |
|||
-- ============================= |
|||
-- |
|||
-- Note: Made non-resizeable since maximising this is far too slow. |
|||
--</span> |
|||
<span style="color: #008080;">with</span> <span style="color: #008080;">javascript_semantics</span> |
|||
<span style="color: #008080;">include</span> <span style="color: #000000;">pGUI</span><span style="color: #0000FF;">.</span><span style="color: #000000;">e</span> |
|||
<span style="color: #008080;">constant</span> <span style="color: #000000;">title</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">"Colour wheel"</span> |
|||
<span style="color: #004080;">Ihandle</span> <span style="color: #000000;">dlg</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">canvas</span> |
|||
<span style="color: #004080;">cdCanvas</span> <span style="color: #000000;">cddbuffer</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">cdcanvas</span> |
|||
<span style="color: #008080;">function</span> <span style="color: #000000;">redraw_cb</span><span style="color: #0000FF;">(</span><span style="color: #004080;">Ihandle</span> <span style="color: #000080;font-style:italic;">/*ih*/</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">integer</span> <span style="color: #000080;font-style:italic;">/*posx*/</span><span style="color: #0000FF;">,</span> <span style="color: #000080;font-style:italic;">/*posy*/</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #004080;">integer</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">w</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">h</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">IupGetIntInt</span><span style="color: #0000FF;">(</span><span style="color: #000000;">canvas</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"DRAWSIZE"</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #7060A8;">cdCanvasActivate</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cddbuffer</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #004080;">integer</span> <span style="color: #000000;">radius</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">floor</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">min</span><span style="color: #0000FF;">(</span><span style="color: #000000;">w</span><span style="color: #0000FF;">,</span><span style="color: #000000;">h</span><span style="color: #0000FF;">)/</span><span style="color: #000000;">2</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #004080;">integer</span> <span style="color: #000000;">cx</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">floor</span><span style="color: #0000FF;">(</span><span style="color: #000000;">w</span><span style="color: #0000FF;">/</span><span style="color: #000000;">2</span><span style="color: #0000FF;">),</span> |
|||
<span style="color: #000000;">cy</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">floor</span><span style="color: #0000FF;">(</span><span style="color: #000000;">h</span><span style="color: #0000FF;">/</span><span style="color: #000000;">2</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #008080;">for</span> <span style="color: #000000;">x</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #000000;">w</span> <span style="color: #008080;">do</span> |
|||
<span style="color: #008080;">for</span> <span style="color: #000000;">y</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #000000;">h</span> <span style="color: #008080;">do</span> |
|||
<span style="color: #004080;">integer</span> <span style="color: #000000;">rx</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">x</span> <span style="color: #0000FF;">-</span> <span style="color: #000000;">cx</span><span style="color: #0000FF;">,</span> |
|||
<span style="color: #000000;">ry</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">y</span> <span style="color: #0000FF;">-</span> <span style="color: #000000;">cy</span> |
|||
<span style="color: #004080;">atom</span> <span style="color: #000000;">s</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">sqrt</span><span style="color: #0000FF;">(</span><span style="color: #000000;">rx</span><span style="color: #0000FF;">*</span><span style="color: #000000;">rx</span><span style="color: #0000FF;">+</span><span style="color: #000000;">ry</span><span style="color: #0000FF;">*</span><span style="color: #000000;">ry</span><span style="color: #0000FF;">)</span> <span style="color: #0000FF;">/</span> <span style="color: #000000;">radius</span> |
|||
<span style="color: #008080;">if</span> <span style="color: #000000;">s</span> <span style="color: #0000FF;"><=</span> <span style="color: #000000;">1.0</span> <span style="color: #008080;">then</span> |
|||
<span style="color: #004080;">atom</span> <span style="color: #000000;">hue</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">((</span><span style="color: #7060A8;">atan2</span><span style="color: #0000FF;">(</span><span style="color: #000000;">ry</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">rx</span><span style="color: #0000FF;">)</span> <span style="color: #0000FF;">/</span> <span style="color: #004600;">PI</span><span style="color: #0000FF;">)</span> <span style="color: #0000FF;">+</span> <span style="color: #000000;">1.0</span><span style="color: #0000FF;">)</span> <span style="color: #0000FF;">/</span> <span style="color: #000000;">2.0</span> |
|||
<span style="color: #7060A8;">cdCanvasPixel</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cddbuffer</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">x</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">h</span><span style="color: #0000FF;">-</span><span style="color: #000000;">y</span><span style="color: #0000FF;">,</span> <span style="color: #7060A8;">hsv_to_rgb</span><span style="color: #0000FF;">(</span><span style="color: #000000;">hue</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">s</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1</span><span style="color: #0000FF;">))</span> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span> |
|||
<span style="color: #7060A8;">cdCanvasFlush</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cddbuffer</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #008080;">return</span> <span style="color: #004600;">IUP_DEFAULT</span> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span> |
|||
<span style="color: #008080;">function</span> <span style="color: #000000;">map_cb</span><span style="color: #0000FF;">(</span><span style="color: #004080;">Ihandle</span> <span style="color: #000000;">ih</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #000000;">cdcanvas</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">cdCreateCanvas</span><span style="color: #0000FF;">(</span><span style="color: #004600;">CD_IUP</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">ih</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #000000;">cddbuffer</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">cdCreateCanvas</span><span style="color: #0000FF;">(</span><span style="color: #004600;">CD_DBUFFER</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">cdcanvas</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #7060A8;">cdCanvasSetBackground</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cddbuffer</span><span style="color: #0000FF;">,</span> <span style="color: #004600;">CD_WHITE</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #7060A8;">cdCanvasSetForeground</span><span style="color: #0000FF;">(</span><span style="color: #000000;">cddbuffer</span><span style="color: #0000FF;">,</span> <span style="color: #004600;">CD_MAGENTA</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #008080;">return</span> <span style="color: #004600;">IUP_DEFAULT</span> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span> |
|||
<span style="color: #008080;">procedure</span> <span style="color: #000000;">main</span><span style="color: #0000FF;">()</span> |
|||
<span style="color: #7060A8;">IupOpen</span><span style="color: #0000FF;">()</span> |
|||
<span style="color: #000000;">canvas</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">IupCanvas</span><span style="color: #0000FF;">(</span><span style="color: #004600;">NULL</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #7060A8;">IupSetAttribute</span><span style="color: #0000FF;">(</span><span style="color: #000000;">canvas</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"RASTERSIZE"</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"300x300"</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #7060A8;">IupSetCallback</span><span style="color: #0000FF;">(</span><span style="color: #000000;">canvas</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"MAP_CB"</span><span style="color: #0000FF;">,</span> <span style="color: #7060A8;">Icallback</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"map_cb"</span><span style="color: #0000FF;">))</span> |
|||
<span style="color: #000000;">dlg</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">IupDialog</span><span style="color: #0000FF;">(</span><span style="color: #000000;">canvas</span><span style="color: #0000FF;">,</span><span style="color: #008000;">`TITLE="%s",RESIZE=NO`</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">title</span><span style="color: #0000FF;">})</span> |
|||
<span style="color: #7060A8;">IupSetCallback</span><span style="color: #0000FF;">(</span><span style="color: #000000;">canvas</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"ACTION"</span><span style="color: #0000FF;">,</span> <span style="color: #7060A8;">Icallback</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"redraw_cb"</span><span style="color: #0000FF;">))</span> |
|||
<span style="color: #7060A8;">IupShowXY</span><span style="color: #0000FF;">(</span><span style="color: #000000;">dlg</span><span style="color: #0000FF;">,</span><span style="color: #004600;">IUP_CENTER</span><span style="color: #0000FF;">,</span><span style="color: #004600;">IUP_CENTER</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #008080;">if</span> <span style="color: #7060A8;">platform</span><span style="color: #0000FF;">()!=</span><span style="color: #004600;">JS</span> <span style="color: #008080;">then</span> |
|||
<span style="color: #7060A8;">IupMainLoop</span><span style="color: #0000FF;">()</span> |
|||
<span style="color: #7060A8;">IupClose</span><span style="color: #0000FF;">()</span> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span> |
|||
<span style="color: #000000;">main</span><span style="color: #0000FF;">()</span> |
|||
<!--</syntaxhighlight>--> |
|||
=={{header|Processing}}== |
|||
<lang perl6>use Image::PNG::Portable; |
|||
<syntaxhighlight lang="java">size(300, 300); |
|||
background(0); |
|||
float radius = min(width, height) / 2.0; |
|||
float cx = width / 2; |
|||
float cy = width / 2; |
|||
for (int x = 0; x < width; x++) { |
|||
for (int y = 0; y < width; y++) { |
|||
float rx = x - cx; |
|||
float ry = y - cy; |
|||
float s = sqrt(sq(rx) + sq(ry)) / radius; |
|||
if (s <= 1.0) { |
|||
float h = ((atan2(ry, rx) / PI) + 1.0) / 2.0; |
|||
colorMode(HSB); |
|||
color c = color(int(h * 255), int(s * 255), 255); |
|||
set(x, y, c); |
|||
} |
|||
} |
|||
}</syntaxhighlight> |
|||
==={{header|Processing Python mode}}=== |
|||
<syntaxhighlight lang="python">size(300, 300) |
|||
background(0) |
|||
radius = min(width, height) / 2.0 |
|||
cx, cy = width / 2, width / 2 |
|||
for x in range(width): |
|||
for y in range(height): |
|||
rx = x - cx |
|||
ry = y - cy |
|||
s = sqrt(rx ** 2 + ry ** 2) / radius |
|||
if s <= 1.0: |
|||
h = ((atan2(ry, rx) / PI) + 1.0) / 2.0 |
|||
colorMode(HSB) |
|||
c = color(int(h * 255), int(s * 255), 255) |
|||
set(x, y, c) # note set() used as Processing set() not as Python set()</syntaxhighlight> |
|||
=={{header|Plain English}}== |
|||
<syntaxhighlight lang="plainenglish"> |
|||
To draw the color wheel: |
|||
Start with the red color. |
|||
Turn right 80 points. |
|||
Loop. |
|||
If the user clicks on the screen, break. |
|||
Move to the center of the screen. |
|||
Draw a line 2 inches long. |
|||
Refresh the screen. |
|||
Change the current hue by 10 points. |
|||
Turn right 10 points. |
|||
Add 1 to a count. |
|||
If the count is 384, break. \ Plain English uses a circle divided into 384 degrees |
|||
Repeat. |
|||
Start in the middle of the screen facing north minus 80 points. |
|||
Use medium-sized letters. |
|||
Write "RED......YELLOW.....GREEN......CYAN......BLUE.....MAGENTA......" with the white pen 2-1/4 inches from the screen's center. |
|||
Refresh the screen. |
|||
Shut down. |
|||
</syntaxhighlight> |
|||
=={{header|Python}}== |
|||
<syntaxhighlight lang="python">from PIL import Image |
|||
import colorsys |
|||
import math |
|||
if __name__ == "__main__": |
|||
im = Image.new("RGB", (300,300)) |
|||
radius = min(im.size)/2.0 |
|||
cx, cy = im.size[0]/2, im.size[1]/2 |
|||
pix = im.load() |
|||
for x in range(im.width): |
|||
for y in range(im.height): |
|||
rx = x - cx |
|||
ry = y - cy |
|||
s = (rx ** 2.0 + ry ** 2.0) ** 0.5 / radius |
|||
if s <= 1.0: |
|||
h = ((math.atan2(ry, rx) / math.pi) + 1.0) / 2.0 |
|||
rgb = colorsys.hsv_to_rgb(h, s, 1.0) |
|||
pix[x,y] = tuple([int(round(c*255.0)) for c in rgb]) |
|||
im.show()</syntaxhighlight> |
|||
=={{header|Racket}}== |
|||
With the colors package |
|||
<syntaxhighlight lang="racket">#lang racket |
|||
(require racket/draw |
|||
colors) |
|||
(define DIM 500) |
|||
(define target (make-bitmap DIM DIM)) |
|||
(define dc (new bitmap-dc% [bitmap target])) |
|||
(define radius 200) |
|||
(define center (/ DIM 2)) |
|||
(define (atan2 y x) (if (= 0 y x) 0 (atan y x))) |
|||
(for* ([x (in-range DIM)] |
|||
[y (in-range DIM)] |
|||
[rx (in-value (- x center))] |
|||
[ry (in-value (- y center))] |
|||
[s (in-value (/ (sqrt (+ (sqr rx) (sqr ry))) radius))] |
|||
#:when (<= s 1)) |
|||
(define h (* 0.5 (+ 1 (/ (atan2 ry rx) pi)))) |
|||
(send dc set-pen (hsv->color (hsv (if (= 1 h) 0 h) s 1)) 1 'solid) |
|||
(send dc draw-point x y)) |
|||
target</syntaxhighlight> |
|||
=={{header|Raku}}== |
|||
(formerly Perl 6) |
|||
{{works with|Rakudo|2016.08}} |
|||
[[File:Color-wheel-perl6.png|thumb]] |
|||
<syntaxhighlight lang="raku" line>use Image::PNG::Portable; |
|||
my ($w, $h) = 300, 300; |
my ($w, $h) = 300, 300; |
||
Line 351: | Line 1,307: | ||
when 5/6..1 { $c, 0, $x } |
when 5/6..1 { $c, 0, $x } |
||
} ).map: ((*+$m) * 255).Int |
} ).map: ((*+$m) * 255).Int |
||
}</ |
}</syntaxhighlight> |
||
=={{header|Ring}}== |
|||
Until local image uploading is re-enabled, see [https://github.com/thundergnat/rc/blob/master/img/Color-wheel-perl6.png Color-wheel-perl6.png] |
|||
[https://kepfeltoltes.zapto.org/public/20210912082335ColorWheel.jpg Color wheel - image] |
|||
=={{header|Phix}}== |
|||
{{libheader|pGUI}} |
|||
<lang Phix>-- demo\rosetta\Colour_wheel.exw |
|||
include pGUI.e |
|||
<syntaxhighlight lang="ring"> |
|||
Ihandle dlg, canvas |
|||
#===================================================================# |
|||
cdCanvas cddbuffer, cdcanvas |
|||
# Sample: Color Wheel |
|||
# Author: Gal Zsolt, Bert Mariani, Ilir Liburn & Mahmoud Fayed |
|||
#===================================================================# |
|||
load "guilib.ring" |
|||
function hsv_to_rgb(atom h, s, v) |
|||
atom r,g,b |
|||
xWidth = 400 |
|||
if s=0 then |
|||
yHeight = 400 |
|||
{r,g,b} @= v |
|||
else |
|||
MyApp = new qapp |
|||
integer i = floor(h*6) |
|||
{ |
|||
atom f = h*6-i, |
|||
win1 = new qwidget() |
|||
{ setwindowtitle("ColorWheel-FastDraw") |
|||
q = v*(1-s*f), |
|||
setgeometry(500,150,xWidth,yHeight) |
|||
t = v*(1-s*(1-f)) |
|||
Canvas = new qlabel(win1) |
|||
{ ### daVinci paints the MonaLisa on the Canvas |
|||
MonaLisa = new qPixMap2( xWidth, yHeight) |
|||
color = new qcolor(){ setrgb(255,255,255,0) } |
|||
pen = new qpen() { setwidth(1) } |
|||
MonaLisa.fill(color) |
|||
case 5: {r,g,b} = {v, p, q} |
|||
end switch |
|||
end if |
|||
return cdEncodeColor(r*255, g*255, b*255) |
|||
end function |
|||
daVinci = new qpainter() |
|||
function redraw_cb(Ihandle /*ih*/, integer /*posx*/, integer /*posy*/) |
|||
{ begin(MonaLisa) |
|||
integer {w, h} = IupGetIntInt(canvas, "DRAWSIZE") |
|||
#endpaint() ### This will Stop the Painting. For Animation comment it out |
|||
cdCanvasActivate(cddbuffer) |
|||
} |
|||
integer radius = floor(min(w,h)/2) |
|||
setPixMap(MonaLisa) |
|||
} |
|||
show() |
|||
integer rx = x - cx, |
|||
} |
|||
ry = y - cy |
|||
atom s = sqrt(rx*rx+ry*ry) / radius |
|||
ColorWheel() |
|||
if s <= 1.0 then |
|||
exec() |
|||
atom hue = ((atan2(ry, rx) / PI) + 1.0) / 2.0 |
|||
} |
|||
cdCanvasPixel(cddbuffer, x, h-y, hsv_to_rgb(hue, s, 1)) |
|||
end if |
|||
//===================== |
|||
end for |
|||
end for |
|||
Func colorWheel |
|||
cdCanvasFlush(cddbuffer) |
|||
return IUP_DEFAULT |
|||
end function |
|||
#=====================================================================# |
|||
function map_cb(Ihandle ih) |
|||
? "Start Processing..." |
|||
cdcanvas = cdCreateCanvas(CD_IUP, ih) |
|||
t1 = clock() |
|||
cddbuffer = cdCreateCanvas(CD_DBUFFER, cdcanvas) |
|||
? "Clock : " + t1 |
|||
cdCanvasSetBackground(cddbuffer, CD_WHITE) |
|||
#=====================================================================# |
|||
cdCanvasSetForeground(cddbuffer, CD_MAGENTA) |
|||
return IUP_DEFAULT |
|||
end function |
|||
aList = [] |
|||
procedure main() |
|||
pi = 3.14159265359 |
|||
IupOpen() |
|||
diameter = pi * 2 |
|||
radius = yHeight / 2 |
|||
canvas = IupCanvas(NULL) |
|||
v = 1 // value/brightness 1 to 100 1=bright 0=dark |
|||
IupSetAttribute(canvas, "RASTERSIZE", "400x400") -- initial size |
|||
IupSetCallback(canvas, "MAP_CB", Icallback("map_cb")) |
|||
for i = 1 to xWidth |
|||
iradius = i - radius |
|||
IupSetAttribute(dlg, "TITLE", "Colour wheel") |
|||
p = pow( iradius, 2) |
|||
IupSetCallback(canvas, "ACTION", Icallback("redraw_cb")) |
|||
IupCloseOnEscape(dlg) |
|||
for j = 1 to yHeight |
|||
IupMap(dlg) |
|||
IupSetAttribute(canvas, "RASTERSIZE", NULL) |
|||
IupShowXY(dlg,IUP_CENTER,IUP_CENTER) |
|||
IupMainLoop() |
|||
IupClose() |
|||
end procedure |
|||
h = (atan2( iradius, j-radius ) + pi ) / diameter // hue/color 1 to 360 |
|||
main()</lang> |
|||
s = sqrt( p + pow( j-radius, 2)) / radius // saturation/intensity 1 to 100 |
|||
if s <= 1 and h <= 1 |
|||
aList + [i,j,h,s,v,1] |
|||
ok |
|||
next |
|||
next |
|||
#=====================================================================# |
|||
=={{header|Python}}== |
|||
? "Start drawing..." |
|||
t2 = clock() |
|||
? "Clock : " + t2 |
|||
#=====================================================================# |
|||
daVinci.drawHSVFList(aList) |
|||
<lang python>from PIL import Image |
|||
Canvas.setPixMap(MonaLisa) |
|||
import colorsys |
|||
import math |
|||
#=====================================================================# |
|||
if __name__ == "__main__": |
|||
? "Done..." |
|||
t3 = clock() |
|||
? "Clock : " + t3 |
|||
#=====================================================================# |
|||
? "Processing Time: " + ( (t2-t1)/ClocksPerSecond() ) + " seconds " |
|||
? "Drawing Time: " + ( (t3-t2)/ClocksPerSecond() ) + " seconds " |
|||
? "Total Time: " + ( (t3-t1)/ClocksPerSecond() ) + " seconds " |
|||
#=====================================================================# |
|||
return |
|||
//================== |
|||
</syntaxhighlight> |
|||
=={{header|Ruby}}== |
|||
im = Image.new("RGB", (300,300)) |
|||
{{libheader|RubyGems}} |
|||
radius = min(im.size)/2.0 |
|||
{{libheader|JRubyArt}} |
|||
centre = im.size[0]/2, im.size[1]/2 |
|||
<syntaxhighlight lang="ruby"> |
|||
pix = im.load() |
|||
def settings |
|||
size(300, 300) |
|||
end |
|||
def setup |
|||
for x in range(im.width): |
|||
sketch_title 'Color Wheel' |
|||
for y in range(im.height): |
|||
background(0) |
|||
rx = x - centre[0] |
|||
radius = width / 2.0 |
|||
ry = y - centre[1] |
|||
center = width / 2 |
|||
s = ((x - centre[0])**2.0 + (y - centre[1])**2.0)**0.5 / radius |
|||
grid(width, height) do |x, y| |
|||
if s <= 1.0: |
|||
rx = x - center |
|||
h = ((math.atan2(ry, rx) / math.pi) + 1.0) / 2.0 |
|||
ry = y - center |
|||
rgb = colorsys.hsv_to_rgb(h, s, 1.0) |
|||
sat = Math.hypot(rx, ry) / radius |
|||
pix[x,y] = tuple([int(round(c*255.0)) for c in rgb]) |
|||
if sat <= 1.0 |
|||
hue = ((Math.atan2(ry, rx) / PI) + 1) / 2.0 |
|||
im.show()</lang> |
|||
color_mode(HSB) |
|||
col = color((hue * 255).to_i, (sat * 255).to_i, 255) |
|||
set(x, y, col) |
|||
end |
|||
end |
|||
end |
|||
</syntaxhighlight> |
|||
=={{header|Run BASIC}}== |
=={{header|Run BASIC}}== |
||
< |
<syntaxhighlight lang="runbasic">' ----------------------------------- |
||
' color wheel |
' color wheel |
||
' ----------------------------------- |
' ----------------------------------- |
||
global pi |
global pi |
||
pi |
pi = 22 / 7 |
||
steps |
steps = 1 |
||
graphic #g, 525, 525 |
graphic #g, 525, 525 |
||
Line 473: | Line 1,447: | ||
for x =0 to 525 step steps |
for x =0 to 525 step steps |
||
for y =0 to 525 step steps |
|||
angle = atan2(y - 250, x - 250) * 360 / 2 / pi ' full degrees.... |
|||
sector = int(angle / 60) ' 60 degree sectors (0 to 5) |
|||
slope = (angle mod 60) /60 * 255 ' 1 degree sectors. |
|||
if sector = 0 then col$ = "255 "; str$( int( slope)); " 0" |
|||
if sector = 1 then col$ = str$(int(256 - slope)); " 255 0" |
|||
if sector = 2 then col$ = "0 255 "; str$( int( slope)) |
|||
if sector = 3 then col$ = "0 "; str$( int( 256 -slope)); " 255" |
|||
if sector = 4 then col$ = str$(int(slope)); " 0 255" |
|||
if sector = 5 then col$ = "255 0 "; str$( int( 256 -slope)) |
|||
red = val( word$( col$, 1)) |
|||
grn = val( word$( col$, 2)) |
|||
blu = val( word$( col$, 3)) |
|||
p = ((x -270)^2 +(y -270)^2)^0.5 / 250 |
|||
r = min(255,p * red) |
|||
g = min(255,p * grn) |
|||
b = min(255,p * blu) |
|||
if p > 1 then #g "color white" else #g color(r,g,b) |
|||
#g "set "; x; " "; y |
|||
next y |
|||
next x |
next x |
||
render #g |
render #g |
||
Line 501: | Line 1,475: | ||
function atan2(y,x) |
function atan2(y,x) |
||
if (x = 0) and (y <> 0) then |
if (x = 0) and (y <> 0) then |
||
r$ = "Y" |
|||
if y > 0 then atan2 = pi /2 |
|||
if y < 0 then atan2 = 3 * pi /2 |
|||
end if |
end if |
||
if y = 0 and (x <> 0) then |
if y = 0 and (x <> 0) then |
||
r$ = "Y" |
|||
if x > 0 then atan2 = 0 |
|||
if x < 0 then atan2 = pi |
|||
end if |
end if |
||
If r$ <> "Y" then |
If r$ <> "Y" then |
||
if x = 0 and y = 0 then |
|||
atan2 = 0 |
|||
else |
|||
baseAngle = atn(abs(y) / abs(x)) |
|||
if x > 0 then |
|||
if y > 0 then atan2 = baseAngle |
|||
If y < 0 then atan2 = 2 * pi - baseAngle |
|||
end if |
|||
if x < 0 then |
|||
If y > 0 then atan2 = pi - baseAngle |
|||
If y < 0 then atan2 = pi + baseAngle |
|||
end if |
|||
end if |
|||
end if |
end if |
||
end function</ |
end function</syntaxhighlight> |
||
=={{header|Rust}}== |
|||
Output is a file in PNG format. |
|||
<syntaxhighlight lang="rust">// [dependencies] |
|||
// image = "0.23" |
|||
use image::error::ImageResult; |
|||
use image::{Rgb, RgbImage}; |
|||
fn hsv_to_rgb(h: f64, s: f64, v: f64) -> Rgb<u8> { |
|||
let hp = h / 60.0; |
|||
let c = s * v; |
|||
let x = c * (1.0 - (hp % 2.0 - 1.0).abs()); |
|||
let m = v - c; |
|||
let mut r = 0.0; |
|||
let mut g = 0.0; |
|||
let mut b = 0.0; |
|||
if hp <= 1.0 { |
|||
r = c; |
|||
g = x; |
|||
} else if hp <= 2.0 { |
|||
r = x; |
|||
g = c; |
|||
} else if hp <= 3.0 { |
|||
g = c; |
|||
b = x; |
|||
} else if hp <= 4.0 { |
|||
g = x; |
|||
b = c; |
|||
} else if hp <= 5.0 { |
|||
r = x; |
|||
b = c; |
|||
} else { |
|||
r = c; |
|||
b = x; |
|||
} |
|||
r += m; |
|||
g += m; |
|||
b += m; |
|||
Rgb([(r * 255.0) as u8, (g * 255.0) as u8, (b * 255.0) as u8]) |
|||
} |
|||
fn write_color_wheel(filename: &str, width: u32, height: u32) -> ImageResult<()> { |
|||
let mut image = RgbImage::new(width, height); |
|||
let margin = 10; |
|||
let diameter = std::cmp::min(width, height) - 2 * margin; |
|||
let xoffset = (width - diameter) / 2; |
|||
let yoffset = (height - diameter) / 2; |
|||
let radius = diameter as f64 / 2.0; |
|||
for x in 0..=diameter { |
|||
let rx = x as f64 - radius; |
|||
for y in 0..=diameter { |
|||
let ry = y as f64 - radius; |
|||
let r = ry.hypot(rx) / radius; |
|||
if r > 1.0 { |
|||
continue; |
|||
} |
|||
let a = 180.0 + ry.atan2(-rx).to_degrees(); |
|||
image.put_pixel(x + xoffset, y + yoffset, hsv_to_rgb(a, r, 1.0)); |
|||
} |
|||
} |
|||
image.save(filename) |
|||
} |
|||
fn main() { |
|||
match write_color_wheel("color_wheel.png", 400, 400) { |
|||
Ok(()) => {} |
|||
Err(error) => eprintln!("{}", error), |
|||
} |
|||
}</syntaxhighlight> |
|||
{{out}} |
|||
[[Media:Color_wheel_rust.png]] |
|||
=={{header|Sidef}}== |
=={{header|Sidef}}== |
||
{{trans| |
{{trans|Raku}} |
||
< |
<syntaxhighlight lang="ruby">require('Imager') |
||
var (width, height) = (300, 300) |
var (width, height) = (300, 300) |
||
Line 547: | Line 1,594: | ||
} |
} |
||
img.write(file => 'color_wheel.png')</ |
img.write(file => 'color_wheel.png')</syntaxhighlight> |
||
Output image: [https://github.com/trizen/rc/blob/master/img/color-wheel-sidef.png Color wheel] |
Output image: [https://github.com/trizen/rc/blob/master/img/color-wheel-sidef.png Color wheel] |
||
=={{header|Smart BASIC}}== |
=={{header|Smart BASIC}}== |
||
< |
<syntaxhighlight lang="smart basic">' Runs on iOS |
||
GET SCREEN SIZE sw,sh |
GET SCREEN SIZE sw,sh |
||
xmax=0.45*3/7*(sw+sh) |
xmax=0.45*3/7*(sw+sh) |
||
Line 596: | Line 1,642: | ||
s5: r=f ! g=0 ! b=1 ! GOTO done |
s5: r=f ! g=0 ! b=1 ! GOTO done |
||
s6: r=1 ! g=0 ! b=z ! done: |
s6: r=1 ! g=0 ! b=z ! done: |
||
END DEF</ |
END DEF</syntaxhighlight> |
||
View the output on Dropbox |
View the output on Dropbox |
||
https://www.dropbox.com/s/g3l5rbywo34bnp6/IMG_4600.PNG?dl=0 |
https://www.dropbox.com/s/g3l5rbywo34bnp6/IMG_4600.PNG?dl=0 |
||
This file is no longer there!!! 10 Sep 2021 |
|||
=={{header|Vala}}== |
|||
{{trans|Julia}} |
|||
<syntaxhighlight lang="vala">public class Example: Gtk.Application { |
|||
private Gtk.ApplicationWindow window; |
|||
private Gtk.DrawingArea drawing_area; |
|||
public Example() { |
|||
Object(application_id: "my.application", flags: ApplicationFlags.FLAGS_NONE); |
|||
this.activate.connect(() => { |
|||
window = new Gtk.ApplicationWindow(this); |
|||
drawing_area = new Gtk.DrawingArea(); |
|||
drawing_area.set_draw_func(draw_circle); |
|||
window.set_child(drawing_area); |
|||
window.present(); |
|||
}); |
|||
} |
|||
private void draw_circle(Gtk.DrawingArea area, Cairo.Context cr, int width, int height) { |
|||
int centerx = width / 2; |
|||
int centery = height / 2; |
|||
double anglestep = 1.0 / width; |
|||
for (float theta = (float) 0.0; theta < 360; theta += (float) 0.1) { |
|||
float r; |
|||
float g; |
|||
float b; |
|||
Gtk.hsv_to_rgb(theta / (float) 360.0, 1, 1, out r, out g, out b); |
|||
cr.set_source_rgb(r, g, b); |
|||
cr.line_to(centerx, centery); |
|||
cr.arc(centerx, centery, ((double) width) / 2.2, GLib.Math.PI * 2 * theta / 360.0, anglestep); |
|||
cr.line_to(centerx, centery); |
|||
cr.stroke(); |
|||
} |
|||
} |
|||
public static int main(string[] argv) { |
|||
var app = new Example(); |
|||
return app.run(argv); |
|||
} |
|||
}</syntaxhighlight> |
|||
=={{header|VBScript}}== |
|||
Building a BMP file and opening it with the default viewer. It takes 5 seconds in my 5 years old notebook. Run with Cscript if you don want to be clicking at annoying message boxes. |
|||
<syntaxhighlight lang="vb"> |
|||
Option explicit |
|||
Class ImgClass |
|||
Private ImgL,ImgH,ImgDepth,bkclr,loc,tt |
|||
private xmini,xmaxi,ymini,ymaxi,dirx,diry |
|||
public ImgArray() 'rgb in 24 bit mode, indexes to palette in 8 bits |
|||
private filename |
|||
private Palette,szpal |
|||
public property get xmin():xmin=xmini:end property |
|||
public property get ymin():ymin=ymini:end property |
|||
public property get xmax():xmax=xmaxi:end property |
|||
public property get ymax():ymax=ymaxi:end property |
|||
public property let depth(x) |
|||
if x<>8 and x<>32 then err.raise 9 |
|||
Imgdepth=x |
|||
end property |
|||
public sub set0 (x0,y0) 'sets the new origin (default tlc). The origin does'nt work if ImgArray is accessed directly |
|||
if x0<0 or x0>=imgl or y0<0 or y0>imgh then err.raise 9 |
|||
xmini=-x0 |
|||
ymini=-y0 |
|||
xmaxi=xmini+imgl-1 |
|||
ymaxi=ymini+imgh-1 |
|||
end sub |
|||
'constructor |
|||
Public Default Function Init(name,w,h,orient,dep,bkg,mipal) |
|||
'offx, offy posicion de 0,0. si ofx+ , x se incrementa de izq a der, si offy+ y se incrementa de abajo arriba |
|||
dim i,j |
|||
ImgL=w |
|||
ImgH=h |
|||
tt=timer |
|||
loc=getlocale |
|||
' not useful as we are not using SetPixel and accessing ImgArray directly |
|||
set0 0,0 'origin blc positive up and right |
|||
redim imgArray(ImgL-1,ImgH-1) |
|||
bkclr=bkg |
|||
if bkg<>0 then |
|||
for i=0 to ImgL-1 |
|||
for j=0 to ImgH-1 |
|||
imgarray(i,j)=bkg |
|||
next |
|||
next |
|||
end if |
|||
Select Case orient |
|||
Case 1: dirx=1 : diry=1 |
|||
Case 2: dirx=-1 : diry=1 |
|||
Case 3: dirx=-1 : diry=-1 |
|||
Case 4: dirx=1 : diry=-1 |
|||
End select |
|||
filename=name |
|||
ImgDepth =dep |
|||
'load user palette if provided |
|||
if imgdepth=8 then |
|||
loadpal(mipal) |
|||
end if |
|||
set init=me |
|||
end function |
|||
private sub loadpal(mipale) |
|||
if isarray(mipale) Then |
|||
palette=mipale |
|||
szpal=UBound(mipale)+1 |
|||
Else |
|||
szpal=256 |
|||
'Default palette recycled from ATARI |
|||
'removed |
|||
, not relevant |
|||
End if |
|||
End Sub |
|||
'class termination writes it to a BMP file and displays it |
|||
'if an error happens VBS terminates the class before exiting so the BMP is displayed the same |
|||
Private Sub Class_Terminate |
|||
if err<>0 then wscript.echo "Error " & err.number |
|||
wscript.echo "copying image to bmp file" |
|||
savebmp |
|||
wscript.echo "opening " & filename & " with your default bmp viewer" |
|||
CreateObject("Shell.Application").ShellExecute filename |
|||
wscript.echo timer-tt & " iseconds" |
|||
End Sub |
|||
function long2wstr( x) 'falta muy poco!!! |
|||
dim k1,k2,x1 |
|||
k1= (x and &hffff&)' or (&H8000& And ((X And &h8000&)<>0))) |
|||
k2=((X And &h7fffffff&) \ &h10000&) Or (&H8000& And (x<0)) |
|||
long2wstr=chrw(k1) & chrw(k2) |
|||
end function |
|||
function int2wstr(x) |
|||
int2wstr=ChrW((x and &h7fff) or (&H8000 And (X<0))) |
|||
End Function |
|||
Public Sub SaveBMP |
|||
'Save the picture to a bmp file |
|||
Dim s,ostream, x,y,loc |
|||
const hdrs=54 '14+40 |
|||
dim bms:bms=ImgH* 4*(((ImgL*imgdepth\8)+3)\4) 'bitmap size including padding |
|||
dim palsize:if (imgdepth=8) then palsize=szpal*4 else palsize=0 |
|||
with CreateObject("ADODB.Stream") 'auxiliary ostream, it creates an UNICODE with bom stream in memory |
|||
.Charset = "UTF-16LE" 'o "UTF16-BE" |
|||
.Type = 2' adTypeText |
|||
.open |
|||
'build a header |
|||
'bmp header: VBSCript does'nt have records nor writes binary values to files, so we use strings of unicode chars!! |
|||
'BMP header |
|||
.writetext ChrW(&h4d42) ' 0 "BM" 4d42 |
|||
.writetext long2wstr(hdrs+palsize+bms) ' 2 fiesize |
|||
.writetext long2wstr(0) ' 6 reserved |
|||
.writetext long2wstr (hdrs+palsize) '10 image offset |
|||
'InfoHeader |
|||
.writetext long2wstr(40) '14 infoheader size |
|||
.writetext long2wstr(Imgl) '18 image length |
|||
.writetext long2wstr(imgh) '22 image width |
|||
.writetext int2wstr(1) '26 planes |
|||
.writetext int2wstr(imgdepth) '28 clr depth (bpp) |
|||
.writetext long2wstr(&H0) '30 compression used 0= NOCOMPR |
|||
.writetext long2wstr(bms) '34 imgsize |
|||
.writetext long2wstr(&Hc4e) '38 bpp hor |
|||
.writetext long2wstr(&hc43) '42 bpp vert |
|||
.writetext long2wstr(szpal) '46 colors in palette |
|||
.writetext long2wstr(&H0) '50 important clrs 0=all |
|||
'write bitmap |
|||
'precalc data for orientation |
|||
Dim x1,x2,y1,y2 |
|||
If dirx=-1 Then x1=ImgL-1 :x2=0 Else x1=0:x2=ImgL-1 |
|||
If diry=-1 Then y1=ImgH-1 :y2=0 Else y1=0:y2=ImgH-1 |
|||
Select Case imgdepth |
|||
Case 32 |
|||
For y=y1 To y2 step diry |
|||
For x=x1 To x2 Step dirx |
|||
'writelong fic, Pixel(x,y) |
|||
.writetext long2wstr(Imgarray(x,y)) |
|||
Next |
|||
Next |
|||
Case 8 |
|||
'palette |
|||
For x=0 to szpal-1 |
|||
.writetext long2wstr(palette(x)) '52 |
|||
Next |
|||
'image |
|||
dim pad:pad=ImgL mod 4 |
|||
For y=y1 to y2 step diry |
|||
For x=x1 To x2 step dirx*2 |
|||
.writetext chrw((ImgArray(x,y) and 255)+ &h100& *(ImgArray(x+dirx,y) and 255)) |
|||
Next |
|||
'line padding |
|||
if pad and 1 then .writetext chrw(ImgArray(x2,y)) |
|||
if pad >1 then .writetext chrw(0) |
|||
Next |
|||
Case Else |
|||
WScript.Echo "ColorDepth not supported : " & ImgDepth & " bits" |
|||
End Select |
|||
'use a second stream to save to file starting past the BOM the first ADODB.Stream has added |
|||
Dim outf:Set outf= CreateObject("ADODB.Stream") |
|||
outf.Type = 1 ' adTypeBinary |
|||
outf.Open |
|||
.position=2 'remove bom (1 wchar) |
|||
.CopyTo outf |
|||
.close |
|||
outf.savetofile filename,2 'adSaveCreateOverWrite |
|||
outf.close |
|||
end with |
|||
End Sub |
|||
end class |
|||
function hsv2rgb( Hue, Sat, Value) 'hue 0-360 0-ro 120-ver 240-az ,sat 0-100,value 0-100 |
|||
dim Angle, Radius,Ur,Vr,Wr,Rdim |
|||
dim r,g,b, rgb |
|||
Angle = (Hue-150) *0.01745329251994329576923690768489 |
|||
Ur = Value * 2.55 |
|||
Radius = Ur * tan(Sat *0.01183199) |
|||
Vr = Radius * cos(Angle) *0.70710678 'sqrt(1/2) |
|||
Wr = Radius * sin(Angle) *0.40824829 'sqrt(1/6) |
|||
r = (Ur - Vr - Wr) |
|||
g = (Ur + Vr - Wr) |
|||
b = (Ur + Wr + Wr) |
|||
'clamp values |
|||
if r >255 then |
|||
Rdim = (Ur - 255) / (Vr + Wr) |
|||
r = 255 |
|||
g = Ur + (Vr - Wr) * Rdim |
|||
b = Ur + 2 * Wr * Rdim |
|||
elseif r < 0 then |
|||
Rdim = Ur / (Vr + Wr) |
|||
r = 0 |
|||
g = Ur + (Vr - Wr) * Rdim |
|||
b = Ur + 2 * Wr * Rdim |
|||
end if |
|||
if g >255 then |
|||
Rdim = (255 - Ur) / (Vr - Wr) |
|||
r = Ur - (Vr + Wr) * Rdim |
|||
g = 255 |
|||
b = Ur + 2 * Wr * Rdim |
|||
elseif g<0 then |
|||
Rdim = -Ur / (Vr - Wr) |
|||
r = Ur - (Vr + Wr) * Rdim |
|||
g = 0 |
|||
b = Ur + 2 * Wr * Rdim |
|||
end if |
|||
if b>255 then |
|||
Rdim = (255 - Ur) / (Wr + Wr) |
|||
r = Ur - (Vr + Wr) * Rdim |
|||
g = Ur + (Vr - Wr) * Rdim |
|||
b = 255 |
|||
elseif b<0 then |
|||
Rdim = -Ur / (Wr + Wr) |
|||
r = Ur - (Vr + Wr) * Rdim |
|||
g = Ur + (Vr - Wr) * Rdim |
|||
b = 0 |
|||
end If |
|||
'b lowest byte, red highest byte |
|||
hsv2rgb= ((b and &hff)+256*((g and &hff)+256*(r and &hff))and &hffffff) |
|||
end function |
|||
function ang(col,row) |
|||
'if col =0 then if row>0 then ang=0 else ang=180:exit function |
|||
if col =0 then |
|||
if row<0 then ang=90 else ang=270 end if |
|||
else |
|||
if col>0 then |
|||
ang=atn(-row/col)*57.2957795130 |
|||
else |
|||
ang=(atn(row/-col)*57.2957795130)+180 |
|||
end if |
|||
end if |
|||
ang=(ang+360) mod 360 |
|||
end function |
|||
Dim X,row,col,fn,tt,hr,sat,row2 |
|||
const h=160 |
|||
const w=160 |
|||
const rad=159 |
|||
const r2=25500 |
|||
tt=timer |
|||
fn=CreateObject("Scripting.FileSystemObject").GetSpecialFolder(2)& "\testwchr.bmp" |
|||
Set X = (New ImgClass)(fn,w*2,h*2,1,32,0,0) |
|||
x.set0 w,h |
|||
'wscript.echo x.xmax, x.xmin |
|||
for row=x.xmin+1 to x.xmax |
|||
row2=row*row |
|||
hr=int(Sqr(r2-row2)) |
|||
For col=hr To 159 |
|||
Dim a:a=((col\16 +row\16) And 1)* &hffffff |
|||
x.imgArray(col+160,row+160)=a |
|||
x.imgArray(-col+160,row+160)=a |
|||
next |
|||
for col=-hr to hr |
|||
sat=100-sqr(row2+col*col)/rad *50 |
|||
' wscript.echo c,r |
|||
x.imgArray(col+160,row+160)=hsv2rgb(ang(row,col)+90,100,sat) |
|||
next |
|||
'script.echo row |
|||
next |
|||
Set X = Nothing |
|||
</syntaxhighlight> |
|||
=={{out}}== |
|||
[[File:Colorwheel vbs.png]] |
|||
=={{header|Wren}}== |
|||
{{libheader|DOME}} |
|||
<syntaxhighlight lang="wren">import "graphics" for Canvas, Color |
|||
import "dome" for Window |
|||
import "random" for Random |
|||
class Game { |
|||
static init() { |
|||
Window.title = "Color Wheel" |
|||
__width = 640 |
|||
__height = 640 |
|||
Window.resize(__width, __height) |
|||
Canvas.resize(__width, __height) |
|||
colorWheel() |
|||
} |
|||
static colorWheel() { |
|||
var cx = (__width/2).floor |
|||
var cy = (__height/2).floor |
|||
var r = (cx < cy) ? cx : cy |
|||
for (y in 0...__height) { |
|||
var dy = y - cy |
|||
for (x in 0...__width) { |
|||
var dx = x - cx |
|||
var dist = (dx*dx + dy*dy).sqrt |
|||
if (dist <= r) { |
|||
var theta = dy.atan(dx) |
|||
var h = (theta + Num.pi) / Num.pi * 180 |
|||
var col = Color.hsv(h, dist/r, 1) |
|||
Canvas.pset(x, y, col) |
|||
} |
|||
} |
|||
} |
|||
} |
|||
static update() {} |
|||
static draw(alpha) {} |
|||
}</syntaxhighlight> |
|||
=={{header|XPL0}}== |
|||
Algorithm is from "Computer Graphics ..." by Foley et al. The output is the same as Zkl. |
|||
<syntaxhighlight lang="xpl0">def Radius = 480/2; |
|||
real Hue, Sat, Dist, I, F, P, Q, T; |
|||
real XX, YY, RR, GG, BB; |
|||
int X, Y, R, G, B; |
|||
def Pi = 3.141592654; |
|||
def V = 1.; \Value |
|||
[SetVid($112); \640x480x24 graphics |
|||
for Y:= -Radius to Radius do |
|||
for X:= -Radius to Radius do |
|||
[XX:= float(X); |
|||
YY:= float(Y); |
|||
Dist:= sqrt(XX*XX + YY*YY); |
|||
if Dist <= float(Radius) then |
|||
[Sat:= Dist/float(Radius); \0 >= Sat <= 1 |
|||
Hue:= ATan2(YY, XX); \-Pi >= Hue <= Pi |
|||
if Hue < 0. then Hue:= Hue + 2.*Pi; |
|||
Hue:= Hue * 180./Pi; \radians to degrees |
|||
Hue:= Hue / 60.; \0 >= Hue < 6 |
|||
I:= Floor(Hue); \integer part of Hue |
|||
F:= Hue - I; \fractional part of Hue |
|||
P:= 1. - Sat; |
|||
Q:= 1. - Sat*F; |
|||
T:= 1. - Sat*(1.-F); |
|||
case fix(I) of |
|||
0: [RR:= V; GG:= T; BB:= P]; |
|||
1: [RR:= Q; GG:= V; BB:= P]; |
|||
2: [RR:= P; GG:= V; BB:= T]; |
|||
3: [RR:= P; GG:= Q; BB:= V]; |
|||
4: [RR:= T; GG:= P; BB:= V]; |
|||
5: [RR:= V; GG:= P; BB:= Q] |
|||
other [exit 1]; |
|||
R:= fix(RR*255.); |
|||
G:= fix(GG*255.); |
|||
B:= fix(BB*255.); |
|||
Point(X+Radius, Radius-Y, R<<16+G<<8+B); |
|||
]; |
|||
]; |
|||
]</syntaxhighlight> |
|||
=={{header|zkl}}== |
=={{header|zkl}}== |
||
Uses Image Magick and |
Uses Image Magick and |
||
the PPM class from http://rosettacode.org/wiki/Bitmap/Bresenham%27s_line_algorithm#zkl |
the PPM class from http://rosettacode.org/wiki/Bitmap/Bresenham%27s_line_algorithm#zkl |
||
< |
<syntaxhighlight lang="zkl">var w=300,h=300,out=PPM(w,h); |
||
colorWheel(out); |
colorWheel(out); |
||
out.writeJPGFile("colorWheel.zkl.jpg"); |
out.writeJPGFile("colorWheel.zkl.jpg"); |
||
Line 612: | Line 2,065: | ||
v,hue:=(x - zero).toFloat().toPolar(y - zero); |
v,hue:=(x - zero).toFloat().toPolar(y - zero); |
||
if(v<=R){ // only render in the circle |
if(v<=R){ // only render in the circle |
||
if((hue = hue.toDeg())<0) hue+=360; // (-pi..pi] to [0..2pi) |
|||
s:=v/R; // scale saturation zero at center to 1 at edge |
|||
ppm[x,y]=hsv2rgb(hue,1.0,s); |
|||
} |
} |
||
} |
} |
||
Line 620: | Line 2,073: | ||
fcn hsv2rgb(hue,v,s){ // 0<=H<360, 0<=v(brightness)<=1, 0<=saturation<=1 |
fcn hsv2rgb(hue,v,s){ // 0<=H<360, 0<=v(brightness)<=1, 0<=saturation<=1 |
||
// --> 24 bit RGB each R,G,B in [0..255] |
|||
to24bit:=fcn(r,g,b,m){ |
to24bit:=fcn(r,g,b,m){ |
||
r,g,b=((r+m)*255).toInt(),((g+m)*255).toInt(),((b+m)*255).toInt(); |
r,g,b=((r+m)*255).toInt(),((g+m)*255).toInt(),((b+m)*255).toInt(); |
||
Line 633: | Line 2,086: | ||
else if(180<=hue<240) return(to24bit(0.0,x, c, m)); |
else if(180<=hue<240) return(to24bit(0.0,x, c, m)); |
||
else if(240<=hue<300) return(to24bit(x, 0.0,c, m)); |
else if(240<=hue<300) return(to24bit(x, 0.0,c, m)); |
||
else |
else return(to24bit(c, 0.0,x, m)); |
||
}</ |
}</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
See [http://www.zenkinetic.com/Images/RosettaCode/colorWheel.zkl.jpg this image] |
See [http://www.zenkinetic.com/Images/RosettaCode/colorWheel.zkl.jpg this image] |
||
==References== |
|||
<references/> |
Latest revision as of 21:57, 18 March 2024
You are encouraged to solve this task according to the task description, using any language you may know.
- Task
Write a function to draw a HSV color wheel completely with code.
This is strictly for learning purposes only. It's highly recommended that you use an image in an actual application to actually draw the color wheel (as procedurally drawing is super slow). This does help you understand how color wheels work and this can easily be used to determine a color value based on a position within a circle.
Applesoft BASIC
The lo-resolution GRaphics screen is limited to 16 colors. Ordered dithering is used for the saturation. Pink is mixed with violet and magenta, and aqua is mixed with light blue and green. These lighter colors are randomly mixed with the saturation dither. Note that the four Apple II colors can be seen at the 90 degree marks: orange at 30 degrees, green at 120 degrees, cyan (blue) at 210 degrees, and violet at 300 degrees.
100 LET R = 3.1415926535 / 180
110 LET YO = 20
120 LET XO = YO
130 LET MS = INT (YO * 7 / 8)
140 LET O$ = "1111111111.1111111110.1111011110.1101110110.1101010110.1010101010.0010101001.0010001001.0000100001.0000000001.0000000000"
150 GR
160 FOR S = 0 TO MS
170 LET D = S / MS
180 LET P$ = MID$ (O$, INT (D * 10) * 11 + 1,11)
190 LET SY = S
200 LET SX = S * 4 / 7
210 LET P = 0
220 FOR I = 0 TO 360
230 LET X = XO + SIN (I * R) * SX
240 LET Y = YO + COS (I * R) * SY
250 LET W = 15
260 IF I > = 30 - 22.4 AND I < 30 + 22.5 THEN COLOR= 9
270 IF I > = 75 - 22.5 AND I < 75 + 22.5 THEN COLOR= 13
280 IF I > = 120 - 22.5 AND I < 120 + 22.5 THEN COLOR= 12:W = 14
290 IF I > = 165 - 22.5 AND I < 165 + 22.5 THEN COLOR= 7:W = 14
300 IF I > = 210 - 22.5 AND I < 210 + 22.5 THEN COLOR= 6
310 IF I > = 255 - 22.5 AND I < 255 + 22.5 THEN COLOR= 2
320 IF I > = 300 - 22.5 AND I < 300 + 22.5 THEN COLOR= 3:W = 11
330 IF I > = 345 - 22.5 OR I < 345 + 22.5 - 360 THEN COLOR= 1:W = 11
340 IF D < .2 THEN W = 15
350 IF RND (1) < D THEN W = 15
360 IF VAL ( MID$ (P$,P + 1,1)) THEN COLOR= W
370 IF SCRN( X,Y) = 0 THEN PLOT X,Y:P = P + 1: IF P > = 9 THEN P = 0
380 NEXT I,S
AppleScript
choose color default color {0, 0, 0, 0}
C++
This program draws an HSV color wheel in a window.
// colorwheelwidget.cpp
#include "colorwheelwidget.h"
#include <QPainter>
#include <QPaintEvent>
#include <cmath>
namespace {
QColor hsvToRgb(int h, double s, double v) {
double hp = h/60.0;
double c = s * v;
double x = c * (1 - std::abs(std::fmod(hp, 2) - 1));
double m = v - c;
double r = 0, g = 0, b = 0;
if (hp <= 1) {
r = c;
g = x;
} else if (hp <= 2) {
r = x;
g = c;
} else if (hp <= 3) {
g = c;
b = x;
} else if (hp <= 4) {
g = x;
b = c;
} else if (hp <= 5) {
r = x;
b = c;
} else {
r = c;
b = x;
}
r += m;
g += m;
b += m;
return QColor(r * 255, g * 255, b * 255);
}
}
ColorWheelWidget::ColorWheelWidget(QWidget *parent)
: QWidget(parent) {
setWindowTitle(tr("Color Wheel"));
resize(400, 400);
}
void ColorWheelWidget::paintEvent(QPaintEvent *event) {
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing);
const QColor backgroundColor(0, 0, 0);
const QColor white(255, 255, 255);
painter.fillRect(event->rect(), backgroundColor);
const int margin = 10;
const double diameter = std::min(width(), height()) - 2*margin;
QPointF center(width()/2.0, height()/2.0);
QRectF rect(center.x() - diameter/2.0, center.y() - diameter/2.0,
diameter, diameter);
for (int angle = 0; angle < 360; ++angle) {
QColor color(hsvToRgb(angle, 1.0, 1.0));
QRadialGradient gradient(center, diameter/2.0);
gradient.setColorAt(0, white);
gradient.setColorAt(1, color);
QBrush brush(gradient);
QPen pen(brush, 1.0);
painter.setPen(pen);
painter.setBrush(brush);
painter.drawPie(rect, angle * 16, 16);
}
}
// colorwheelwidget.h
#ifndef COLORWHEELWIDGET_H
#define COLORWHEELWIDGET_H
#include <QWidget>
class ColorWheelWidget : public QWidget {
Q_OBJECT
public:
ColorWheelWidget(QWidget *parent = nullptr);
protected:
void paintEvent(QPaintEvent *event) override;
};
#endif // COLORWHEELWIDGET_H
// main.cpp
#include "colorwheelwidget.h"
#include <QApplication>
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
ColorWheelWidget widget;
widget.show();
return app.exec();
}
- Output:
C#
// constructor of main window
// in MainWindow.xaml just create <Image Name="imgMain" />
public MainWindow()
{
InitializeComponent();
RenderOptions.SetBitmapScalingMode(imgMain, BitmapScalingMode.HighQuality);
imgMain.Source = new WriteableBitmap(480, 480, 96, 96, PixelFormats.Bgr32, null);
// using slider you can change saturation and call DrawHue with different level
DrawHue(100);
}
void DrawHue(int saturation)
{
var bmp = (WriteableBitmap)imgMain.Source;
int centerX = (int)bmp.Width / 2;
int centerY = (int)bmp.Height / 2;
int radius = Math.Min(centerX, centerY);
int radius2 = radius - 40;
bmp.Lock();
unsafe{
var buf = bmp.BackBuffer;
IntPtr pixLineStart;
for(int y=0; y < bmp.Height; y++){
pixLineStart = buf + bmp.BackBufferStride * y;
double dy = (y - centerY);
for(int x=0; x < bmp.Width; x++){
double dx = (x - centerX);
double dist = Math.Sqrt(dx * dx + dy * dy);
if (radius2 <= dist && dist <= radius) {
double theta = Math.Atan2(dy, dx);
double hue = (theta + Math.PI) / (2.0 * Math.PI);
*((int*)(pixLineStart + x * 4)) = HSB_to_RGB((int)(hue * 360), saturation, 100);
}
}
}
}
bmp.AddDirtyRect(new Int32Rect(0, 0, 480, 480));
bmp.Unlock();
}
static int HSB_to_RGB(int h, int s, int v)
{
var rgb = new int[3];
var baseColor = (h + 60) % 360 / 120;
var shift = (h + 60) % 360 - (120 * baseColor + 60 );
var secondaryColor = (baseColor + (shift >= 0 ? 1 : -1) + 3) % 3;
//Setting Hue
rgb[baseColor] = 255;
rgb[secondaryColor] = (int) ((Math.Abs(shift) / 60.0f) * 255.0f);
//Setting Saturation
for (var i = 0; i < 3; i++)
rgb[i] += (int) ((255 - rgb[i]) * ((100 - s) / 100.0f));
//Setting Value
for (var i = 0; i < 3; i++)
rgb[i] -= (int) (rgb[i] * (100-v) / 100.0f);
return RGB2int(rgb[0], rgb[1], rgb[2]);
}
public static int RGB2int(int r, int g, int b) => r << 16 | g << 8 | b;
- Output:
Delphi
program Color_wheel;
{$APPTYPE CONSOLE}
uses
Winapi.Windows,
System.SysUtils,
Vcl.Graphics,
System.Math,
Vcl.Imaging.pngimage;
const
TAU = 2 * PI;
function HSBtoColor(hue, sat, bri: Double): TColor;
var
f, h: Double;
u, p, q, t: Byte;
begin
u := Trunc(bri * 255 + 0.5);
if sat = 0 then
Exit(rgb(u, u, u));
h := (hue - Floor(hue)) * 6;
f := h - Floor(h);
p := Trunc(bri * (1 - sat) * 255 + 0.5);
q := Trunc(bri * (1 - sat * f) * 255 + 0.5);
t := Trunc(bri * (1 - sat * (1 - f)) * 255 + 0.5);
case Trunc(h) of
0:
result := rgb(u, t, p);
1:
result := rgb(q, u, p);
2:
result := rgb(p, u, t);
3:
result := rgb(p, q, u);
4:
result := rgb(t, p, u);
5:
result := rgb(u, p, q);
else
result := clwhite;
end;
end;
function ColorWheel(Width, Height: Integer): TPngImage;
var
Center: TPoint;
Radius: Integer;
x, y: Integer;
Hue, dy, dx, dist, theta: Double;
Bmp: TBitmap;
begin
Bmp := TBitmap.Create;
Bmp.SetSize(Width, Height);
with Bmp.Canvas do
begin
Brush.Color := clWhite;
FillRect(ClipRect);
Center := ClipRect.CenterPoint;
Radius := Center.X;
if Center.Y < Radius then
Radius := Center.Y;
for y := 0 to Height - 1 do
begin
dy := y - Center.y;
for x := 0 to Width - 1 do
begin
dx := x - Center.x;
dist := Sqrt(Sqr(dx) + Sqr(dy));
if dist <= Radius then
begin
theta := ArcTan2(dy, dx);
Hue := (theta + PI) / TAU;
Pixels[x, y] := HSBtoColor(Hue, 1, 1);
end;
end;
end;
end;
Result := TPngImage.Create;
Result.Assign(Bmp);
Bmp.Free;
end;
begin
with ColorWheel(500, 500) do
begin
SaveToFile('ColorWheel.png');
Free;
end;
end.
- Output:
Png Image [1].
EasyLang
proc hsb2rgb hue sat bri . r g b .
h = (hue - floor hue) * 6
f = h - floor h
p = bri * (1 - sat)
q = bri * (1 - sat * f)
t = bri * (1 - sat * (1 - f))
h = floor h
if h = 0
r = bri ; g = t ; b = p
elif h = 1
r = q ; g = bri ; b = p
elif h = 2
r = p ; g = bri ; b = t
elif h = 3
r = p ; g = q ; b = bri
elif h = 4
r = t ; g = p ; b = bri
else
r = bri ; g = p ; b = q
.
.
proc cwheel . .
for y = 0 to 499
dy = y - 250
for x = 0 to 499
dx = x - 250
dist = sqrt (dx * dx + dy * dy)
if dist <= 250
theta = atan2 dy dx
hue = (theta + 180) / 360
hsb2rgb hue (dist / 250) 1 r g b
color3 r g b
move x / 5 y / 5
rect 0.3 0.3
.
.
.
.
cwheel
Fōrmulæ
Fōrmulæ programs are not textual, visualization/edition of programs is done showing/manipulating structures but not text. Moreover, there can be multiple visual representations of the same program. Even though it is possible to have textual representation —i.e. XML, JSON— they are intended for storage and transfer purposes more than visualization and edition.
Programs in Fōrmulæ are created/edited online in its website.
In this page you can see and run the program(s) related to this task and their results. You can also change either the programs or the parameters they are called with, for experimentation, but remember that these programs were created with the main purpose of showing a clear solution of the task, and they generally lack any kind of validation.
Solution
Test case
Generating a color wheel of 300x300 pixels:
FreeBASIC
#include "fbgfx.bi"
Sub HSVtoRGB(h As Single, s As Integer, v As Integer, Byref r As Integer, Byref g As Integer, Byref b As Integer)
If s = 0 Then
r = v
g = v
b = v
Return
End If
h = h Mod 360
Dim As Single hue = h
Select Case h
Case 0f To 51.5f
hue = ((hue ) * (30f / (51.5f )))
Case 51.5f To 122f
hue = ((hue - 51.5f) * (30f / (122f - 51.5f))) + 30
Case 122f To 142.5f
hue = ((hue - 122f) * (30f / (142.5f - 122f))) + 60
Case 142.5f To 165.5f
hue = ((hue - 142.5f) * (30f / (165.5f - 142.5f))) + 90
Case 165.5f To 192f
hue = ((hue - 165.5f) * (30f / (192f - 165.5f))) + 120
Case 192f To 218.5f
hue = ((hue - 192f) * (30f / (218.5f - 192f))) + 150
Case 218.5f To 247f
hue = ((hue - 218.5f) * (30f / (247f - 218.5f))) + 180
Case 247f To 275.5f
hue = ((hue - 247f) * (30f / (275.5f - 247f))) + 210
Case 275.5f To 302.5f
hue = ((hue - 275.5f) * (30f / (302.5f - 275.5f))) + 240
Case 302.5f To 330f
hue = ((hue - 302.5f) * (30f / (330f - 302.5f))) + 270
Case 330f To 344.5f
hue = ((hue - 330f) * (30f / (344.5f - 330f))) + 300
Case 344.5f To 360f
hue = ((hue - 344.5f) * (30f / (360f - 344.5f))) + 330
End Select
h = hue
h = h Mod 360
Dim As Single h1 = h / 60
Dim As Integer i = Int(h1)
Dim As Single f = h1 - i
Dim As Integer p = v * (255 - s) / 256
Dim As Integer q = v * (255 - f * s) / 256
Dim As Integer t = v * (255 - (1 - f) * s) / 256
Select Case As Const i
Case 0
r = v
g = t
b = p
Return
Case 1
r = q
g = v
b = p
Return
Case 2
r = p
g = v
b = t
Return
Case 3
r = p
g = q
b = v
Return
Case 4
r = t
g = p
b = v
Return
Case 5
r = v
g = p
b = q
Return
End Select
End Sub
Const pi As Single = 4 * Atn(1)
Const radius = 160
Const xres = (radius * 2) + 1, yres = xres
Screenres xres, yres, 32
Windowtitle "Color wheel"
Dim As Integer r,g,b
Dim As Single dx, dy, dist, angle
Do
Screenlock
Cls
For x As Integer = 0 To (radius * 2) - 1
For y As Integer = 0 To (radius * 2) - 1
dx = x - radius
dy = radius - y
dist = Sqr(dx * dx + dy * dy)
If dist < radius Then
angle = Atan2(dy, dx) * (180/pi)
If angle < 0 Then angle += 360
If angle > 360 Then angle -= 360
HSVtoRGB(angle, (dist / radius) * 255, 255, r, g, b)
Pset(x, y), Rgb(r, g, b)
End If
Next y
Next x
Screenunlock
Loop Until Inkey = Chr(27)
FutureBasic
FB has native functions for programmatically building color wheels.
_window = 1
begin enum output 1
_colorwheelImageView
end enum
void local fn BuildWindow
CGRect r = fn CGRectMake( 0, 0, 400, 400 )
window _window, @"Programmatic Color Wheel", r, NSWindowStyleMaskTitled + NSWindowStyleMaskClosable
r = fn CGRectMake( 20, 20, 360, 360 )
imageview _colorwheelImageView, YES, , r, NSImageScaleProportionallyUpOrDown, NSImageAlignCenter, NSImageFrameNone, _window
end fn
local fn CIImageToImageRef( ciImage as CIImageRef ) as ImageRef
CIImageRepRef rep = fn CIImageRepWithCIImage( ciImage )
CGSize size = fn ImageRepSize( rep )
ImageRef image = fn ImageWithSize( size )
ImageAddRepresentation( image, rep )
end fn = image
local fn ColorWheelImage( colorSpace as CGColorSpaceRef, dither as CFNumberRef, radius as CFNumberRef, softness as CFNumberRef, lightness as CFNumberRef ) as CIImageRef
CIFilterRef filter = fn CIFilterWithName( @"CIHueSaturationValueGradient" )
ObjectSetValueForkey( filter, colorSpace, @"inputColorSpace" )
ObjectSetValueForkey( filter, dither, @"inputDither" )
ObjectSetValueForkey( filter, radius, @"inputRadius" )
ObjectSetValueForkey( filter, softness, @"inputSoftness" )
ObjectSetValueForkey( filter, lightness, @"inputValue" )
CIImageRef outputCIImage = fn CIFilterOutputImage( filter )
end fn = outputCIImage
local fn BuildColorWheel
CIImageRef colorWheelCIImage = fn ColorWheelImage( fn CGColorSpaceCreateDeviceRGB, @0, @160, @0, @1 )
ImageRef colorWheelImage = fn CIImageToImageRef( colorWheelCIImage )
ImageViewSetImage( _colorwheelImageView, colorWheelImage )
end fn
fn BuildWindow
fn BuildColorWheel
HandleEvents
- Output:
GML
for (var i = 1; i <= 360; i++) {
for (var j = 0; j < 255; j++) {
var hue = 255*(i/360);
var saturation = j;
var value = 255;
var c = make_colour_hsv(hue,saturation,value);
//size of circle determined by how far from the center it is
//if you just draw them too small the circle won't be full.
//it will have patches inside it that didn't get filled in with color
var r = max(1,3*(j/255));
//Math for built-in GMS functions
//lengthdir_x(len,dir) = +cos(degtorad(direction))*length;
//lengthdir_y(len,dir) = -sin(degtorad(direction))*length;
draw_circle_colour(x+lengthdir_x(m_radius*(j/255),i),y+lengthdir_y(m_radius*(j/255),i),r,c,c,false);
}
}
Go
package main
import (
"github.com/fogleman/gg"
"math"
)
const tau = 2 * math.Pi
func hsb2rgb(hue, sat, bri float64) (r, g, b int) {
u := int(bri*255 + 0.5)
if sat == 0 {
r, g, b = u, u, u
} else {
h := (hue - math.Floor(hue)) * 6
f := h - math.Floor(h)
p := int(bri*(1-sat)*255 + 0.5)
q := int(bri*(1-sat*f)*255 + 0.5)
t := int(bri*(1-sat*(1-f))*255 + 0.5)
switch int(h) {
case 0:
r, g, b = u, t, p
case 1:
r, g, b = q, u, p
case 2:
r, g, b = p, u, t
case 3:
r, g, b = p, q, u
case 4:
r, g, b = t, p, u
case 5:
r, g, b = u, p, q
}
}
return
}
func colorWheel(dc *gg.Context) {
width, height := dc.Width(), dc.Height()
centerX, centerY := width/2, height/2
radius := centerX
if centerY < radius {
radius = centerY
}
for y := 0; y < height; y++ {
dy := float64(y - centerY)
for x := 0; x < width; x++ {
dx := float64(x - centerX)
dist := math.Sqrt(dx*dx + dy*dy)
if dist <= float64(radius) {
theta := math.Atan2(dy, dx)
hue := (theta + math.Pi) / tau
r, g, b := hsb2rgb(hue, 1, 1)
dc.SetRGB255(r, g, b)
dc.SetPixel(x, y)
}
}
}
}
func main() {
const width, height = 480, 480
dc := gg.NewContext(width, height)
dc.SetRGB(1, 1, 1) // set background color to white
dc.Clear()
colorWheel(dc)
dc.SavePNG("color_wheel.png")
}
- Output:
Image is same as Kotlin entry
J
rgbc=: {{1-x*0>.1<.(<.4&-)6|m+y%60}}
hsv=: 5 rgbc(,"0 1) 3 rgbc(,"0) 1 rgbc
degrees=: {{180p_1*{:"1+.^.y}}
wheel=: {{((1>:|)*|hsv degrees)j./~y%~i:y}}
require'viewmat'
'rgb' viewmat 256#.<.255*wheel 400
The right argument to wheel determines the radius (in pixels) of the color wheel (with a white pixel in the center), so the diameter of the above color wheel is 801 pixels.
Here's a representation of wheel 5:
Here's an online implementation for wheel 80 (hit "Run" in the upper right corner).
Java
This program draws a color wheel in a window.
import java.awt.*;
import javax.swing.*;
public class ColorWheel {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
ColorWheelFrame frame = new ColorWheelFrame();
frame.setVisible(true);
}
});
}
private static class ColorWheelFrame extends JFrame {
private ColorWheelFrame() {
super("Color Wheel");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
getContentPane().add(new ColorWheelPanel());
pack();
}
}
private static class ColorWheelPanel extends JComponent {
private ColorWheelPanel() {
setPreferredSize(new Dimension(400, 400));
}
public void paint(Graphics g) {
Graphics2D g2 = (Graphics2D)g;
int w = getWidth();
int h = getHeight();
int margin = 10;
int radius = (Math.min(w, h) - 2 * margin)/2;
int cx = w/2;
int cy = h/2;
float[] dist = {0.F, 1.0F};
g2.setColor(Color.BLACK);
g2.fillRect(0, 0, w, h);
for (int angle = 0; angle < 360; ++angle) {
Color color = hsvToRgb(angle, 1.0, 1.0);
Color[] colors = {Color.WHITE, color};
RadialGradientPaint paint = new RadialGradientPaint(cx, cy,
radius, dist, colors);
g2.setPaint(paint);
g2.fillArc(cx - radius, cy - radius, radius*2, radius*2,
angle, 1);
}
}
}
private static Color hsvToRgb(int h, double s, double v) {
double hp = h/60.0;
double c = s * v;
double x = c * (1 - Math.abs(hp % 2.0 - 1));
double m = v - c;
double r = 0, g = 0, b = 0;
if (hp <= 1) {
r = c;
g = x;
} else if (hp <= 2) {
r = x;
g = c;
} else if (hp <= 3) {
g = c;
b = x;
} else if (hp <= 4) {
g = x;
b = c;
} else if (hp <= 5) {
r = x;
b = c;
} else {
r = c;
b = x;
}
r += m;
g += m;
b += m;
return new Color((int)(r * 255), (int)(g * 255), (int)(b * 255));
}
}
- Output:
Julia
using Gtk, Graphics, Colors
const win = GtkWindow("Color Wheel", 450, 450) |> (const can = @GtkCanvas())
set_gtk_property!(can, :expand, true)
@guarded draw(can) do widget
ctx = getgc(can)
h = height(can)
w = width(can)
center = (x = w / 2, y = h / 2)
anglestep = 1/w
for θ in 0:0.1:360
rgb = RGB(HSV(θ, 1, 1))
set_source_rgb(ctx, rgb.r, rgb.g, rgb.b)
line_to(ctx, center...)
arc(ctx, center.x, center.y, w/2.2, 2π * θ / 360, anglestep)
line_to(ctx, center...)
stroke(ctx)
end
end
show(can)
const condition = Condition()
endit(w) = notify(condition)
signal_connect(endit, win, :destroy)
wait(condition)
Kotlin
We reuse the class in the Bitmap task for this and add a member function to draw the color wheel. To give a more 'wheel-like' image, a constant 'saturation' of 1.0 has been used rather than one which varies in line with distance from the center.
// Version 1.2.41
import java.awt.Color
import java.awt.Graphics
import java.awt.image.BufferedImage
import java.io.File
import javax.imageio.ImageIO
import kotlin.math.*
class BasicBitmapStorage(width: Int, height: Int) {
val image = BufferedImage(width, height, BufferedImage.TYPE_3BYTE_BGR)
fun fill(c: Color) {
val g = image.graphics
g.color = c
g.fillRect(0, 0, image.width, image.height)
}
fun setPixel(x: Int, y: Int, c: Color) = image.setRGB(x, y, c.getRGB())
fun getPixel(x: Int, y: Int) = Color(image.getRGB(x, y))
fun colorWheel() {
val centerX = image.width / 2
val centerY = image.height / 2
val radius = minOf(centerX, centerY)
for (y in 0 until image.height) {
val dy = (y - centerY).toDouble()
for (x in 0 until image.width) {
val dx = (x - centerX).toDouble()
val dist = sqrt(dx * dx + dy * dy)
if (dist <= radius) {
val theta = atan2(dy, dx)
val hue = (theta + PI) / (2.0 * PI)
val rgb = Color.HSBtoRGB(hue.toFloat(), 1.0f, 1.0f)
setPixel(x, y, Color(rgb))
}
}
}
}
}
fun main(args: Array<String>) {
val bbs = BasicBitmapStorage(480, 480)
with (bbs) {
fill(Color.white)
colorWheel()
val cwFile = File("Color_wheel.png")
ImageIO.write(image, "png", cwFile)
}
}
- Output:
Looks like mirror image of Smart BASIC entry
Lua
local function hsv_to_rgb (h, s, v) -- values in ranges: [0, 360], [0, 1], [0, 1]
local r = math.min (math.max (3*math.abs (((h )/180)%2-1)-1, 0), 1)
local g = math.min (math.max (3*math.abs (((h -120)/180)%2-1)-1, 0), 1)
local b = math.min (math.max (3*math.abs (((h +120)/180)%2-1)-1, 0), 1)
local k1 = v*(1-s)
local k2 = v - k1
return k1+k2*r, k1+k2*g, k1+k2*b -- values in ranges: [0, 1], [0, 1], [0, 1]
end
function love.load()
local w, h, r = 256, 256, 128-0.5
local cx, cy = w/2, h/2
canvas = love.graphics.newCanvas ()
love.graphics.setCanvas(canvas)
for x = 0, w do
for y = 0, h do
local dx, dy = x-cx, y-cy
if dx*dx + dy*dy <= r*r then
local h = math.deg(math.atan2(dy, dx))
local s = (dx*dx + dy*dy)^0.5/r
local v = 1
love.graphics.setColor (hsv_to_rgb (h, s, v))
love.graphics.points (x, y)
end
end
end
love.graphics.setCanvas()
end
function love.draw()
love.graphics.setColor (1,1,1)
love.graphics.draw (canvas)
end
M2000 Interpreter
Module Check {
\\ we use an internal object for Math functions (here for Atan2)
Declare Math Math
Const tau=2*Pi, Center=2
\\ change console size, and center it ( using ;) to current monitor
Window 12, 800*twipsX,600*twipsY;
\\ actual size maybe less (so can fit text exactly)
Double ' Double height characters
Report Center, "Color wheel"
Normal ' restore to normal
Atan2=Lambda Math (a, b) ->{
Method Math, "Atan2", a, b As ret
=ret
}
\\ brightness=1 for this program
hsb2rgb=Lambda (hue, sat) ->{
If sat == 0 Then {
= 255, 255, 255
} Else {
h=frac(hue+1)*6
f = frac(h)
p = Int((1-sat)*255 + 0.5)
q = Int((1-sat*f)*255 + 0.5)
t = Int((1-sat*(1-f))*255 + 0.5)
Select Case Int(h)
Case 1
= q, 255, p
Case 2
= p, 255, t
Case 3
= p, q, 255
Case 4
= t, p, 255
Case 5
= 255, p, q
Else Case
= 255, t, p
End Select
}
}
Let OffsetX=X.twips/2-128*TwipsX, OffsetY=Y.twips/2-128*TwipsY
\\ a pixel has a size of TwipsX x TwipsY
OffsetX=(OffsetX div TwipsX)*TwipsX
OffsetY=(OffsetY div TwipsY)*TwipsY
\\ We set hsb2rgb, OffsetX, OffsetY as closures to PrintPixel
\\ We send to stack the R G B values using Stack ! array
\\ hsb2rgb() return an array of values
\\ we pop these values using Number
PrintPixel = Lambda hsb2rgb, OffsetX, OffsetY (x,y, theta, sat) -> {
Stack ! hsb2rgb(theta,sat)
PSet Color(number, number, number), x*TwipsX+offsetX, y*TwipsY+offsetY
}
\\ set Atan2, tau as closures to HueCircle
\\ we can rotate/flip the wheel by changing signs in Atan2() and
\\ by changing order of arguments (dx,dy) or (dy,dx). 8 combinations
HueCircle= Lambda Atan2, tau (PrintPixel) -> {
Let c_width=256, c_height=256
Let cx=c_width/2, cy=c_height/2
Let radius=If(cx<=cy->cx, cy)
c_width--
c_height--
dy=-cy
For y=0 To c_height {
dy++ : dy2=dy*dy : dx=-cx
For x=0 To c_width {
dx++ : dist=Sqrt(dx^2+dy2)
If dist>radius Then continue
Call PrintPixel(x,y, Atan2(dx, -dy)/tau, dist/radius)
}
}
}
Call HueCircle(PrintPixel)
Scr$="" ' we use this string to load an image
Move 0,0
\\ scale.x, scale.y are twips height and width, of current layer
Copy scale.x, scale.y to Scr$
Clipboard Scr$ ' save window to clipboard
}
Check
- Output:
see this image
Mathematica/Wolfram Language
r = 100;
Image[Table[
If[x^2 + y^2 <= r^2,
angle = Mod[ArcTan[N@x, y]/(2 Pi), 1];
List @@ RGBColor[Hue[angle, Sqrt[x^2 + y^2]/N[r], 1.0]]
,
{1, 1, 1}
], {x, -r, r}, {y, -r, r}]
]
- Output:
Outputs an image.
Nim
As Rust code does, we store the color wheel in a PNG image.
import math
import imageman
#---------------------------------------------------------------------------------------------------
func hsvToRgb(h, s, v: float): ColorRGBU =
## Convert HSV values to RGB values.
let hp = h / 60
let c = s * v
let x = c * (1 - abs(hp mod 2 - 1))
let m = v - c
var r, g, b = 0.0
if hp <= 1:
r = c
g = x
elif hp <= 2:
r = x
g = c
elif hp <= 3:
g = c
b = x
elif hp <= 4:
g = x
b= c
elif hp <= 5:
r = x
b = c
else:
r = c
b = x
r += m
g += m
b += m
result = ColorRGBU [byte(r * 255), byte(g * 255), byte(b * 255)]
#---------------------------------------------------------------------------------------------------
func buildColorWheel(image: var Image) =
## Build a color wheel into the image.
const Margin = 10
let diameter = min(image.w, image.h) - 2 * Margin
let xOffset = (image.w - diameter) div 2
let yOffset = (image.h - diameter) div 2
let radius = diameter / 2
for x in 0..diameter:
let rx = x.toFloat - radius
for y in 0..diameter:
let ry = y.toFloat - radius
let r = hypot(rx, ry) / radius
if r > 1: continue
let a = 180 + arctan2(ry, -rx).radToDeg()
image[x + xOffset, y + yOffset] = hsvToRgb(a, r, 1)
#———————————————————————————————————————————————————————————————————————————————————————————————————
const
Side = 400
Output = "color_wheel.png"
var image = initImage[ColorRGBU](Side, Side)
image.buildColorWheel()
image.savePNG(Output, compression = 9)
Perl
use Imager;
use Math::Complex qw(cplx i pi);
my ($width, $height) = (300, 300);
my $center = cplx($width/2, $height/2);
my $img = Imager->new(xsize => $width,
ysize => $height);
foreach my $y (0 .. $height - 1) {
foreach my $x (0 .. $width - 1) {
my $vec = $center - $x - $y * i;
my $mag = 2 * abs($vec) / $width;
my $dir = (pi + atan2($vec->Re, $vec->Im)) / (2 * pi);
$img->setpixel(x => $x, y => $y,
color => {hsv => [360 * $dir, $mag, $mag < 1 ? 1 : 0]});
}
}
$img->write(file => 'color_wheel.png');
Phix
You can run this online here.
-- -- demo\rosetta\Colour_wheel.exw -- ============================= -- -- Note: Made non-resizeable since maximising this is far too slow. -- with javascript_semantics include pGUI.e constant title = "Colour wheel" Ihandle dlg, canvas cdCanvas cddbuffer, cdcanvas function redraw_cb(Ihandle /*ih*/, integer /*posx*/, /*posy*/) integer {w, h} = IupGetIntInt(canvas, "DRAWSIZE") cdCanvasActivate(cddbuffer) integer radius = floor(min(w,h)/2) integer cx = floor(w/2), cy = floor(h/2) for x=1 to w do for y=1 to h do integer rx = x - cx, ry = y - cy atom s = sqrt(rx*rx+ry*ry) / radius if s <= 1.0 then atom hue = ((atan2(ry, rx) / PI) + 1.0) / 2.0 cdCanvasPixel(cddbuffer, x, h-y, hsv_to_rgb(hue, s, 1)) end if end for end for cdCanvasFlush(cddbuffer) return IUP_DEFAULT end function function map_cb(Ihandle ih) cdcanvas = cdCreateCanvas(CD_IUP, ih) cddbuffer = cdCreateCanvas(CD_DBUFFER, cdcanvas) cdCanvasSetBackground(cddbuffer, CD_WHITE) cdCanvasSetForeground(cddbuffer, CD_MAGENTA) return IUP_DEFAULT end function procedure main() IupOpen() canvas = IupCanvas(NULL) IupSetAttribute(canvas, "RASTERSIZE", "300x300") IupSetCallback(canvas, "MAP_CB", Icallback("map_cb")) dlg = IupDialog(canvas,`TITLE="%s",RESIZE=NO`,{title}) IupSetCallback(canvas, "ACTION", Icallback("redraw_cb")) IupShowXY(dlg,IUP_CENTER,IUP_CENTER) if platform()!=JS then IupMainLoop() IupClose() end if end procedure main()
Processing
size(300, 300);
background(0);
float radius = min(width, height) / 2.0;
float cx = width / 2;
float cy = width / 2;
for (int x = 0; x < width; x++) {
for (int y = 0; y < width; y++) {
float rx = x - cx;
float ry = y - cy;
float s = sqrt(sq(rx) + sq(ry)) / radius;
if (s <= 1.0) {
float h = ((atan2(ry, rx) / PI) + 1.0) / 2.0;
colorMode(HSB);
color c = color(int(h * 255), int(s * 255), 255);
set(x, y, c);
}
}
}
Processing Python mode
size(300, 300)
background(0)
radius = min(width, height) / 2.0
cx, cy = width / 2, width / 2
for x in range(width):
for y in range(height):
rx = x - cx
ry = y - cy
s = sqrt(rx ** 2 + ry ** 2) / radius
if s <= 1.0:
h = ((atan2(ry, rx) / PI) + 1.0) / 2.0
colorMode(HSB)
c = color(int(h * 255), int(s * 255), 255)
set(x, y, c) # note set() used as Processing set() not as Python set()
Plain English
To draw the color wheel:
Start with the red color.
Turn right 80 points.
Loop.
If the user clicks on the screen, break.
Move to the center of the screen.
Draw a line 2 inches long.
Refresh the screen.
Change the current hue by 10 points.
Turn right 10 points.
Add 1 to a count.
If the count is 384, break. \ Plain English uses a circle divided into 384 degrees
Repeat.
Start in the middle of the screen facing north minus 80 points.
Use medium-sized letters.
Write "RED......YELLOW.....GREEN......CYAN......BLUE.....MAGENTA......" with the white pen 2-1/4 inches from the screen's center.
Refresh the screen.
Shut down.
Python
from PIL import Image
import colorsys
import math
if __name__ == "__main__":
im = Image.new("RGB", (300,300))
radius = min(im.size)/2.0
cx, cy = im.size[0]/2, im.size[1]/2
pix = im.load()
for x in range(im.width):
for y in range(im.height):
rx = x - cx
ry = y - cy
s = (rx ** 2.0 + ry ** 2.0) ** 0.5 / radius
if s <= 1.0:
h = ((math.atan2(ry, rx) / math.pi) + 1.0) / 2.0
rgb = colorsys.hsv_to_rgb(h, s, 1.0)
pix[x,y] = tuple([int(round(c*255.0)) for c in rgb])
im.show()
Racket
With the colors package
#lang racket
(require racket/draw
colors)
(define DIM 500)
(define target (make-bitmap DIM DIM))
(define dc (new bitmap-dc% [bitmap target]))
(define radius 200)
(define center (/ DIM 2))
(define (atan2 y x) (if (= 0 y x) 0 (atan y x)))
(for* ([x (in-range DIM)]
[y (in-range DIM)]
[rx (in-value (- x center))]
[ry (in-value (- y center))]
[s (in-value (/ (sqrt (+ (sqr rx) (sqr ry))) radius))]
#:when (<= s 1))
(define h (* 0.5 (+ 1 (/ (atan2 ry rx) pi))))
(send dc set-pen (hsv->color (hsv (if (= 1 h) 0 h) s 1)) 1 'solid)
(send dc draw-point x y))
target
Raku
(formerly Perl 6)
use Image::PNG::Portable;
my ($w, $h) = 300, 300;
my $out = Image::PNG::Portable.new: :width($w), :height($h);
my $center = $w/2 + $h/2*i;
color-wheel($out);
$out.write: 'Color-wheel-perl6.png';
sub color-wheel ( $png ) {
^$w .race.map: -> $x {
for ^$h -> $y {
my $vector = $center - $x - $y*i;
my $magnitude = $vector.abs * 2 / $w;
my $direction = ( π + atan2( |$vector.reals ) ) / τ;
$png.set: $x, $y, |hsv2rgb( $direction, $magnitude, $magnitude < 1 );
}
}
}
sub hsv2rgb ( $h, $s, $v ){
my $c = $v * $s;
my $x = $c * (1 - abs( (($h*6) % 2) - 1 ) );
my $m = $v - $c;
(do given $h {
when 0..^1/6 { $c, $x, 0 }
when 1/6..^1/3 { $x, $c, 0 }
when 1/3..^1/2 { 0, $c, $x }
when 1/2..^2/3 { 0, $x, $c }
when 2/3..^5/6 { $x, 0, $c }
when 5/6..1 { $c, 0, $x }
} ).map: ((*+$m) * 255).Int
}
Ring
#===================================================================#
# Sample: Color Wheel
# Author: Gal Zsolt, Bert Mariani, Ilir Liburn & Mahmoud Fayed
#===================================================================#
load "guilib.ring"
xWidth = 400
yHeight = 400
MyApp = new qapp
{
win1 = new qwidget()
{ setwindowtitle("ColorWheel-FastDraw")
setgeometry(500,150,xWidth,yHeight)
Canvas = new qlabel(win1)
{ ### daVinci paints the MonaLisa on the Canvas
MonaLisa = new qPixMap2( xWidth, yHeight)
color = new qcolor(){ setrgb(255,255,255,0) }
pen = new qpen() { setwidth(1) }
MonaLisa.fill(color)
daVinci = new qpainter()
{ begin(MonaLisa)
#endpaint() ### This will Stop the Painting. For Animation comment it out
}
setPixMap(MonaLisa)
}
show()
}
ColorWheel()
exec()
}
//=====================
Func colorWheel
#=====================================================================#
? "Start Processing..."
t1 = clock()
? "Clock : " + t1
#=====================================================================#
aList = []
pi = 3.14159265359
diameter = pi * 2
radius = yHeight / 2
v = 1 // value/brightness 1 to 100 1=bright 0=dark
for i = 1 to xWidth
iradius = i - radius
p = pow( iradius, 2)
for j = 1 to yHeight
h = (atan2( iradius, j-radius ) + pi ) / diameter // hue/color 1 to 360
s = sqrt( p + pow( j-radius, 2)) / radius // saturation/intensity 1 to 100
if s <= 1 and h <= 1
aList + [i,j,h,s,v,1]
ok
next
next
#=====================================================================#
? "Start drawing..."
t2 = clock()
? "Clock : " + t2
#=====================================================================#
daVinci.drawHSVFList(aList)
Canvas.setPixMap(MonaLisa)
#=====================================================================#
? "Done..."
t3 = clock()
? "Clock : " + t3
#=====================================================================#
? "Processing Time: " + ( (t2-t1)/ClocksPerSecond() ) + " seconds "
? "Drawing Time: " + ( (t3-t2)/ClocksPerSecond() ) + " seconds "
? "Total Time: " + ( (t3-t1)/ClocksPerSecond() ) + " seconds "
#=====================================================================#
return
//==================
Ruby
def settings
size(300, 300)
end
def setup
sketch_title 'Color Wheel'
background(0)
radius = width / 2.0
center = width / 2
grid(width, height) do |x, y|
rx = x - center
ry = y - center
sat = Math.hypot(rx, ry) / radius
if sat <= 1.0
hue = ((Math.atan2(ry, rx) / PI) + 1) / 2.0
color_mode(HSB)
col = color((hue * 255).to_i, (sat * 255).to_i, 255)
set(x, y, col)
end
end
end
Run BASIC
' -----------------------------------
' color wheel
' -----------------------------------
global pi
pi = 22 / 7
steps = 1
graphic #g, 525, 525
for x =0 to 525 step steps
for y =0 to 525 step steps
angle = atan2(y - 250, x - 250) * 360 / 2 / pi ' full degrees....
sector = int(angle / 60) ' 60 degree sectors (0 to 5)
slope = (angle mod 60) /60 * 255 ' 1 degree sectors.
if sector = 0 then col$ = "255 "; str$( int( slope)); " 0"
if sector = 1 then col$ = str$(int(256 - slope)); " 255 0"
if sector = 2 then col$ = "0 255 "; str$( int( slope))
if sector = 3 then col$ = "0 "; str$( int( 256 -slope)); " 255"
if sector = 4 then col$ = str$(int(slope)); " 0 255"
if sector = 5 then col$ = "255 0 "; str$( int( 256 -slope))
red = val( word$( col$, 1))
grn = val( word$( col$, 2))
blu = val( word$( col$, 3))
p = ((x -270)^2 +(y -270)^2)^0.5 / 250
r = min(255,p * red)
g = min(255,p * grn)
b = min(255,p * blu)
if p > 1 then #g "color white" else #g color(r,g,b)
#g "set "; x; " "; y
next y
next x
render #g
end
function atan2(y,x)
if (x = 0) and (y <> 0) then
r$ = "Y"
if y > 0 then atan2 = pi /2
if y < 0 then atan2 = 3 * pi /2
end if
if y = 0 and (x <> 0) then
r$ = "Y"
if x > 0 then atan2 = 0
if x < 0 then atan2 = pi
end if
If r$ <> "Y" then
if x = 0 and y = 0 then
atan2 = 0
else
baseAngle = atn(abs(y) / abs(x))
if x > 0 then
if y > 0 then atan2 = baseAngle
If y < 0 then atan2 = 2 * pi - baseAngle
end if
if x < 0 then
If y > 0 then atan2 = pi - baseAngle
If y < 0 then atan2 = pi + baseAngle
end if
end if
end if
end function
Rust
Output is a file in PNG format.
// [dependencies]
// image = "0.23"
use image::error::ImageResult;
use image::{Rgb, RgbImage};
fn hsv_to_rgb(h: f64, s: f64, v: f64) -> Rgb<u8> {
let hp = h / 60.0;
let c = s * v;
let x = c * (1.0 - (hp % 2.0 - 1.0).abs());
let m = v - c;
let mut r = 0.0;
let mut g = 0.0;
let mut b = 0.0;
if hp <= 1.0 {
r = c;
g = x;
} else if hp <= 2.0 {
r = x;
g = c;
} else if hp <= 3.0 {
g = c;
b = x;
} else if hp <= 4.0 {
g = x;
b = c;
} else if hp <= 5.0 {
r = x;
b = c;
} else {
r = c;
b = x;
}
r += m;
g += m;
b += m;
Rgb([(r * 255.0) as u8, (g * 255.0) as u8, (b * 255.0) as u8])
}
fn write_color_wheel(filename: &str, width: u32, height: u32) -> ImageResult<()> {
let mut image = RgbImage::new(width, height);
let margin = 10;
let diameter = std::cmp::min(width, height) - 2 * margin;
let xoffset = (width - diameter) / 2;
let yoffset = (height - diameter) / 2;
let radius = diameter as f64 / 2.0;
for x in 0..=diameter {
let rx = x as f64 - radius;
for y in 0..=diameter {
let ry = y as f64 - radius;
let r = ry.hypot(rx) / radius;
if r > 1.0 {
continue;
}
let a = 180.0 + ry.atan2(-rx).to_degrees();
image.put_pixel(x + xoffset, y + yoffset, hsv_to_rgb(a, r, 1.0));
}
}
image.save(filename)
}
fn main() {
match write_color_wheel("color_wheel.png", 400, 400) {
Ok(()) => {}
Err(error) => eprintln!("{}", error),
}
}
- Output:
Sidef
require('Imager')
var (width, height) = (300, 300)
var center = Complex(width/2 , height/2)
var img = %O<Imager>.new(xsize => width, ysize => height)
for y=(^height), x=(^width) {
var vector = (center - x - y.i)
var magnitude = (vector.abs * 2 / width)
var direction = ((Num.pi + atan2(vector.real, vector.imag)) / Num.tau)
img.setpixel(x => x, y => y,
color => Hash(hsv => [360*direction, magnitude, magnitude < 1 ? 1 : 0])
)
}
img.write(file => 'color_wheel.png')
Output image: Color wheel
Smart BASIC
' Runs on iOS
GET SCREEN SIZE sw,sh
xmax=0.45*3/7*(sw+sh)
x0=sw/2!y0=sh/2
twopi=2*3.1415926
GRAPHICS
GRAPHICS CLEAR
DIM triX(1000), triY(1000)
triX(0)=x0 ! triY(0)=y0
steps=INT(1^2*360)+1
dAngle=twopi/steps
dAngle2=dAngle/2
REFRESH OFF
FOR i=0 TO steps-1
pal(i/steps+TintOffset)
ANGLE=i*dAngle
FILL COLOR pal.r,pal.g,pal.b
DRAW COLOR pal.r,pal.g,pal.b
x=x0+(xmax-radius)*COS(ANGLE)
y=y0-(xmax-radius)*SIN(ANGLE)
k=0
FOR j=-dAngle2 TO dAngle2 STEP 0.02
k+=1
triX(k)=x0+xmax*COS(ANGLE+j)
triY(k)=y0-xmax*SIN(ANGLE+j)
NEXT j
k+=1
triX(k)=x0+xmax*COS(ANGLE+dAngle2)
triY(k)=y0-xmax*SIN(ANGLE+dAngle2)
DRAW POLY triX,triY COUNT k+1
FILL POLY triX,triY COUNT k+1
NEXT i
REFRESH ON
END
DEF pal(tint)
tint=tint*360
h=(tint%360)/60 ! f=FRACT(h) ! z=1-f ! ic=FLOOR(h)+1
ON ic GOTO s1,s2,s3,s4,s5,s6
s1: r=1 ! g=f ! b=0 ! GOTO done
s2: r=z ! g=1 ! b=0 ! GOTO done
s3: r=0 ! g=1 ! b=f ! GOTO done
s4: r=0 ! g=z ! b=1 ! GOTO done
s5: r=f ! g=0 ! b=1 ! GOTO done
s6: r=1 ! g=0 ! b=z ! done:
END DEF
View the output on Dropbox https://www.dropbox.com/s/g3l5rbywo34bnp6/IMG_4600.PNG?dl=0 This file is no longer there!!! 10 Sep 2021
Vala
public class Example: Gtk.Application {
private Gtk.ApplicationWindow window;
private Gtk.DrawingArea drawing_area;
public Example() {
Object(application_id: "my.application", flags: ApplicationFlags.FLAGS_NONE);
this.activate.connect(() => {
window = new Gtk.ApplicationWindow(this);
drawing_area = new Gtk.DrawingArea();
drawing_area.set_draw_func(draw_circle);
window.set_child(drawing_area);
window.present();
});
}
private void draw_circle(Gtk.DrawingArea area, Cairo.Context cr, int width, int height) {
int centerx = width / 2;
int centery = height / 2;
double anglestep = 1.0 / width;
for (float theta = (float) 0.0; theta < 360; theta += (float) 0.1) {
float r;
float g;
float b;
Gtk.hsv_to_rgb(theta / (float) 360.0, 1, 1, out r, out g, out b);
cr.set_source_rgb(r, g, b);
cr.line_to(centerx, centery);
cr.arc(centerx, centery, ((double) width) / 2.2, GLib.Math.PI * 2 * theta / 360.0, anglestep);
cr.line_to(centerx, centery);
cr.stroke();
}
}
public static int main(string[] argv) {
var app = new Example();
return app.run(argv);
}
}
VBScript
Building a BMP file and opening it with the default viewer. It takes 5 seconds in my 5 years old notebook. Run with Cscript if you don want to be clicking at annoying message boxes.
Option explicit
Class ImgClass
Private ImgL,ImgH,ImgDepth,bkclr,loc,tt
private xmini,xmaxi,ymini,ymaxi,dirx,diry
public ImgArray() 'rgb in 24 bit mode, indexes to palette in 8 bits
private filename
private Palette,szpal
public property get xmin():xmin=xmini:end property
public property get ymin():ymin=ymini:end property
public property get xmax():xmax=xmaxi:end property
public property get ymax():ymax=ymaxi:end property
public property let depth(x)
if x<>8 and x<>32 then err.raise 9
Imgdepth=x
end property
public sub set0 (x0,y0) 'sets the new origin (default tlc). The origin does'nt work if ImgArray is accessed directly
if x0<0 or x0>=imgl or y0<0 or y0>imgh then err.raise 9
xmini=-x0
ymini=-y0
xmaxi=xmini+imgl-1
ymaxi=ymini+imgh-1
end sub
'constructor
Public Default Function Init(name,w,h,orient,dep,bkg,mipal)
'offx, offy posicion de 0,0. si ofx+ , x se incrementa de izq a der, si offy+ y se incrementa de abajo arriba
dim i,j
ImgL=w
ImgH=h
tt=timer
loc=getlocale
' not useful as we are not using SetPixel and accessing ImgArray directly
set0 0,0 'origin blc positive up and right
redim imgArray(ImgL-1,ImgH-1)
bkclr=bkg
if bkg<>0 then
for i=0 to ImgL-1
for j=0 to ImgH-1
imgarray(i,j)=bkg
next
next
end if
Select Case orient
Case 1: dirx=1 : diry=1
Case 2: dirx=-1 : diry=1
Case 3: dirx=-1 : diry=-1
Case 4: dirx=1 : diry=-1
End select
filename=name
ImgDepth =dep
'load user palette if provided
if imgdepth=8 then
loadpal(mipal)
end if
set init=me
end function
private sub loadpal(mipale)
if isarray(mipale) Then
palette=mipale
szpal=UBound(mipale)+1
Else
szpal=256
'Default palette recycled from ATARI
'removed
, not relevant
End if
End Sub
'class termination writes it to a BMP file and displays it
'if an error happens VBS terminates the class before exiting so the BMP is displayed the same
Private Sub Class_Terminate
if err<>0 then wscript.echo "Error " & err.number
wscript.echo "copying image to bmp file"
savebmp
wscript.echo "opening " & filename & " with your default bmp viewer"
CreateObject("Shell.Application").ShellExecute filename
wscript.echo timer-tt & " iseconds"
End Sub
function long2wstr( x) 'falta muy poco!!!
dim k1,k2,x1
k1= (x and &hffff&)' or (&H8000& And ((X And &h8000&)<>0)))
k2=((X And &h7fffffff&) \ &h10000&) Or (&H8000& And (x<0))
long2wstr=chrw(k1) & chrw(k2)
end function
function int2wstr(x)
int2wstr=ChrW((x and &h7fff) or (&H8000 And (X<0)))
End Function
Public Sub SaveBMP
'Save the picture to a bmp file
Dim s,ostream, x,y,loc
const hdrs=54 '14+40
dim bms:bms=ImgH* 4*(((ImgL*imgdepth\8)+3)\4) 'bitmap size including padding
dim palsize:if (imgdepth=8) then palsize=szpal*4 else palsize=0
with CreateObject("ADODB.Stream") 'auxiliary ostream, it creates an UNICODE with bom stream in memory
.Charset = "UTF-16LE" 'o "UTF16-BE"
.Type = 2' adTypeText
.open
'build a header
'bmp header: VBSCript does'nt have records nor writes binary values to files, so we use strings of unicode chars!!
'BMP header
.writetext ChrW(&h4d42) ' 0 "BM" 4d42
.writetext long2wstr(hdrs+palsize+bms) ' 2 fiesize
.writetext long2wstr(0) ' 6 reserved
.writetext long2wstr (hdrs+palsize) '10 image offset
'InfoHeader
.writetext long2wstr(40) '14 infoheader size
.writetext long2wstr(Imgl) '18 image length
.writetext long2wstr(imgh) '22 image width
.writetext int2wstr(1) '26 planes
.writetext int2wstr(imgdepth) '28 clr depth (bpp)
.writetext long2wstr(&H0) '30 compression used 0= NOCOMPR
.writetext long2wstr(bms) '34 imgsize
.writetext long2wstr(&Hc4e) '38 bpp hor
.writetext long2wstr(&hc43) '42 bpp vert
.writetext long2wstr(szpal) '46 colors in palette
.writetext long2wstr(&H0) '50 important clrs 0=all
'write bitmap
'precalc data for orientation
Dim x1,x2,y1,y2
If dirx=-1 Then x1=ImgL-1 :x2=0 Else x1=0:x2=ImgL-1
If diry=-1 Then y1=ImgH-1 :y2=0 Else y1=0:y2=ImgH-1
Select Case imgdepth
Case 32
For y=y1 To y2 step diry
For x=x1 To x2 Step dirx
'writelong fic, Pixel(x,y)
.writetext long2wstr(Imgarray(x,y))
Next
Next
Case 8
'palette
For x=0 to szpal-1
.writetext long2wstr(palette(x)) '52
Next
'image
dim pad:pad=ImgL mod 4
For y=y1 to y2 step diry
For x=x1 To x2 step dirx*2
.writetext chrw((ImgArray(x,y) and 255)+ &h100& *(ImgArray(x+dirx,y) and 255))
Next
'line padding
if pad and 1 then .writetext chrw(ImgArray(x2,y))
if pad >1 then .writetext chrw(0)
Next
Case Else
WScript.Echo "ColorDepth not supported : " & ImgDepth & " bits"
End Select
'use a second stream to save to file starting past the BOM the first ADODB.Stream has added
Dim outf:Set outf= CreateObject("ADODB.Stream")
outf.Type = 1 ' adTypeBinary
outf.Open
.position=2 'remove bom (1 wchar)
.CopyTo outf
.close
outf.savetofile filename,2 'adSaveCreateOverWrite
outf.close
end with
End Sub
end class
function hsv2rgb( Hue, Sat, Value) 'hue 0-360 0-ro 120-ver 240-az ,sat 0-100,value 0-100
dim Angle, Radius,Ur,Vr,Wr,Rdim
dim r,g,b, rgb
Angle = (Hue-150) *0.01745329251994329576923690768489
Ur = Value * 2.55
Radius = Ur * tan(Sat *0.01183199)
Vr = Radius * cos(Angle) *0.70710678 'sqrt(1/2)
Wr = Radius * sin(Angle) *0.40824829 'sqrt(1/6)
r = (Ur - Vr - Wr)
g = (Ur + Vr - Wr)
b = (Ur + Wr + Wr)
'clamp values
if r >255 then
Rdim = (Ur - 255) / (Vr + Wr)
r = 255
g = Ur + (Vr - Wr) * Rdim
b = Ur + 2 * Wr * Rdim
elseif r < 0 then
Rdim = Ur / (Vr + Wr)
r = 0
g = Ur + (Vr - Wr) * Rdim
b = Ur + 2 * Wr * Rdim
end if
if g >255 then
Rdim = (255 - Ur) / (Vr - Wr)
r = Ur - (Vr + Wr) * Rdim
g = 255
b = Ur + 2 * Wr * Rdim
elseif g<0 then
Rdim = -Ur / (Vr - Wr)
r = Ur - (Vr + Wr) * Rdim
g = 0
b = Ur + 2 * Wr * Rdim
end if
if b>255 then
Rdim = (255 - Ur) / (Wr + Wr)
r = Ur - (Vr + Wr) * Rdim
g = Ur + (Vr - Wr) * Rdim
b = 255
elseif b<0 then
Rdim = -Ur / (Wr + Wr)
r = Ur - (Vr + Wr) * Rdim
g = Ur + (Vr - Wr) * Rdim
b = 0
end If
'b lowest byte, red highest byte
hsv2rgb= ((b and &hff)+256*((g and &hff)+256*(r and &hff))and &hffffff)
end function
function ang(col,row)
'if col =0 then if row>0 then ang=0 else ang=180:exit function
if col =0 then
if row<0 then ang=90 else ang=270 end if
else
if col>0 then
ang=atn(-row/col)*57.2957795130
else
ang=(atn(row/-col)*57.2957795130)+180
end if
end if
ang=(ang+360) mod 360
end function
Dim X,row,col,fn,tt,hr,sat,row2
const h=160
const w=160
const rad=159
const r2=25500
tt=timer
fn=CreateObject("Scripting.FileSystemObject").GetSpecialFolder(2)& "\testwchr.bmp"
Set X = (New ImgClass)(fn,w*2,h*2,1,32,0,0)
x.set0 w,h
'wscript.echo x.xmax, x.xmin
for row=x.xmin+1 to x.xmax
row2=row*row
hr=int(Sqr(r2-row2))
For col=hr To 159
Dim a:a=((col\16 +row\16) And 1)* &hffffff
x.imgArray(col+160,row+160)=a
x.imgArray(-col+160,row+160)=a
next
for col=-hr to hr
sat=100-sqr(row2+col*col)/rad *50
' wscript.echo c,r
x.imgArray(col+160,row+160)=hsv2rgb(ang(row,col)+90,100,sat)
next
'script.echo row
next
Set X = Nothing
==
- Output:
==
Wren
import "graphics" for Canvas, Color
import "dome" for Window
import "random" for Random
class Game {
static init() {
Window.title = "Color Wheel"
__width = 640
__height = 640
Window.resize(__width, __height)
Canvas.resize(__width, __height)
colorWheel()
}
static colorWheel() {
var cx = (__width/2).floor
var cy = (__height/2).floor
var r = (cx < cy) ? cx : cy
for (y in 0...__height) {
var dy = y - cy
for (x in 0...__width) {
var dx = x - cx
var dist = (dx*dx + dy*dy).sqrt
if (dist <= r) {
var theta = dy.atan(dx)
var h = (theta + Num.pi) / Num.pi * 180
var col = Color.hsv(h, dist/r, 1)
Canvas.pset(x, y, col)
}
}
}
}
static update() {}
static draw(alpha) {}
}
XPL0
Algorithm is from "Computer Graphics ..." by Foley et al. The output is the same as Zkl.
def Radius = 480/2;
real Hue, Sat, Dist, I, F, P, Q, T;
real XX, YY, RR, GG, BB;
int X, Y, R, G, B;
def Pi = 3.141592654;
def V = 1.; \Value
[SetVid($112); \640x480x24 graphics
for Y:= -Radius to Radius do
for X:= -Radius to Radius do
[XX:= float(X);
YY:= float(Y);
Dist:= sqrt(XX*XX + YY*YY);
if Dist <= float(Radius) then
[Sat:= Dist/float(Radius); \0 >= Sat <= 1
Hue:= ATan2(YY, XX); \-Pi >= Hue <= Pi
if Hue < 0. then Hue:= Hue + 2.*Pi;
Hue:= Hue * 180./Pi; \radians to degrees
Hue:= Hue / 60.; \0 >= Hue < 6
I:= Floor(Hue); \integer part of Hue
F:= Hue - I; \fractional part of Hue
P:= 1. - Sat;
Q:= 1. - Sat*F;
T:= 1. - Sat*(1.-F);
case fix(I) of
0: [RR:= V; GG:= T; BB:= P];
1: [RR:= Q; GG:= V; BB:= P];
2: [RR:= P; GG:= V; BB:= T];
3: [RR:= P; GG:= Q; BB:= V];
4: [RR:= T; GG:= P; BB:= V];
5: [RR:= V; GG:= P; BB:= Q]
other [exit 1];
R:= fix(RR*255.);
G:= fix(GG*255.);
B:= fix(BB*255.);
Point(X+Radius, Radius-Y, R<<16+G<<8+B);
];
];
]
zkl
Uses Image Magick and the PPM class from http://rosettacode.org/wiki/Bitmap/Bresenham%27s_line_algorithm#zkl
var w=300,h=300,out=PPM(w,h);
colorWheel(out);
out.writeJPGFile("colorWheel.zkl.jpg");
fcn colorWheel(ppm){
zero,R:=ppm.w/2, zero;
foreach x,y in (w,h){
v,hue:=(x - zero).toFloat().toPolar(y - zero);
if(v<=R){ // only render in the circle
if((hue = hue.toDeg())<0) hue+=360; // (-pi..pi] to [0..2pi)
s:=v/R; // scale saturation zero at center to 1 at edge
ppm[x,y]=hsv2rgb(hue,1.0,s);
}
}
}
fcn hsv2rgb(hue,v,s){ // 0<=H<360, 0<=v(brightness)<=1, 0<=saturation<=1
// --> 24 bit RGB each R,G,B in [0..255]
to24bit:=fcn(r,g,b,m){
r,g,b=((r+m)*255).toInt(),((g+m)*255).toInt(),((b+m)*255).toInt();
r*0x10000 + g*0x100 + b
};
c:=v*s;
x:=c*(1.0 - (hue.toFloat()/60%2 - 1).abs());
m:=v - c;
if (0 <=hue< 60) return(to24bit(c, x, 0.0,m));
else if(60 <=hue<120) return(to24bit(x, c, 0.0,m));
else if(120<=hue<180) return(to24bit(0.0,c, x, m));
else if(180<=hue<240) return(to24bit(0.0,x, c, m));
else if(240<=hue<300) return(to24bit(x, 0.0,c, m));
else return(to24bit(c, 0.0,x, m));
}
- Output:
See this image
- Programming Tasks
- Basic language learning
- Applesoft BASIC
- AppleScript
- C++
- Qt
- C sharp
- Delphi
- Winapi.Windows
- System.SysUtils
- Vcl.Graphics
- System.Math
- Vcl.Imaging.pngimage
- EasyLang
- Fōrmulæ
- FreeBASIC
- FutureBasic
- GML
- Go
- Go Graphics
- J
- Java
- Julia
- Kotlin
- Lua
- LÖVE
- M2000 Interpreter
- Mathematica
- Wolfram Language
- Nim
- Imageman
- Perl
- Phix
- Phix/pGUI
- Phix/online
- Processing
- Processing Python mode
- Plain English
- Python
- Racket
- Raku
- Pages with broken file links
- Ring
- Ruby
- RubyGems
- JRubyArt
- Run BASIC
- Rust
- Sidef
- Smart BASIC
- Vala
- VBScript
- Wren
- DOME
- XPL0
- Zkl