I didn't forget, it just took longer than I would have liked.
Images can now be colorized with one to four tones when using the direct method.
The threshold spin gadgets can be used to adjust the transition points between tones.
Example, when using duo tones the default transition is set for a value of 128.
color tone two will be used.
Colors can be selected using the available controls or by clicking directly on the source
image. The color under the cursor will be captured.
It often works best to use a color of high luminosity. For convenience a color can be
automatically adjusted to maximum luminosity by right clicking on the gradient or
palette display. When the color is to your liking click on one of the set buttons C1-C4.
There are preset colors available that often work well with the direct method.
When using the palette method better results are often obtained by manually choosing
dominant colors from the source image.
Here are a couple of examples that give an idea of what can be done.
The palette method is actually a way to quantize the colors of the image and not a 'colorize' toning process.
It works very well if you choose the colors carefully, I chose only four colors from the source image and used
the 'quad' setting to yield a palette of only 16 colors even though the resulting image appears to have many more
than 16 colors.
[edit] 2/18/2016, Fixed load preset colors problem for Linux users.
[edit] 3/2/2016, added new features 'blend method' based on Wilbert's code above.
now images can be colorized using duotone, tritone, and quadtone methods.
[edit] 9/19/2016, Previous threshold settings are now retained in the direct method after switching back
Code: Select all
; ColorizeImage.pb
; apply specific color(s) to image by BasicallyPure
; 9.19,2016
; License : Free
; Compiler: PureBasic 5.50 LTS
; OS: cross platform
EnableExplicit
UsePNGImageDecoder() : UsePNGImageEncoder()
UseJPEGImageDecoder() : UseJPEGImageEncoder()
UseJPEG2000ImageDecoder() : UseJPEG2000ImageEncoder()
Structure PresetType
na.s ; preset name
C1.i ; tone 1 value
C2.i
C3.i
C4.i
EndStructure
;{ procedure declarations
Declare ASSEMBLE_TO_PALETTE(image, Array Pallete.l(1))
Declare CAPTURE_COLOR_POINT()
Declare CATCH_PALETTE(*MemoryAddress.Long, NumColors.i)
Declare COLORIZE_CANVAS_CALLBACK()
Declare COLORIZE_IMAGE(image.i)
Declare COLORIZE_QUADTONE(Image.i)
Declare COPY()
Declare CREATE_PALETTE(size.i)
Declare DRAW_PALETTE(style.i)
Declare DRAW_GRAD(image.i, shift.i)
Declare EVENT_LOOP()
Declare.l FIND_NEAREST(Color.l)
Declare FIT_CANVAS_TO_WINDOW()
Declare FIT_WINDOW_TO_IMAGE(image.i)
Declare HANDLE_WIN_COLORIZE_EVENTS(event.i)
Declare HANDLE_WIN_MAIN_EVENTS(event.i)
Declare LOAD_IMAGE()
Declare LOAD_PRESET()
Declare OPEN_COLORIZE_WINDOW()
Declare OPEN_MAIN_WINDOW()
Declare PASTE()
Declare.l PointOrdDith(x.i, y.i)
Declare REDRAW_CUSTOM_TRACKBAR(canvas.i)
Declare REVERT()
Declare SAVE_IMAGE()
Declare SPIN_ADJUST(gadget)
Declare T_COLOR_UPDATE()
Declare UPDATE_CANVAS(image.i)
Declare UPDATE_METHOD(gadget.i)
Declare UPDATE_TONEOPTION(gadget.i) : ;}
CompilerIf #PB_Compiler_Processor = #PB_Processor_x86
Macro rdx : edx : EndMacro
#x64 = #False
CompilerElse
#x64 = #True
CompilerEndIf
#WinMain = 0
#WinColorize = 1
#WinPreset = 2
#MainMenu = 0
#PopMenu = 1
#CBcolor = $404040 ;canvas background color
;{ enumerations
Enumeration ;images
#imgRef : #imgRevert : #imgAdj
#img_Adj_R : #img_Adj_G : #img_Adj_B : #img_C1 : #img_C2
#img_C3 : #img_C4 : #img_Hue : #img_Tone
EndEnumeration
Enumeration
#Canvas ; for main window
; gadgets for colorize window
#btn_C1_set : #btn_C2_set : #btn_C3_set : #btn_C4_set : #btn_preview : #btn_apply : #btn_close : #Btn_source
#Fra_Hue : #Fra_Grad : #Fra_C1 : #Fra_C2 : #Fra_Method : #Fra_C3 : #Fra_C4 : #Fra_palSize : #Fra_Modify
#opt_tri : #opt_mono : #opt_duo : #opt_quad : #opt_direct : #opt_palette : #opt_blend
#imgGad_C1 : #imgGad_C2 : #imgGad_C3 : #imgGad_C4 : #ImgGad_Tone
#spin_thresh_1 : #spin_thresh_2 : #spin_thresh_3
#Can_Hue : #Can_Adj_R : #Can_Adj_G : #Can_Adj_B
#Combo_presets : #chk_dither : #trk_palSize
EndEnumeration
Enumeration ;menu items
#MenuItem_Load : #MenuItem_Exit : #MenuItem_Colorize : #MenuItem_Copy
#MenuItem_Paste : #MenuItem_Save : #MenuItem_Revert : #MenuItem_Enter
EndEnumeration : ;}
;{ global variables
Global NewMap PresetMap.i()
Global NewList presetList.PresetType()
AddElement(presetList())
Restore PresetData
Read.s presetList()\na
While presetList()\na <> "End_Data"
Read.i presetList()\C1
Read.i presetList()\C2
Read.i presetList()\C3
Read.i presetList()\C4
AddElement(presetList())
Read.s presetList()\na
Wend
DeleteElement(presetList())
Global Dim Hue_Palette.l(0)
Global Dim IndexG.l(255)
Global Dim Palette.l(1)
Global Dim hue.i(1535)
Global Dim tone(3)
Global CurrentFileName$, File$
Global Title$ = "Colorize image "
Global endProgram = #False
Global DW,DH,LinuxAdj
Global CanvasMaxWidth, CanvasMaxHeight
Global CanvasMinWidth, CanvasMinHeight
Global WinBorder_X, WinBorder_Y
Global Pan_X, Pan_Y, oversize
Global ColorizeWinActive
Global HueSet.i = 264
Global paletteSize = 6
Global toneOption = #opt_quad
Global SM1 = 160, SM2 = 96, SM3 = 64
Global pMlt = 4 ;quad
Global method = #opt_blend
Global Tcolor = $FFFF00
Global preset = 4
Global DragPrivateImage
Global dither = #False : ;}
Macro MakeHueGradient(m, n)
;used in OPEN_COLORIZE_WINDOW() procedure
While m < $100
Hue(x) = RGB(R,G,B)
LineXY(x,0,x,20,Hue(x))
x + 1
m + 1
Wend
m - 1
While n > -1
Hue(x) = RGB(R,G,B)
LineXY(x,0,x,20,Hue(x))
x + 1
n - 1
Wend
n + 1
EndMacro
If OPEN_MAIN_WINDOW()
EVENT_LOOP()
EndIf
End
Procedure ASSEMBLE_TO_PALETTE(image.i, Array palette.l(1))
;examine each pixel of an image and assign the nearest color
;from the given palette.
Protected.i h, w, x, y, dither = GetGadgetState(#Chk_Dither)
CATCH_PALETTE(@palette(), ArraySize(palette())+1)
If StartDrawing(ImageOutput(Image))
h = OutputHeight()
w = OutputWidth()
If dither
While y < h
x = 0
While x < w
Plot(x, y, FIND_NEAREST(PointOrdDith(x, y)))
x + 1
Wend
y + 1
Wend
Else
While y < h
x = 0
While x < w
Plot(x, y, FIND_NEAREST(Point(x, y)))
x + 1
Wend
y + 1
Wend
EndIf
StopDrawing()
EndIf
EndProcedure
Procedure CANVAS_CALLBACK()
;respond to events from the main window canvas gadget
Static drag, Xorg, Yorg, iw, ih, ow, oh, Llim, Rlim, Tlim, Blim
Protected mx, my, x, y
Select EventType()
Case #PB_EventType_RightButtonUp : PostEvent(#PB_Event_RightClick)
; triggers a '#PB_Event_RightClick' for pop-up menu activation
; just like right clicking on the main window.
Case #PB_EventType_LeftButtonDown
If oversize : drag = #True
Xorg = GetGadgetAttribute(#Canvas,#PB_Canvas_MouseX)
Yorg = GetGadgetAttribute(#Canvas,#PB_Canvas_MouseY)
ow = GadgetWidth(#Canvas) : iw = ImageWidth(#imgRef)
oh = GadgetHeight(#Canvas) : ih = ImageHeight(#imgRef)
Llim = ow-iw : If Llim > 0 : Llim = 0 : EndIf
Rlim = ow-iw : If Rlim < 0 : Rlim = 0 : EndIf
Tlim = oh-ih : If Tlim > 0 : Tlim = 0 : EndIf
Blim = oh-ih : If Blim < 0 : Blim = 0 : EndIf
EndIf
Case #PB_EventType_MouseMove
If drag
mx = GetGadgetAttribute(#Canvas,#PB_Canvas_MouseX)
my = GetGadgetAttribute(#Canvas,#PB_Canvas_MouseY)
If iw > ow : Pan_X + (mx - Xorg) : Xorg = mx : EndIf
If ih > oh : Pan_Y + (my - Yorg) : Yorg = my : EndIf
; pan canvas image
StartDrawing(CanvasOutput(#Canvas))
Box(0,0,ow,oh,#CBcolor)
x = Pan_X + (ow - iw) / 2
y = Pan_Y + (oh - Ih) / 2
If x < Llim : Pan_X + (Llim - x) : x = Llim : EndIf
If x > Rlim : Pan_X - (x - Rlim) : x = Rlim : EndIf
If y < Tlim : Pan_Y + (Tlim - y) : y = Tlim : EndIf
If y > Blim : Pan_Y - (y - Blim) : y = Blim : EndIf
DrawImage(ImageID(#imgRef),x,y)
StopDrawing()
EndIf
Case #PB_EventType_LeftButtonUp
drag = #False
If ColorizeWinActive
CAPTURE_COLOR_POINT()
EndIf
EndSelect
EndProcedure
Procedure CATCH_PALETTE(*MemoryAddress.Long, NumColors.i)
; Catch a palette from memory
Protected.i i, j = 1
ReDim Palette(NumColors + 1)
Palette(0) = 0 : Palette(NumColors + 1) = 0
For i = 1 To NumColors
Palette(i) = $ff000000 | *MemoryAddress\l
*MemoryAddress + 4
Next
SortStructuredArray(Palette(), 0, 0, #PB_Unicode, 1, NumColors)
For i = 0 To 255
IndexG(i) = j
While ((Palette(j) >> 8) & $ff) = i And j < NumColors
j + 1
Wend
IndexG(i) = (IndexG(i) + j) >> 1
Next
EndProcedure
Procedure CAPTURE_COLOR_POINT()
Protected mx, my
StartDrawing(CanvasOutput(#Canvas))
mx = GetGadgetAttribute(#Canvas,#PB_Canvas_MouseX)
my = GetGadgetAttribute(#Canvas,#PB_Canvas_MouseY)
Tcolor = Point(mx,my)
StopDrawing()
SetGadgetData(#Can_Adj_R,Red(Tcolor)) : REDRAW_CUSTOM_TRACKBAR(#Can_Adj_R)
SetGadgetData(#Can_Adj_G,Green(Tcolor)) : REDRAW_CUSTOM_TRACKBAR(#Can_Adj_G)
SetGadgetData(#Can_Adj_B,Blue(Tcolor)) : REDRAW_CUSTOM_TRACKBAR(#Can_Adj_B)
DRAW_PALETTE(#opt_direct)
SetGadgetText(#Fra_Modify,"Modify | " + RSet(Hex(Tcolor),6,"0"))
EndProcedure
Procedure COLORIZE_CANVAS_CALLBACK()
;respond to events from any of the canvas gadgets
;on the colorize control window. These are the
;custom trackbar gadgets.
Static c, cxor, drag, mx, my, img, gadget, scale.d
gadget = EventGadget()
Select gadget
Case #Can_Hue : img = #img_Hue : cxor = $FFFFFF : scale = 1535 / 529
Case #Can_Adj_R : img = #img_Adj_R : cxor = $00FFFF : scale = 1
Case #Can_Adj_G : img = #img_Adj_G : cxor = $FF00FF : scale = 1
Case #Can_Adj_B : img = #img_Adj_B : cxor = $00FFFF : scale = 1
Default : ProcedureReturn
EndSelect
Select EventType()
Case #PB_EventType_LeftButtonDown : drag = #True
mx = GetGadgetAttribute(gadget,#PB_Canvas_MouseX)
StartDrawing(CanvasOutput(gadget))
DrawImage(ImageID(img),0,0)
DrawingMode(#PB_2DDrawing_XOr)
Box(mx-1,0,3,20,cxor)
StopDrawing()
Select gadget
Case #Can_Hue : SetGadgetData(gadget, hue(Int(mx * scale)))
SetGadgetText(#Fra_Hue,"HUE | " + RSet(Hex(hue(Int(mx * scale))),6,"0"))
Default : SetGadgetData(gadget, mx * scale)
EndSelect
Case #PB_EventType_MouseMove
If drag
mx = GetGadgetAttribute(gadget,#PB_Canvas_MouseX)
StartDrawing(CanvasOutput(gadget))
DrawImage(ImageID(img),0,0)
DrawingMode(#PB_2DDrawing_XOr)
Box(mx-1,0,3,20,cxor)
StopDrawing()
Select gadget
Case #Can_Hue : SetGadgetData(gadget, hue(Int(mx * scale)))
SetGadgetText(#Fra_Hue,"HUE | " + RSet(Hex(hue(Int(mx * scale))),6,"0"))
Default : SetGadgetData(gadget, mx * scale)
EndSelect
EndIf
Case #PB_EventType_LeftButtonUp, #PB_EventType_MouseLeave
If drag : drag = #False
If gadget = #Can_Hue
c = hue(Int(mx * scale))
SetGadgetData(#Can_Adj_R,Red(c)) : REDRAW_CUSTOM_TRACKBAR(#Can_Adj_R)
SetGadgetData(#Can_Adj_G,Green(c)) : REDRAW_CUSTOM_TRACKBAR(#Can_Adj_G)
SetGadgetData(#Can_Adj_B,Blue(c)) : REDRAW_CUSTOM_TRACKBAR(#Can_Adj_B)
Tcolor = c
Else
Tcolor = RGB(GetGadgetData(#Can_Adj_R),GetGadgetData(#Can_Adj_G),
GetGadgetData(#Can_Adj_B))
EndIf
SetGadgetText(#Fra_Modify,"Modify | " + RSet(Hex(Tcolor),6,"0"))
DRAW_PALETTE(#opt_direct)
EndIf
EndSelect
EndProcedure
Procedure COLORIZE_IMAGE(image.i)
;direct method, no blending between color transitions
;global array tone() holds 4 blending colors
;option gadgets determine how many of the colors are used
Protected.i c, i, x, y, xMax, yMax
Protected.d r1, g1, b1, r2, g2, b2, r3, g3, b3, r4, g4, b4
Protected.i dither = GetGadgetState(#Chk_Dither)
Protected.i th1 = GetGadgetState(#spin_thresh_1) * 7
Protected.i th2 = GetGadgetState(#spin_thresh_2) * 7
Protected.i th3 = GetGadgetState(#spin_thresh_3) * 7
r1 = Red(tone(0)) /1785 : r2 = Red(tone(1)) /1785 : r3 = Red(tone(2)) /1785 : r4 = Red(tone(3)) /1785
g1 = Green(tone(0))/1785 : g2 = Green(tone(1))/1785 : g3 = Green(tone(2))/1785 : g4 = Green(tone(3))/1785
b1 = Blue(tone(0)) /1785 : b2 = Blue(tone(1)) /1785 : b3 = Blue(tone(2)) /1785 : b4 = Blue(tone(3)) /1785
If IsImage(image)
StartDrawing(ImageOutput(image))
xMax = OutputWidth() - 1
yMax = OutputHeight() - 1
For y = 0 To yMax
For x = 0 To xMax
If dither
c = PointOrdDith(x, y)
Else
c = Point(x, y)
EndIf
i = (c & $FF) << 1 : c >> 8
i + (C & $FF) << 2 : c >> 8
i + (C & $FF)
If i > th1
Plot(x, y, RGB(r1*i, g1*i, b1*i))
ElseIf i > th2
Plot(x, y, RGB(r2*i, g2*i, b2*i))
ElseIf i > th3
Plot(x, y, RGB(r3*i, g3*i, b3*i))
Else
Plot(x, y, RGB(r4*i, g4*i, b4*i))
EndIf
Next x
Next y
StopDrawing()
EndIf
EndProcedure
Procedure COLORIZE_QUADTONE(Image)
;colorize image with smooth transitions between colors
;global array tone() holds 4 blending colors
;option gadgets determine how many of the colors are used
;blending with 2, 3, or 4 colors is possible
Protected.i c, x, y, w, h
Protected.i R1, G1, B1, R2, G2, B2, R3, G3, B3, R4, G4, B4
Protected.i lum_1, lum_2, DkR, DkG, DkB, tc
; determine how many colors to blend, default = 2
If GetGadgetState(#opt_tri)
tc = %01
ElseIf GetGadgetState(#opt_quad)
tc = %11
EndIf
; expand color components
R1 = Red(tone(0)) : G1 = Green(tone(0)) : B1 = Blue(tone(0))
R2 = Red(tone(1)) : G2 = Green(tone(1)) : B2 = Blue(tone(1))
R3 = Red(tone(2)) : G3 = Green(tone(2)) : B3 = Blue(tone(2))
R4 = Red(tone(3)) : G4 = Green(tone(3)) : B4 = Blue(tone(3))
Select tc ; determinw which color will blend to dark
Case %00 : DkR = R2 : DkG = G2 : DkB = B2 ;Duotone
Case %01 : DkR = R3 : DkG = G3 : DkB = B3 ;TriTone
Case %11 : DkR = R4 : DkG = G4 : DkB = B4 ;QuadTone
EndSelect
; process image
If IsImage(Image) And StartDrawing(ImageOutput(Image))
w = OutputWidth()
h = OutputHeight()
While y < h
x = 0
While x < w
c = Point(x, y)
; calculate luma where lum_1 <= $1FFFF
; weight = R*0.299, G*0.587, B*0.114
lum_1 = c & $FF * $266C0 : c >> 8 ; red
lum_1 + c & $FF * $4B6E2 : c >> 8 ; grn
lum_1 + c & $FF * $0EA63 ; blu
lum_1 >> 10
If lum_1 > $FFFF ; C1 to C2 range
lum_1 & $FFFF
lum_2 = ($FFFF - lum_1)>>1
Plot(x, y,
RGB((lum_1*R1 + lum_2*R2)>>16, ;red
(lum_1*G1 + lum_2*G2)>>16, ;grn
(lum_1*B1 + lum_2*B2)>>16));blu
ElseIf (tc & %01) And lum_1 > $7FFF ; C2 to C3 range
lum_1 & $7FFF
lum_2 = ($7FFF - lum_1)>>1
Plot(x, y,
RGB((lum_1*R2 + lum_2*R3)>>16, ;red
(lum_1*G2 + lum_2*G3)>>16, ;grn
(lum_1*B2 + lum_2*B3)>>16));blu
ElseIf (tc & %10) And lum_1 > $3FFF ; C3 to C4 range
lum_1 & $3FFF
lum_2 = ($3FFF - lum_1)>>1
Plot(x, y,
RGB((lum_1*R3 + lum_2*R4)>>16, ;red
(lum_1*G3 + lum_2*G4)>>16, ;grn
(lum_1*B3 + lum_2*B4)>>16));blu
Else ; C? to dark range
lum_1 >> 1
Plot(x, y,
RGB((lum_1*DkR)>>16, ;red
(lum_1*DkG)>>16, ;grn
(lum_1*DkB)>>16));blu
EndIf
x + 1
Wend
y + 1
Wend
StopDrawing()
EndIf
EndProcedure
Procedure COPY()
; copy active image to clipboard
Protected timeout, img, msgWin, x, y, t$ = "copied to clipboard."
If ColorizeWinActive
SetClipboardImage(#imgAdj)
Else
SetClipboardImage(#imgRef)
EndIf
x = ImageWidth(#imgRef)/2 + 30 + WindowX(#WinMain)
y = ImageHeight(#imgRef)/2 - 15 + WindowY(#WinMain)
msgWin = OpenWindow(#PB_Any,x,y,200,30,"",#PB_Window_BorderLess)
TextGadget(#PB_Any,0,5,200,25,t$,#PB_Text_Center)
timeout = ElapsedMilliseconds() + 1250
While ElapsedMilliseconds() < timeout
While WindowEvent() : Wend
Delay(10)
Wend
CloseWindow(msgWin)
EndProcedure
Procedure CREATE_PALETTE(size.i)
Protected.f inc, total, Rr, Gr, Br, Mr
Protected.i count, max, sum, idx, offset, r, g, b, n
Select toneOption
Case #opt_mono : ReDim Hue_Palette(size*1 -1) : n = 0
Case #opt_duo : ReDim Hue_Palette(size*2 -1) : n = 1
Case #opt_tri : ReDim Hue_Palette(size*3 -1) : n = 2
Case #opt_quad : ReDim Hue_Palette(size*4 -1) : n = 3
EndSelect
For count = 0 To n
r = Red(tone(count))
g = Green(tone(count))
b = Blue(tone(count))
sum = r + g + b
max = g
If r > max : max = r : EndIf
If b > max : max = b : EndIf
inc = max / (size)
Rr = r / sum
Gr = g / sum
Br = b / sum
Mr = max / sum
offset = count * size
For idx = 0 To size - 1
total = (max - inc * idx) / Mr ; calc' R+G+B total
r = Round(total * Rr, #PB_Round_Nearest)
g = Round(total * Gr, #PB_Round_Nearest)
b = Round(total * Br, #PB_Round_Nearest)
Hue_Palette(idx + offset) = (r + g<<8 + b<<16)
Next idx
Next count
EndProcedure
Procedure DRAW_PALETTE(style.i)
Protected.i xMax, yMax, i, j, n, size = GetGadgetState(#trk_palSize)
Protected.f x, r, g, b, h, inc, yi, y1, y2
StartDrawing(ImageOutput(#img_Tone))
xMax = OutputWidth() - 1
yMax = OutputHeight() - 1
inc = OutputWidth() / 256
h = OutputHeight() - 1
If style = #opt_palette
CREATE_PALETTE(size)
Select toneOption
Case #opt_mono : n = 1
Case #opt_duo : n = 2
Case #opt_tri : n = 3
Case #opt_quad : n = 4
EndSelect
pMlt = n
inc = Round(OutputWidth() / size, #PB_Round_Nearest)
yi = OutputHeight() / n
y1 = 0
y2 = yi
For j = 1 To n
x = xMax
For i = 0 To size - 1
Box(x-inc, y1, inc, y2, Hue_Palette(i + Int(size*(j-1))))
x - inc
Next i
y1 + yi
y2 + yi
Next j
Else
r = Red(Tcolor)
g = Green(Tcolor)
b = Blue(Tcolor)
r/xMax : g/xMax : b/xMax
x = 0
Repeat
LineXY(x, 0, x, yMax, RGB(r*x, g*x, b*x))
x + inc
Until x > xMax : x - inc
EndIf
StopDrawing()
SetGadgetState(#ImgGad_Tone,ImageID(#img_Tone))
SetGadgetText(#Fra_palSize,Str(paletteSize * pMlt))
EndProcedure
Procedure DRAW_GRAD(image.i, shift)
Protected inc.f, c.f, x.i
StartDrawing(ImageOutput(image))
inc = (256 / OutputWidth())
c = 0
For x = 0 To OutputWidth() - 1
LineXY(x,0,x,19,Int(c)<<shift)
c + inc
Next
StopDrawing()
EndProcedure
Procedure EVENT_LOOP()
Protected event
Repeat
event = WaitWindowEvent()
Select EventWindow()
Case #WinMain : HANDLE_WIN_MAIN_EVENTS(event)
Case #WinColorize : HANDLE_WIN_COLORIZE_EVENTS(event)
EndSelect
Until endProgram = #True
EndProcedure
Procedure.l FIND_NEAREST(Color.l)
; Find the nearest color
; Taken from NearestColor module by Wilbert
; Latest updated : Jan 27, 2016
; Color distance formula based on:
; http://www.compuphase.com/cmetric.htm
Protected.l c, c0, c1, d, bestd = $12000000
Protected.Long *p0, *p1
EnableASM
Macro M_FindNearest(i, st)
!nearestcolor.findnearest#i#_loop:
!mov ecx, [p.v_c#i#]
!test ecx, ecx
!jz nearestcolor.findnearest#i#_cont2
!movzx eax, byte [p.v_Color + 1]
!movzx ecx, ch
!sub eax, ecx
!imul eax, eax
!shl eax, 11
!cmp eax, [p.v_bestd]
!jnc nearestcolor.findnearest#i#_cont1
!mov [p.v_d], eax
!movzx eax, byte [p.v_Color]
!movzx ecx, byte [p.v_c#i#]
!lea edx, [eax + ecx] ; edx = rsum
!sub eax, ecx
!imul eax, eax ; eax = r*r
!lea ecx, [edx + 0x400] ; ecx = $400 + rsum
!imul eax, ecx ; eax = ($400+rsum)*r*r
!add [p.v_d], eax
!movzx eax, byte [p.v_Color + 2]
!movzx ecx, byte [p.v_c#i# + 2]
!sub eax, ecx
!imul eax, eax ; eax = b*b
!neg edx
!add edx, 0x5fe ; edx = $5fe - rsum
!imul eax, edx ; eax = ($5fe-rsum)*b*b
!add eax, [p.v_d]
!cmp eax, [p.v_bestd]
!jnc nearestcolor.findnearest#i#_cont0
!mov [p.v_bestd], eax
!mov eax, [p.v_c#i#]
!mov [p.v_c], eax
!nearestcolor.findnearest#i#_cont0:
mov rdx, *p#i
add rdx, st
mov *p#i, rdx
mov eax, [rdx]
!mov [p.v_c#i#], eax
CompilerIf i = 1
!jmp nearestcolor.findnearest0_loop
CompilerElse
!jmp nearestcolor.findnearest1_loop
CompilerEndIf
!nearestcolor.findnearest#i#_cont1:
!mov dword [p.v_c#i#], 0
!nearestcolor.findnearest#i#_cont2:
CompilerIf i = 1
!cmp dword [p.v_c0], 0
!jnz nearestcolor.findnearest0_loop
CompilerEndIf
EndMacro
!movzx eax, byte [p.v_Color + 1]
!mov [p.v_d], eax
*p1 = @Palette(IndexG(d)) : *p0 = *p1 - 4
c0 = *p0\l : c1 = *p1\l
M_FindNearest(0, -4)
M_FindNearest(1, 4)
DisableASM
ProcedureReturn c
EndProcedure
Procedure FIT_CANVAS_TO_WINDOW()
; handle main window resize event
; resize canvas to fit window
Protected ww = WindowWidth(#WinMain,#PB_Window_InnerCoordinate)
Protected wh = WindowHeight(#WinMain,#PB_Window_InnerCoordinate) - MenuHeight()
Protected iw = ImageWidth(#imgRef)
Protected ih = ImageHeight(#imgRef)
Protected cw, ch
ResizeGadget(#Canvas, 0, 0, ww, wh-LinuxAdj) ;<-- -4 for Linux
;Pan_X = 0 : Pan_Y = 0
If iw < ww : Pan_X = 0 : EndIf
If ih < wh : Pan_Y = 0 : EndIf
cw = GadgetWidth(#Canvas)
ch = GadgetHeight(#Canvas)
If iw > ww Or ih > wh
oversize = #True
Else
oversize = #False
EndIf
; set canvas cursor
If oversize = #True
CompilerIf #PB_Compiler_OS = #PB_OS_MacOS
SetGadgetAttribute(#Canvas,#PB_Canvas_Cursor , #PB_Cursor_Hand)
CompilerElse
SetGadgetAttribute(#Canvas,#PB_Canvas_Cursor , #PB_Cursor_Arrows)
CompilerEndIf
Else
SetGadgetAttribute(#Canvas,#PB_Canvas_Cursor , #PB_Cursor_Default)
EndIf
If ColorizeWinActive
UPDATE_CANVAS(#imgAdj)
Else
UPDATE_CANVAS(#imgRef)
EndIf
EndProcedure
Procedure FIT_WINDOW_TO_IMAGE(image.i)
Protected iw = ImageWidth(image)
Protected ih = ImageHeight(image)
If GetWindowState(#WinMain) <> #PB_Window_Maximize
If iw > CanvasMaxWidth : iw = CanvasMaxWidth : EndIf
If iw < CanvasMinWidth : iw = CanvasMinWidth : EndIf
If ih > CanvasMaxHeight : ih = CanvasMaxHeight : EndIf
If ih < CanvasMinHeight : ih = CanvasMinHeight : EndIf
ih + MenuHeight() + LinuxAdj ;<-- +4 for Linux
ResizeWindow(#WinMain,(DW-iw-WinBorder_X)/2,(DH-ih-WinBorder_Y)/2,iw,ih)
EndIf
FIT_CANVAS_TO_WINDOW()
EndProcedure
Procedure HANDLE_WIN_COLORIZE_EVENTS(event.i)
Static gadget, cp, cd, r, g, b, max, idx_s, idx_t, mpy.f
Static dragSource, sourceImageID, dragTarget, mx, my, altered = #False
Select event
Case #PB_Event_CloseWindow
If IsImage(#img_Tone) : FreeImage(#img_Tone) : EndIf
If altered : UPDATE_CANVAS(#imgRef) : altered = 0 : EndIf
RemoveKeyboardShortcut(#WinColorize, #PB_Shortcut_Return)
ColorizeWinActive = #False
If oversize = #True
CompilerIf #PB_Compiler_OS = #PB_OS_MacOS
SetGadgetAttribute(#Canvas,#PB_Canvas_Cursor , #PB_Cursor_Hand)
CompilerElse
SetGadgetAttribute(#Canvas,#PB_Canvas_Cursor , #PB_Cursor_Arrows)
CompilerEndIf
Else
SetGadgetAttribute(#Canvas,#PB_Canvas_Cursor , #PB_Cursor_Default)
EndIf
CloseWindow(#WinColorize)
Case #PB_Event_Menu
If EventMenu() = #MenuItem_Enter
gadget = GetActiveGadget()
Select gadget
Case #spin_thresh_1, #spin_thresh_2, #spin_thresh_3
SetGadgetState(gadget,Val(GetGadgetText(gadget)))
PostEvent(#PB_Event_Gadget,#WinColorize,GetActiveGadget(),#PB_EventType_Up)
EndSelect
EndIf
Case #PB_Event_Gadget
gadget = EventGadget()
Select gadget
Case #trk_palSize
paletteSize = GetGadgetState(#trk_palSize)
SetGadgetText(#Fra_palSize,Str(paletteSize * pMlt))
If method = #opt_palette
cp = 1
cd = ElapsedMilliseconds() + 300
EndIf
Case #imgGad_C1, #imgGad_C2, #imgGad_C3, #imgGad_C4
If EventType() = #PB_EventType_DragStart
dragSource = gadget
sourceImageID = GetGadgetState(gadget)
DragPrivate(DragPrivateImage)
ElseIf EventType() = #PB_EventType_LeftDoubleClick
Select gadget
Case #imgGad_C1 : Tcolor = tone(0)
Case #imgGad_C2 : Tcolor = tone(1)
Case #imgGad_C3 : Tcolor = tone(2)
Case #imgGad_C4 : Tcolor = tone(3)
EndSelect
T_COLOR_UPDATE()
EndIf
Case #ImgGad_Tone
If EventType() = #PB_EventType_RightClick ; maximize luma
r = Red(Tcolor) : g = Green(Tcolor) : b = Blue(Tcolor)
max = r : If g > max : max = g : EndIf : If b > max : max = b : EndIf
mpy = 255.0 / max
r = Round(mpy * r,#PB_Round_Nearest)
g = Round(mpy * g,#PB_Round_Nearest)
b = Round(mpy * b,#PB_Round_Nearest)
Tcolor = RGB(r,g,b)
T_COLOR_UPDATE()
ElseIf EventType() = #PB_EventType_LeftClick ; reduce luma
StartDrawing(ImageOutput(#img_Tone))
mx = WindowMouseX(#WinColorize)-GadgetX(#ImgGad_Tone)
my = WindowMouseY(#WinColorize)-GadgetY(#ImgGad_Tone)
Tcolor = Point(mx,my)
StopDrawing()
T_COLOR_UPDATE()
EndIf
Case #Combo_presets : LOAD_PRESET()
Case #btn_preview
CopyImage(#imgRef,#ImgAdj)
DisableGadget(#Btn_Apply,0)
Select method
Case #opt_palette : ASSEMBLE_TO_PALETTE(#ImgAdj, Hue_Palette())
Case #opt_direct : COLORIZE_IMAGE(#imgAdj)
Case #opt_blend : COLORIZE_QUADTONE(#imgAdj)
EndSelect
UPDATE_CANVAS(#ImgAdj)
altered = #True
Case #btn_apply
CopyImage(#ImgAdj,#imgRef)
UPDATE_CANVAS(#imgRef)
altered = #False
PostEvent(#PB_Event_CloseWindow,#WinColorize,#PB_Ignore)
Case #btn_close : PostEvent(#PB_Event_CloseWindow,#WinColorize,#PB_Ignore)
Case #Btn_source : UPDATE_CANVAS(#imgRef) : DisableGadget(#btn_apply,1)
Case #btn_C1_set : tone(0) = Tcolor
CreateImage(#img_C1,51,26,24,tone(0))
SetGadgetState(#imgGad_C1,ImageID(#img_C1))
If method = #opt_palette : DRAW_PALETTE(#opt_palette) : EndIf
Case #btn_C2_set : tone(1) = Tcolor
CreateImage(#img_C2,51,26,24,tone(1))
SetGadgetState(#imgGad_C2,ImageID(#img_C2))
If method = #opt_palette : DRAW_PALETTE(#opt_palette) : EndIf
Case #btn_C3_set : tone(2) = Tcolor
CreateImage(#img_C3,51,26,24,tone(2))
SetGadgetState(#imgGad_C3,ImageID(#img_C3))
If method = #opt_palette : DRAW_PALETTE(#opt_palette) : EndIf
Case #btn_C4_set : tone(3) = Tcolor
CreateImage(#img_C4,51,26,24,tone(3))
SetGadgetState(#imgGad_C4,ImageID(#img_C4))
If method = #opt_palette : DRAW_PALETTE(#opt_palette) : EndIf
Case #opt_mono, #opt_duo, #opt_tri, #opt_quad
UPDATE_TONEOPTION(gadget)
Case #opt_direct, #opt_palette, #opt_blend
UPDATE_METHOD(gadget)
Case #spin_thresh_1, #spin_thresh_2, #spin_thresh_3
SPIN_ADJUST(gadget)
Case #chk_dither
dither = GetGadgetState(#chk_dither)
EndSelect
Case #PB_Event_GadgetDrop
If EventDropType() = #PB_Drop_Private
If EventDropPrivate() = DragPrivateImage
dragTarget = EventGadget()
SetGadgetState(dragSource, GetGadgetState(dragTarget))
Delay(50)
While WindowEvent() : Wend
Delay(50)
SetGadgetState(dragTarget, sourceImageID)
Select dragSource
Case #imgGad_C1 : idx_s = 0
Case #imgGad_C2 : idx_s = 1
Case #imgGad_C3 : idx_s = 2
Case #imgGad_C4 : idx_s = 3
EndSelect
Select dragTarget
Case #imgGad_C1 : idx_t = 0
Case #imgGad_C2 : idx_t = 1
Case #imgGad_C3 : idx_t = 2
Case #imgGad_C4 : idx_t = 3
EndSelect
Swap tone(idx_s), tone(idx_t)
EndIf
EndIf
EndSelect
If cp = #True
If ElapsedMilliseconds() > cd
cp = #False
DRAW_PALETTE(method)
EndIf
EndIf
EndProcedure
Procedure HANDLE_WIN_MAIN_EVENTS(event.i)
Static F$
Select event
Case #PB_Event_CloseWindow
endProgram = #True
Case #PB_Event_SizeWindow : FIT_CANVAS_TO_WINDOW()
Case #PB_Event_RestoreWindow : FIT_WINDOW_TO_IMAGE(#imgRef)
Case #PB_Event_RightClick
If ColorizeWinActive = #False
DisplayPopupMenu(#PopMenu,WindowID(#WinMain))
EndIf
Case #PB_Event_Menu
If ColorizeWinActive = #False
Select EventMenu()
Case #MenuItem_Load : LOAD_IMAGE()
Case #MenuItem_Save : SAVE_IMAGE()
Case #MenuItem_Copy : COPY()
Case #MenuItem_Paste : PASTE()
Case #MenuItem_Exit : endProgram = #True
Case #MenuItem_Colorize : OPEN_COLORIZE_WINDOW()
Case #MenuItem_Revert : REVERT()
EndSelect
EndIf
Case #PB_Event_Gadget
Select EventGadget()
EndSelect
Case #PB_Event_GadgetDrop
If EventDropType() = #PB_Drop_Files
F$ = EventDropFiles()
If LoadImage(#imgRef, F$)
File$ = F$ ; for global use
CurrentFileName$ = GetFilePart(F$,#PB_FileSystem_NoExtension) ; for global use
CopyImage(#imgRef,#imgRevert)
Pan_X = 0 : Pan_Y = 0
F$ = GetFilePart(File$) + " | (" + ImageWidth(#imgRef) + " x " + ImageHeight(#imgRef) + ")"
SetWindowTitle(#WinMain,Title$ + "| " + F$)
FIT_WINDOW_TO_IMAGE(#imgRef)
EndIf
EndIf
EndSelect
EndProcedure
Procedure LOAD_IMAGE()
Static Path$, pattern, firstRun = #True
Protected Pattern$ = "all supported formats|*.png;*.jpg;*.jpeg;*.jp2;;*.bmp|*.png|*.png|*.jpg, *.jpeg"+
"|*.jpg;*.jpeg|*.jpeg2000|*.jp2|*.bmp|*.bmp|all files|*.*"
Protected F$, text$, h, w, aw, ah, x, y
If firstRun = #True : firstRun = #False
Path$ = GetPathPart(File$)
EndIf
F$ = OpenFileRequester("Select image to process", Path$, Pattern$, pattern)
If F$
File$ = F$ ; for global use
pattern = SelectedFilePattern()
CurrentFileName$ = GetFilePart(F$,#PB_FileSystem_NoExtension) ; for global use
Path$ = GetPathPart(F$)
If LoadImage(#imgRef, F$)
CopyImage(#imgRef,#imgRevert)
Pan_X = 0 : Pan_Y = 0
F$ = GetFilePart(File$) + " | (" + ImageWidth(#imgRef) + " x " + ImageHeight(#imgRef) + ")"
SetWindowTitle(#WinMain,Title$ + "| " + F$)
FIT_WINDOW_TO_IMAGE(#imgRef)
EndIf
EndIf
EndProcedure
Procedure LOAD_PRESET()
If EventType() = #PB_EventType_Change
preset = GetGadgetState(#Combo_presets)
SelectElement(presetList(),preset)
tone(0) = presetList()\C1
tone(1) = presetList()\C2
tone(2) = presetList()\C3
tone(3) = presetList()\C4
CreateImage(#img_C1,51,26,24,tone(0))
SetGadgetState(#imgGad_C1,ImageID(#img_C1))
CreateImage(#img_C2,51,26,24,tone(1))
SetGadgetState(#imgGad_C2,ImageID(#img_C2))
CreateImage(#img_C3,51,26,24,tone(2))
SetGadgetState(#imgGad_C3,ImageID(#img_C3))
CreateImage(#img_C4,51,26,24,tone(3))
SetGadgetState(#imgGad_C4,ImageID(#img_C4))
If method = #opt_palette : DRAW_PALETTE(method) : EndIf
EndIf
EndProcedure
Procedure OPEN_COLORIZE_WINDOW()
Protected result, R, G, B, x, y
Static firstRun = #True, flags = #PB_Window_Tool|#PB_Window_SystemMenu
x = WindowX(#WinMain,#PB_Window_InnerCoordinate)
y = WindowY(#WinMain,#PB_Window_InnerCoordinate)
result = OpenWindow(#WinColorize,x,y,600,320,"Colorize image",flags,WindowID(#WinMain))
If result
SetWindowColor(#WinColorize,$7E940A)
ColorizeWinActive = #True
DragPrivateImage = WindowID(#WinMain)
AddKeyboardShortcut(#WinColorize, #PB_Shortcut_Return, #MenuItem_Enter)
SetGadgetAttribute(#Canvas,#PB_Canvas_Cursor,#PB_Cursor_Cross)
CreateImage(#img_Hue,1536,20)
CreateImage(#img_Adj_R,256,20)
CreateImage(#img_Adj_G,256,20)
CreateImage(#img_Adj_B,256,20)
CreateImage(#img_C1,51,26,24,tone(0))
CreateImage(#img_C2,51,26,24,tone(1))
CreateImage(#img_C3,51,26,24,tone(2))
CreateImage(#img_C4,51,26,24,tone(3))
R = $FF : G = 0 : B = 0 : x = 0 ;make hue image + fill hue() array
StartDrawing(ImageOutput(#img_Hue))
MakeHueGradient(G, R)
MakeHueGradient(B, G)
MakeHueGradient(R, B)
StopDrawing()
ResizeImage(#img_Hue,530,20)
DRAW_GRAD(#img_Adj_R,0)
DRAW_GRAD(#img_Adj_G,8)
DRAW_GRAD(#img_Adj_B,16)
FrameGadget(#Fra_Hue,5,5,540,50,"HUE | FFFF00")
CanvasGadget(#Can_Hue,10,25,530,20,#PB_Canvas_ClipMouse)
BindGadgetEvent(#Can_Hue,@COLORIZE_CANVAS_CALLBACK())
FrameGadget(#Fra_Modify,5,60,266,120,"Modify | " + RSet(Hex(Tcolor),6,"0"))
CanvasGadget(#Can_Adj_R,10,150,256,20,#PB_Canvas_ClipMouse)
CanvasGadget(#Can_Adj_G,10,115,256,20,#PB_Canvas_ClipMouse)
CanvasGadget(#Can_Adj_B,10,080,256,20,#PB_Canvas_ClipMouse)
BindGadgetEvent(#Can_Adj_R,@COLORIZE_CANVAS_CALLBACK())
BindGadgetEvent(#Can_Adj_G,@COLORIZE_CANVAS_CALLBACK())
BindGadgetEvent(#Can_Adj_B,@COLORIZE_CANVAS_CALLBACK())
FrameGadget(#Fra_Method,5,185,70,130,"Method")
OptionGadget(#opt_direct,10,205,60,22,"Abrupt")
OptionGadget(#opt_blend,10,232,60,22,"Blend")
OptionGadget(#opt_palette,10,259,60,22,"Palette")
CheckBoxGadget(#chk_dither,10,286,60,22,"Dither")
SetGadgetState(#chk_dither,dither)
FrameGadget(-1,80,185,70,130,"Tones")
OptionGadget(#opt_mono,85,205,60,22,"One") : GadgetToolTip(#opt_mono,"C1")
OptionGadget(#opt_duo ,85,232,60,22,"Two") : GadgetToolTip(#opt_duo ,"C1, C2")
OptionGadget(#opt_tri ,85,259,60,22,"Three") : GadgetToolTip(#opt_tri ,"C1, C2, C3")
OptionGadget(#opt_quad,85,286,60,22,"Four") : GadgetToolTip(#opt_quad,"C1, C2, C3, C4")
FrameGadget(#Fra_C1 ,255,185,65,87,"C1")
ImageGadget(#imgGad_C1 ,260,205,51,026,ImageID(#img_C1),#PB_Image_Border)
EnableGadgetDrop(#imgGad_C1,#PB_Drop_Private,#PB_Drag_Copy,DragPrivateImage)
GadgetToolTip(#imgGad_C1,"double click to edit")
ButtonGadget(#btn_C1_set ,260,240,55,025,"set")
GadgetToolTip(#btn_C1_set,"set color 1")
FrameGadget(#Fra_C2 ,330,185,65,87,"C2")
ImageGadget(#imgGad_C2 ,335,205,51,026,ImageID(#img_C2),#PB_Image_Border)
EnableGadgetDrop(#imgGad_C2,#PB_Drop_Private,#PB_Drag_Copy,DragPrivateImage)
GadgetToolTip(#imgGad_C2 ,"double click to edit")
ButtonGadget(#btn_C2_set ,335,240,55,025,"set")
GadgetToolTip(#btn_C2_set,"set color 2")
FrameGadget(#Fra_C3 ,405,185,65,87,"C3")
ImageGadget(#imgGad_C3 ,410,205,51,026,ImageID(#img_C3),#PB_Image_Border)
EnableGadgetDrop(#imgGad_C3,#PB_Drop_Private,#PB_Drag_Copy,DragPrivateImage)
GadgetToolTip(#imgGad_C3 ,"double click to edit")
ButtonGadget(#btn_C3_set ,410,240,55,025,"set")
GadgetToolTip(#btn_C3_set,"set color 3")
FrameGadget(#Fra_C4,480,185,65,87,"C4")
ImageGadget(#imgGad_C4,485,205,51,26,ImageID(#img_C4),#PB_Image_Border)
EnableGadgetDrop(#imgGad_C4,#PB_Drop_Private,#PB_Drag_Copy,DragPrivateImage)
GadgetToolTip(#imgGad_C4 ,"double click to edit")
ButtonGadget(#btn_C4_set, 485,240,55,25,"set")
GadgetToolTip(#btn_C4_set,"set color 4")
SpinGadget(#spin_thresh_1,295,280,55,30,0,256)
SpinGadget(#spin_thresh_2,370,280,55,30,0,255)
SpinGadget(#spin_thresh_3,445,280,55,30,0,254)
GadgetToolTip(#spin_thresh_1,"1|2 threshold")
GadgetToolTip(#spin_thresh_2,"2|3 threshold")
GadgetToolTip(#spin_thresh_3,"3|4 threshold")
ButtonGadget(#btn_preview,160,190,85,25,"Preview")
ButtonGadget(#Btn_source ,160,220,85,25,"Source")
ButtonGadget(#btn_apply ,160,250,85,25,"Apply") : DisableGadget(#btn_apply,1)
ButtonGadget(#btn_close ,510,280,85,30,"Close")
GadgetToolTip(#Btn_source,"show source image")
ComboBoxGadget(#Combo_presets,160,280,125,30)
GadgetToolTip(#Combo_presets,"load preset")
ForEach presetList()
AddGadgetItem(#Combo_presets,-1,presetList()\na)
Next
SetGadgetState(#Combo_presets,preset)
If firstRun : firstRun = #False
PostEvent(#PB_Event_Gadget,#WinColorize,#Combo_presets,#PB_EventType_Change)
EndIf
FrameGadget(#Fra_palSize, 550,05,45,266,Str(paletteSize * pMlt))
TrackBarGadget(#trk_palSize,558,25,30,236,2,64,#PB_TrackBar_Vertical)
GadgetToolTip(#trk_palSize,"palette size")
SetGadgetState(#trk_palSize,paletteSize)
DisableGadget(#trk_palSize,1)
SetGadgetState(toneOption,1)
SetGadgetState(method,1)
SetGadgetData(#Can_Hue,HueSet) : REDRAW_CUSTOM_TRACKBAR(#Can_Hue)
SetGadgetData(#Can_Adj_R,Red(Tcolor)) : REDRAW_CUSTOM_TRACKBAR(#Can_Adj_R)
SetGadgetData(#Can_Adj_G,Green(Tcolor)) : REDRAW_CUSTOM_TRACKBAR(#Can_Adj_G)
SetGadgetData(#Can_Adj_B,Blue(Tcolor)) : REDRAW_CUSTOM_TRACKBAR(#Can_Adj_B)
FrameGadget(#Fra_Grad,280,60,266,120,"Gradient or Palette")
CreateImage(#img_Tone,256,100,24,0)
ImageGadget(#ImgGad_Tone,285,75,256,100,ImageID(#Img_Tone))
GadgetToolTip(#ImgGad_Tone,"click: right = maximize, left = darken")
UPDATE_TONEOPTION(toneOption)
UPDATE_METHOD(method)
DRAW_PALETTE(method)
CopyImage(#imgRef,#ImgAdj)
ProcedureReturn result
EndIf
EndProcedure
Procedure OPEN_MAIN_WINDOW()
Protected result, w = 600, h = 450
Protected flags = #PB_Window_SystemMenu | #PB_Window_MinimizeGadget | #PB_Window_SizeGadget |
#PB_Window_MaximizeGadget | #PB_Window_ScreenCentered
result = OpenWindow(#WinMain,0,0,w,h,Title$,flags)
If result
ExamineDesktops()
DW = DesktopWidth(0)
DH = DesktopHeight(0)
CanvasMinHeight = h
CanvasMinWidth = w
WinBorder_X = WindowWidth(#WinMain,#PB_Window_FrameCoordinate) - WindowWidth(#WinMain)
WinBorder_Y = WindowHeight(#WinMain,#PB_Window_FrameCoordinate) - WindowHeight(#WinMain)
CompilerIf #PB_Compiler_OS = #PB_OS_Linux
LinuxAdj = 4
h + MenuHeight() + LinuxAdj
CompilerEndIf
WindowBounds(#WinMain,w,h,#PB_Ignore,#PB_Ignore)
CreateMenu(#MainMenu,WindowID(#WinMain))
MenuTitle(" File ")
MenuItem(#MenuItem_Load,"Load image" + Chr(9) + "Ctrl+L")
MenuItem(#MenuItem_Save,"Save image" + Chr(9) + "Ctrl+S")
MenuBar()
MenuItem(#MenuItem_Exit,"Exit")
MenuTitle(" Edit ")
MenuItem(#MenuItem_Colorize,"Colorize image...")
MenuBar()
MenuItem(#MenuItem_Copy,"Copy to clipboard" + Chr(9) + "Ctrl+C")
MenuItem(#MenuItem_Paste,"Paste from clipboard" + Chr(9) + "Ctrl+V")
MenuBar()
MenuItem(#MenuItem_Revert,"Revert" + Chr(9) + "Ctrl+R")
CreatePopupMenu(#PopMenu)
OpenSubMenu("File...")
MenuItem(#MenuItem_Load,"Load image" + Chr(9) + "Ctrl+L")
MenuItem(#MenuItem_Save,"Save image" + Chr(9) + "Ctrl+S")
MenuBar()
MenuItem(#MenuItem_Exit,"Exit")
CloseSubMenu()
MenuBar()
OpenSubMenu("Edit...")
MenuItem(#MenuItem_Colorize,"Colorize image...")
MenuBar()
MenuItem(#MenuItem_Copy,"Copy to clipboard" + Chr(9) + "Ctrl+C")
MenuItem(#MenuItem_Paste,"Paste from clipboard" + Chr(9) + "Ctrl+V")
MenuBar()
MenuItem(#MenuItem_Revert,"Revert" + Chr(9) + "Ctrl+R")
CloseSubMenu()
AddKeyboardShortcut(#WinMain, #PB_Shortcut_L | #PB_Shortcut_Control , #MenuItem_Load)
AddKeyboardShortcut(#WinMain, #PB_Shortcut_S | #PB_Shortcut_Control , #MenuItem_Save)
AddKeyboardShortcut(#WinMain, #PB_Shortcut_C | #PB_Shortcut_Control , #MenuItem_Copy)
AddKeyboardShortcut(#WinMain, #PB_Shortcut_V | #PB_Shortcut_Control , #MenuItem_Paste)
AddKeyboardShortcut(#WinMain, #PB_Shortcut_R | #PB_Shortcut_Control , #MenuItem_Revert)
CanvasMaxWidth = DW - WinBorder_X
CanvasMaxHeight = DH - WinBorder_Y - MenuHeight()
h - MenuHeight() - LinuxAdj
CanvasGadget(#Canvas,0,0,w,h,#PB_Canvas_ClipMouse)
BindGadgetEvent(#Canvas,@CANVAS_CALLBACK())
EnableGadgetDrop(#Canvas,#PB_Drop_Files,#PB_Drag_Copy)
CreateImage(#imgRef,w,h,24,#CBcolor)
UPDATE_CANVAS(#imgRef)
CompilerIf #PB_Compiler_OS = #PB_OS_Windows
File$ = GetHomeDirectory() + "Pictures\"
CompilerElse
File$ = GetHomeDirectory() + "Pictures/"
CompilerEndIf
File$ + "no_image_loaded"
SetWindowTitle(#WinMain,Title$ + "| " + "no_image_loaded")
EndIf
ProcedureReturn result
EndProcedure
Procedure PASTE()
Protected F$
If GetClipboardImage(#imgRef,32)
CopyImage(#imgRef, #imgRevert)
CurrentFileName$ = "NewImage"
File$ = GetPathPart(File$) + CurrentFileName$
F$ = CurrentFileName$ + " | (" + ImageWidth(#imgRef) + " x " + ImageHeight(#imgRef) + ")"
SetWindowTitle(#WinMain,Title$ + "| " + F$)
FIT_WINDOW_TO_IMAGE(#imgRef)
EndIf
EndProcedure
Procedure.l PointOrdDith(x.i, y.i)
;this procedure was borrowed from Wilbert's Neuquant module
EnableASM
Point(x, y)
!movd xmm0, eax
!mov al, [p.v_x]
!mov ah, [p.v_y]
!shl al, 6
!and eax, 0x3c0
!shr ax, 3
!punpcklbw xmm0, xmm0
CompilerIf #x64
!lea rdx, [nearest.l_pointorddith]
!movq xmm1, [rdx + rax]
CompilerElse
!movq xmm1, [nearest.l_pointorddith + eax]
CompilerEndIf
!psrlw xmm0, 8
!paddw xmm0, xmm1
!packuswb xmm0, xmm0
!movd eax, xmm0
ProcedureReturn
!nearest.l_pointorddith:
!dq 0xfff9fff9fff9, 0x000100010001, 0xfffbfffbfffb, 0x000300030003
!dq 0x000500050005, 0xfffdfffdfffd, 0x000700070007, 0xffffffffffff
!dq 0xfffcfffcfffc, 0x000400040004, 0xfffafffafffa, 0x000200020002
!dq 0x000800080008, 0x000000000000, 0x000600060006, 0xfffefffefffe
DisableASM
EndProcedure
Procedure REDRAW_CUSTOM_TRACKBAR(canvas.i)
Protected cxor.i, image.i, position.i = GetGadgetData(canvas)
Select canvas
Case #Can_Hue : image = #img_Hue : cxor = $FFFFFF
Case #Can_Adj_R : image = #img_Adj_R : cxor = $00FFFF
Case #Can_Adj_G : image = #img_Adj_G : cxor = $FF00FF
Case #Can_Adj_B : image = #img_Adj_B : cxor = $00FFFF
EndSelect
StartDrawing(CanvasOutput(canvas))
DrawImage(ImageID(image),0,0)
DrawingMode(#PB_2DDrawing_XOr)
Box(position-1,0,3,20,cxor)
StopDrawing()
EndProcedure
Procedure REVERT()
If IsImage(#imgRevert)
CopyImage(#imgRevert,#imgRef)
UPDATE_CANVAS(#imgRef)
EndIf
EndProcedure
Procedure SAVE_IMAGE()
Static YesNo = #PB_MessageRequester_YesNo, Yes = #PB_MessageRequester_Yes
Static Pattern$ = "image.png|*.png|image.jpg|*.jpg|image.jpeg|*.jpeg|image.jpeg2000|*.jp2|image.bmp|*.bmp"
Static lastPattern = 1, firstRun = #True
Protected F$, p, cancel = #False
Select LCase(GetExtensionPart(File$))
Case "png" : lastPattern = 0
Case "jpg" : lastPattern = 1
Case "jpeg": lastPattern = 2
Case "jpeg2000" : lastPattern = 3
Case "bmp" : lastPattern = 4
EndSelect
F$ = SaveFileRequester("Save image", GetPathPart(File$)+CurrentFileName$, Pattern$, lastPattern)
If F$
lastPattern = SelectedFilePattern()
; remove any existing file extension
p = FindString(ReverseString(F$),".")
If p
F$ = Left(F$,Len(F$)-p)
EndIf
Select SelectedFilePattern()
Case 0 : F$ + ".png"
Case 1 : F$ + ".jpg"
Case 2 : F$ + ".jpeg"
Case 3 : F$ + ".jp2"
Case 4 : F$ + ".bmp"
EndSelect
If FileSize(F$) <> -1 ; file exists
If MessageRequester("File Exists!", "Do you wish to overwrite?", YesNo) <> Yes
cancel = #True
EndIf
EndIf
If cancel = #False
Select SelectedFilePattern()
Case 0 : SaveImage(#imgRef, F$, #PB_ImagePlugin_PNG)
Case 1 : SaveImage(#imgRef, F$, #PB_ImagePlugin_JPEG,8)
Case 2 : SaveImage(#imgRef, F$, #PB_ImagePlugin_JPEG,8)
Case 3 : SaveImage(#imgRef, F$, #PB_ImagePlugin_JPEG2000,3)
Case 4 : SaveImage(#imgRef, F$, #PB_ImagePlugin_BMP)
EndSelect
File$ = F$ ; for global use
F$ = GetFilePart(File$) + " | (" + ImageWidth(#imgRef) + " x " + ImageHeight(#imgRef) + ")"
SetWindowTitle(#WinMain,Title$ + "| " + F$)
EndIf
EndIf
EndProcedure
Procedure SPIN_ADJUST(gadget)
Protected value.i
Select EventType()
Case #PB_EventType_Change
SetGadgetState(gadget,Val(GetGadgetText(gadget)))
Case #PB_EventType_Up, #PB_EventType_Down
value = GetGadgetState(gadget)
Select gadget
Case #spin_thresh_1
If value <= GetGadgetState(#spin_thresh_2)
value =GetGadgetState(#spin_thresh_2)+1
EndIf
SM1 = value
Case #spin_thresh_2
If value <= GetGadgetState(#spin_thresh_3)
value = GetGadgetState(#spin_thresh_3)+1
ElseIf value >= GetGadgetState(#spin_thresh_1)
value = GetGadgetState(#spin_thresh_1)-1
EndIf
SM2 = value
Case #spin_thresh_3
If value >= GetGadgetState(#spin_thresh_2)
value = GetGadgetState(#spin_thresh_2)-1
EndIf
SM3 = value
EndSelect
SetGadgetText(gadget,Str(value))
SetGadgetState(gadget,value)
EndSelect
EndProcedure
Procedure T_COLOR_UPDATE()
SetGadgetData(#Can_Adj_R,Red(Tcolor))
SetGadgetData(#Can_Adj_G,Green(Tcolor))
SetGadgetData(#Can_Adj_B,Blue(Tcolor))
SetGadgetText(#Fra_Modify,"Modify | " + RSet(Hex(Tcolor),6,"0"))
REDRAW_CUSTOM_TRACKBAR(#Can_Adj_R)
REDRAW_CUSTOM_TRACKBAR(#Can_Adj_G)
REDRAW_CUSTOM_TRACKBAR(#Can_Adj_B)
DRAW_PALETTE(#opt_direct)
EndProcedure
Procedure UPDATE_CANVAS(image.i)
Protected x, y, iw, ih, ow, oh, Llim, Rlim, Tlim, Blim, text$
If IsImage(image)
StartDrawing(CanvasOutput(#Canvas))
ow = OutputWidth() : iw = ImageWidth(image)
oh = OutputHeight() : ih = ImageHeight(image)
Box(0,0,ow,oh,#CBcolor)
x = (ow - iw) / 2 + Pan_X
y = (oh - Ih) / 2 + Pan_Y
DrawImage(ImageID(image),x,y)
StopDrawing()
EndIf
EndProcedure
Procedure UPDATE_METHOD(gadget.i)
If method <> #opt_palette And gadget = #opt_palette
DRAW_PALETTE(#opt_palette)
ElseIf method = #opt_palette And gadget <> #opt_palette
DRAW_PALETTE(gadget)
EndIf
method = gadget
If method = #opt_blend
If GetGadgetState(#opt_mono)
SetGadgetState(#opt_mono,0)
SetGadgetState(#opt_duo, 1)
toneOption = #opt_duo
UPDATE_TONEOPTION(toneOption)
EndIf
EndIf
If method = #opt_direct
UPDATE_TONEOPTION(toneOption)
Else
DisableGadget(#spin_thresh_1, 1) : DisableGadget(#spin_thresh_2, 1) : DisableGadget(#spin_thresh_3, 1)
EndIf
DisableGadget(#opt_mono,Bool(method = #opt_blend))
DisableGadget(#chk_dither,Bool(method = #opt_blend))
DisableGadget(#trk_palSize,Bool(method <> #opt_palette))
EndProcedure
Procedure UPDATE_TONEOPTION(gadget.i)
Protected S2, S3, S4, L1, L2, L3
toneOption = gadget
Select gadget
Case #opt_mono : L1 = 0 : L2 = 0 : L3 = 0
S2 = 1 : S3 = 1 : S4 = 1
Case #opt_duo : L1 = SM1 : L2 = 0 : L3 = 0
S2 = 0 : S3 = 1 : S4 = 1
Case #opt_tri : L1 = SM1 : L2 = SM2 : L3 = 0
S2 = 0 : S3 = 0 : S4 = 1
Case #opt_quad : L1 = SM1 : L2 = SM2 : L3 = SM3
S2 = 0 : S3 = 0 : S4 = 0
EndSelect
DisableGadget(#btn_C2_set,S2) : DisableGadget(#btn_C3_set,S3) : DisableGadget(#btn_C4_set,S4)
DisableGadget(#imgGad_C2,S2) : DisableGadget(#imgGad_C3,S3) : DisableGadget(#imgGad_C4,S4)
If method = #opt_palette
DRAW_PALETTE(#opt_palette)
SetGadgetText(#Fra_palSize,Str(paletteSize * pMlt))
ProcedureReturn
ElseIf method = #opt_direct
SetGadgetState(#spin_thresh_1,L1) : SetGadgetState(#spin_thresh_2,L2) : SetGadgetState(#spin_thresh_3,L3)
SetGadgetText(#spin_thresh_1,Str(L1)) : SetGadgetText(#spin_thresh_2,Str(L2)) : SetGadgetText(#spin_thresh_3,Str(L3))
DisableGadget(#spin_thresh_1, S2) : DisableGadget(#spin_thresh_2, S3) : DisableGadget(#spin_thresh_3, S4)
EndIf
EndProcedure
;{ Preset Color data
DataSection
PresetData:
Data.s "gray scale" : Data.i $FFFFFF, $B0B0B0, $707070, $303030
Data.s "aqua" : Data.i $FFEA00, $FFBF00, $FF9000, $FF5C00
Data.s "blond" : Data.i $BFFDFF, $A3FDFF, $96E3FF, $76D5FF
Data.s "brunette" : Data.i $BDDCFB, $7EACF9, $697AE9, $3F435B
Data.S "candy" : Data.i $4AC5FF, $005FFF, $E08E00, $FF5DB7
Data.s "Cinnabar" : Data.i $76BCFF, $2A3AEF, $D4C343, $0010CF
Data.s "grass" : Data.i $BFFFD9, $77FFD0, $82FFA8, $D2FFC3
Data.s "magic" : Data.i $7FE1FF, $D25BFF, $D7D700, $FFFFFF
Data.s "rainbow" : Data.i $00FFFF, $FFFF00, $FF00FF, $0000FF
Data.s "rose" : Data.i $A228FF, $A228DA, $FF0060, $4611A3
Data.s "skin" : Data.i $8EBFFF, $76B0FF, $5E8DFF, $517AE6
Data.s "tangerine" : Data.i $00DCFF, $00AEFF, $0085FF, $0059FF
Data.s "topaz" : Data.i $7CC8FF, $66A4E7, $4E85CA, $3265A7
Data.s "warrior" : Data.i $A3C2FF, $FFBF00, $4000FF, $FF5C00
Data.s "End_Data"
EndDataSection : ;}