n'est pas a proprement parlé fait pour reduire la taille des images
mais plutot un prg qui permet de reduire le nombre couleurs utilisé pour dessiner une image
par la suite un algo de compression pour etre mis en place pour profiter du nombre de couleurs reduite
et reduire la taille de l'image !
utilisation : (il y a plusieurs mode d'utilisations )
mode normal :
vous chargez une image , elle va se dessiner dans l'interface
[Nbr de couleurs] indique le nombre de couleur que vous voulez utiliser pour redessiner l'image
a noter que vous pouvez faire plusieurs essai, sans avoir a recharger l'image d'origine,le prg repart toujours de l'image d'origine meme si pas affichée
un appuis sur [Run] , ça bosse (indication en haut a gauche de la fenetre)
ça va afficher le resultat ....
le curseur vertical a gauche permet de regler la tolerance , plus il y a de tolerance, plus vous permettez au prg de prendre la couleur qu'il veux pour dessiner !
diminuer la tolerance, oblige le prg a utiliser un crayon de la palette le plus proche possible de la couleur a dessiner ....
faites des tests
Mode Pick :
dans ce mode, vous chargez une image
ensuite en activant le bouton [pick] , vous choisissez des pixels de couleur pour creer la palette de crayons pour le prg
chaque click = un crayon de plus (le compteur se met a jour dans l'interface )
ensuite vous reglez votre tolerance (ou pas) , et lancez le dessin avec [Run] !
la case a cocher Floyd sert a tramer en utilisant l'algo Floyd
la case Flou permet d'ajouter un leger flou sur l'image final
voici le code :
Code : Tout sélectionner
;***********************************************
;Titre :*Pure_reductor_interface
;Auteur : Dobro
;Date :17/03/2016
;Heure :18:01:29
;Version Purebasic : PureBasic 5.60 (Windows - x86)
;Version de l'editeur :EPB V2.64
; Libairies necessaire : Aucune
;***********************************************
;{- Enumerations / DataSections
;{ Windows
Enumeration
#Win
EndEnumeration
;}
;{ Gadgets
Enumeration
#Button_Load
#CheckBox_Floyd
#CheckBox_Flou
#TrackBar_tolerance
#Text_info
#Text_info2
#Text_tol_val
#Text_tolerance
#Text_Titre
#Container_8
#Button_Run
#String_nb_couleur
#Text_color
#Button_Save
#zone_acenseur
#image_palette
#Button_pick
#Image_ori
EndEnumeration
;}
;{ Fonts
Enumeration
#Font_Text_Titre
EndEnumeration
;}
Define.l Event
InitMouse()
UseJPEGImageDecoder():UsePNGImageDecoder():UseTGAImageDecoder():UseTIFFImageDecoder()
UseJPEGImageEncoder()
Resultat = InitSprite()
Declare distance_couleur(couleur1,couleur2)
Declare make_palette(nb_image,nbr_couleur.i,palette )
Declare Dessin(nb_image,nbr_couleur,tolerance,Floyd,flou)
Declare mise_en_tab_ori(nb_image,Largeur_image,Hauteur_image)
Declare mise_en_tab(nb_image,largeur_image,hauteur_image)
Declare flou(nb_image,imagex,imagey, niveau)
Declare doomohundro(himg) ; floyd
Declare.i truncf0255 (a.f)
Declare rgbtolum(c.l) ;get luminosity (the min and max rgb levels / 2)
Enumeration
#Image
#image_resultat
#Fenetre
#file
EndEnumeration
Global NewList palette()
Global NewList des()
Global Flag_pick=-1,compteur,vertical,pas,compteur_coul,nbr_couleur,Flag_pick_pick
;}
Procedure OpenWindow_Win()
If OpenWindow(#Win, 180, 5, 1096, 672, "Pure_reductor By Dobro", #PB_Window_SystemMenu|#PB_Window_SizeGadget|#PB_Window_MinimizeGadget|#PB_Window_TitleBar)
;If CreateGadgetList(WindowID(#Win))
ButtonGadget(#Button_Load, 15, 50, 90, 35, "Load Img")
CheckBoxGadget(#CheckBox_Floyd, 15, 135, 105, 25, "Floyd Tramage")
CheckBoxGadget(#CheckBox_Flou, 15, 160, 105, 25, "Flou")
TrackBarGadget(#TrackBar_tolerance, 10, 235, 45, 310, 0,442, #PB_TrackBar_Ticks|#PB_TrackBar_Vertical)
TextGadget(#Text_tolerance, 10, 210, 75, 25, "Tolerance")
TextGadget(#Text_tol_val,90, 210, 40, 30, "0")
tolerance=0 ; Tolerance par defaut !
SetGadgetState(#TrackBar_tolerance,tolerance)
SetgadgetText (#Text_tol_val,str(tolerance))
SetgadgetText (#Text_tol_val,str(tolerance))
TextGadget(#Text_Titre, 430, 15, 195, 40, "Pure_reductor")
TextGadget(#Text_info, 20, 15, 100, 25, "Info")
TextGadget(#Text_info2, 150,5, 195,40, "Info2")
ButtonGadget(#Button_Run, 10, 545, 90, 35, "Run")
StringGadget(#String_nb_couleur, 85, 90, 35, 20, "256")
TextGadget(#Text_color, 15, 90, 70, 20, "Nbr Couleurs")
ButtonGadget(#Button_Save, 10, 595, 90, 35, "Save Img")
ButtonGadget(#Button_pick, 55, 240, 50, 20, "Pick",#PB_Button_Toggle )
ScrollAreaGadget(#zone_acenseur,130, 55, 940, 595,0, 0, 30)
CanvasGadget(#image_palette, 0,55, 8*16, 8*256)
ContainerGadget(#Container_8, 130, 55, 940, 595,#PB_Container_Double)
OpenWindowedScreen(gadgetID(#Container_8),0, 0, 940, 595, 0, 0, 0 ) ; on met un ecrant dedans
CloseGadgetList()
; Gadget Fonts
SetGadgetFont(#Text_Titre, LoadFont(#Font_Text_Titre, "Microsoft Sans Serif", 22, #PB_Font_HighQuality))
;EndIf
EndIf
EndProcedure
OpenWindow_Win()
;{- Event loop
Repeat
Event = WaitWindowEvent(12)
Select Event
; ///////////////////
Case #PB_Event_Gadget
Select EventGadget()
Case #Button_Load
Flag_pick_pick=0 :vertical=0:compteur=0
if FileSize("chemin.inf")<>-1
if Openfile(#file,"chemin.inf")
chemin$=ReadString(#file)
CloseFile(#file)
NomFichier$=OpenFileRequester("Charge une image", chemin$+"*.*", "", 0)
Endif
chemin$=GetPathPart(NomFichier$)
Openfile(#file,"chemin.inf")
WriteStringN(#file,chemin$)
CloseFile(#file)
Else
NomFichier$ = OpenFileRequester("Charge une image", "*.*", "", 0) ; on choisi un ficher
chemin$=GetPathPart(NomFichier$)
Openfile(#file,"chemin.inf")
WriteStringN(#file,chemin$)
CloseFile(#file)
Endif
If NomFichier$<>""
Resultat = LoadImage(#Image, NomFichier$ ) ; on charge une image
global format$=GetExtensionPart(NomFichier$)
EndIf
if IsImage(#image)
Global largeur_image=ImageWidth(#Image)
Global Hauteur_image=ImageHeight(#Image)
if largeur_image>Hauteur_image : ResizeImage(#image,1024,768):endif
if largeur_image<Hauteur_image : ResizeImage(#image,768,1024):endif
Global largeur_image=ImageWidth(#Image)
Global Hauteur_image=ImageHeight(#Image)
CloseScreen()
OpenWindowedScreen(gadgetID(#Container_8),0, 0, largeur_image,Hauteur_image, 0, 0, 0 ) ; on met un ecran dedans
CopyImage(#Image,#Image_ori)
StartDrawing(ScreenOutput()) ;
DrawImage(ImageID(#Image), 0, 0)
StopDrawing()
ResizeGadget(#container_8, #PB_Ignore, #PB_Ignore,Largeur_image, Hauteur_image)
SetGadgetAttribute(#zone_acenseur, #PB_ScrollArea_InnerWidth , Largeur_image+(Largeur_image/2))
SetGadgetAttribute(#zone_acenseur, #PB_ScrollArea_InnerHeight ,Hauteur_image+(Hauteur_image/2))
Else
MessageRequester("erreur", "l'image n'a pas pu etre chargée")
End
Endif
GLobal Dim TAB_ori(Largeur_image,Hauteur_image) ; le Tableau
GLobal Dim TAB(Largeur_image,Hauteur_image) ; le Tableau
StartDrawing(ImageOutput(nb_image))
mise_en_tab_ori(nb_image,largeur_image,Hauteur_image) ; apres ça l'image 16 millions de couleurs est dans le Tableau Tab_ori()
StopDrawing()
CopyArray(TAB_ori(), TAB())
FlipBuffers()
Case #Button_pick
if IsImage(#image_ori)
ClearScreen($0)
CopyArray(TAB_ori(), TAB())
CopyImage(#Image_ori,#Image)
Flag_pick=-Flag_pick
nbr_couleur=0
if Flag_pick>0 ; mode on recup les couleurs
;on nettoie le canvas qui contient la palette
; StartDrawing(CanvasOutput(#image_palette))
; Box(0,0,GadgetWidth(#image_palette),GadgetHeight(#image_palette),$0)
; StopDrawing()
; on nettoie aussi les listes concernant la palette
ClearList(palette())
ClearList(Des())
Endif
Endif
Case #zone_acenseur
;debug "ascenseur"
; if IsImage(nb_image)
; StartDrawing(ScreenOutput()) ;
; DrawImage(ImageID(nb_image), 0, 0)
; StopDrawing()
; FlipBuffers()
; Endif
Case #CheckBox_Floyd
statF=GetGadgetstate(#CheckBox_Floyd)
if statf=#PB_CheckBox_Checked
floyd=1
Else
floyd=0
Endif
Case #CheckBox_Flou
statfl=GetGadgetstate(#CheckBox_Flou)
if statfl=#PB_CheckBox_Checked
Flou=1
Else
Flou=0
Endif
Case #TrackBar_tolerance
tolerance=GetGadgetstate(#TrackBar_tolerance)
SetgadgetText (#Text_tol_val,str(tolerance))
Case #Text_tolerance
Case #Text_Titre
Case #Container_8
Case #Button_Run
if Flag_pick>0
SetGadgetState(#Button_pick, 0)
Flag_pick=-Flag_pick
Endif
if isimage(#image)
;-bouton RUN
if Flag_pick_pick=0
ClearList(palette())
ClearList(Des())
CopyArray(TAB_ori(), TAB())
Endif
ClearScreen($0)
FlipBuffers()
;Tolerance
tolerance=GetGadgetstate(#TrackBar_tolerance)
; Flou
statfl=GetGadgetstate(#CheckBox_Flou)
if statfl=#PB_CheckBox_Checked
Flou=1
Else
Flou=0
Endif
;FLoyd
statF=GetGadgetstate(#CheckBox_Floyd)
if statf=#PB_CheckBox_Checked
floyd=1
Else
floyd=0
Endif
; Nbr_couleur
nbr_couleur=val(GetGadgetText(#String_nb_couleur))
; Run
palette=1; pour afficher la palette dans l'image
if Flag_pick_pick=0
make_palette(#image,nbr_couleur,palette)
Endif
dessin(#image,nbr_couleur,tolerance,Floyd,flou ) ;
Else
MessageRequester("info", "Chargez d'abord une image")
ENdif
Case #String_nb_couleur
compteur_coul=0
nbr_couleur=val(GetGadgetText(#String_nb_couleur))
Case #Text_color
Case #Button_Save
if isimage(#image)
SaveImage(#image,"resultat_en_"+str(nbr_couleur)+"_"+str(tolerance)+".bmp",#PB_ImagePlugin_BMP)
MessageRequester("info", "Image sauvé avec le nom :"+chr(10)+"resultat_en_"+str(nbr_couleur)+"_"+str(tolerance)+".bmp")
Else
MessageRequester("info", "Chargez d'abord une image")
Endif
EndSelect
; ////////////////////////
Case #PB_Event_CloseWindow
Select EventWindow()
Case #Win
CloseWindow(#Win)
Break
EndSelect
Case #WM_LBUTTONDOWN
if Flag_pick>0 ; on pick
GetCursorPos_(@cp.POINT)
GetWindowRect_(GadgetID(#Container_8),gr.RECT)
PtInRect_(@gr, cp\x<<32+cp\Y)
MapWindowPoints_(#Null, GadgetID(#Container_8), cp, 1) ; cp now contains gadget coords
if ( cp\x>=0 and cp\x<=ImageWidth(#image)) and (cp\y>=0 and cp\y<=ImageHeight(#image) )
StartDrawing(ScreenOutput()) ;
couleur_pick=point(cp\x,cp\Y)
StopDrawing()
coul.i=couleur_pick
Endif
ForEach palette()
if palette()=coul.i ; c'est une couleurs nouvelle pour la palette ?
flag_ok=1 ; non on l'a deja !
Endif
Next
; *************************************************
if flag_ok=1 ; couleur deja presente dans la palette
flag_ok=0
Else ; couleur nouvelle trouvée
Flag_pick_pick=1
AddElement(palette()) ; on la stock
palette()=coul.i
compteur_coul=compteur_coul+1
nbr_couleur=compteur_coul
SetGadgetText( #String_nb_couleur,str(nbr_couleur))
Endif
SortList(palette(), #PB_Sort_Descending)
StartDrawing(CanvasOutput(#image_palette))
Box(0,0,GadgetWidth(#image_palette),GadgetHeight(#image_palette),$0)
compteur=0:vertical=0
ForEach palette()
pas=8
Box (1+compteur,vertical,pas,pas,palette())
compteur=compteur+pas
if compteur => GadgetWidth(#image_palette)
compteur=0
vertical=vertical+pas
compteur=0
Endif
Next
StopDrawing()
Endif
EndSelect
if IsImage(#image)
StartDrawing(ScreenOutput()) ;
DrawImage(ImageID(#Image), 0, 0)
StopDrawing()
FlipBuffers()
Endif
Forever
;
;}
;-Procedures Zone
;-calcul Distance couleur
Procedure distance_couleur(couleur1,couleur2)
; by Dobro
rf.c=red(couleur1) :vf.c=green(couleur1): bf.c=blue(couleur1)
r.c=red(couleur2) :v.c=green(couleur2): b.c=blue(couleur2)
distance=sqr(pow(rf-r.c,2)+ pow(vf-v.c,2)+pow(bf-b.c,2)) ; calcul de la distance qui sépare la couleur de l'image avec la couleur de la palette
ProcedureReturn distance
Endprocedure
;-make palette
Procedure make_palette(nb_image,nbr_couleur.i,palette)
if nbr_couleur.i=0 : nbr_couleur.i=16:Endif
; By Dobro
largeur_image=ImageWidth(nb_image)
Hauteur_image=ImageHeight(nb_image)
; mise en tableau
StartDrawing(ImageOutput(nb_image))
;mise_en_tab(nb_image,largeur_image,Hauteur_image) ; apres ça l'image 16 millions de couleurs est dans le Tableau Tab()
RandomSeed(13)
; ajout obligatoire du blanc, et du noir !
AddElement(palette()) ; on la stock
palette()=$0
AddElement(palette()) ; on la stock
palette()=rgb(255,255,255)
ccc=0
compteur_coul=0
for i=1 to nbr_couleur.i-2
recommence:
x=random(largeur_image-1,1) ; choisi x couleurs au hazard dans l'image pour fabriquer la palette
y=random(Hauteur_image-1,1)
; ici en principe, on est sur que 2 fois le meme pixel (et donc 2 fois la meme couleur, ne sera pas dans la palette
coul.i=TAB(x,y) ; recupere la couleur dans l'image d'origine (celle des 16 millions de couleurs )
; **** Scan la liste pour chercher des couleurs nouvelles **
If nbr_couleur.i<=800
tol=5
Else
Tol=1
Endif
ForEach palette()
If distance_couleur(palette(),coul.i)<=Tol ; ICI on regarde si on a affaire a une nouvelle couleur ,
; on considere que si la couleur trouvée est supérieur en distance a : 5 , alors c'est une nouvelle couleur , sinon si c'est infereur, on considere qu'on a deja cette couleur dans la palette
;if palette()=coul.i ; c'est une couleurs nouvelle pour la palette ?
flag_ok=1 ; non on l'a deja !
Break
Endif
ccco=ccco+1
if ccco>nbr_couleur.i-2/3
WaitWindowEvent(2)
ccco=0
Endif
Next
; *************************************************
if flag_ok=1 ; couleur deja presente dans la palette
flag_ok=0
Goto recommence
Else ; couleur nouvelle trouvée
AddElement(palette()) ; on la stock
palette()=coul.i
compteur_coul=compteur_coul+1
Endif
Next i
SortList(palette(), #PB_Sort_Descending)
if palette=1 ; Dessine la palette
pos=0:compteur=0:vertical=0
StopDrawing() ; ferme l'ecran pour le moment
StartDrawing(CanvasOutput(#image_palette))
Box(0,0,GadgetWidth(#image_palette),GadgetHeight(#image_palette),$0)
ForEach palette()
if nbr_couleur.i<=512
pas=8
Else
Pas=4
Endif
Box (1+compteur,vertical,pas,pas,palette())
compteur=compteur+pas
if compteur => GadgetWidth(#image_palette)
compteur=0
vertical=vertical+pas
Endif
Next
compteur=0
vertical=0
StopDrawing()
StartDrawing(ImageOutput(nb_image)) ; reouvre l'ecran
Endif
; a ce stade nous devrions avoir le bon nombre de couleurs
; *************************************************
StopDrawing()
taa$= " il y a "+str(compteur_coul+2)+" couleurs dans la palette"
taa1$= "ok la palette est créé j'attaque le dessin ... patience"
SetgadgetText (#Text_info2,taa$+chr(10)+taa1$)
Endprocedure
;- Dessin
Procedure Dessin(nb_image,nbr_couleur,tolerance,Floyd,flou)
DisableDebugger
ClearScreen(0)
FlipBuffers()
largeur_image=ImageWidth(nb_image)
Hauteur_image=ImageHeight(nb_image)
FreeImage(nb_image) ; efface l'image pour etre sur d'avoir une nouvelle base
CreateImage(nb_image, largeur_image,Hauteur_image) ; recreer l'image vierge
taa2$= "debut du dessin"
;SetgadgetText (#Text_info2,taa$+ " "+taa1$+ " "+taa2$)
StartDrawing(ImageOutput(nb_image))
For y=0 to Hauteur_image-1
For x=0 to largeur_image-1
coul.i=TAB(x,y)
mem_distance=RGB(255,255,255)
coull=$0
; rf.c=red(coul.i)
; vf.c=green(coul.i)
; bf.c=blue(coul.i)
;if nbr_couleur>8
ForEach palette() ; Pour chaque couleur de la palette
;r.c=red(palette()) :v.c=green(palette()):b.c=blue(palette())
distance=distance_couleur(coul.i,palette()) ; on regarde la distance qui separe la couleur d'origine de l'image avec la couleur en cours de la palette
If distance<=mem_distance ; si la distance trouvé est plus petite ou egale a la distance mise en memoire
mem_distance=distance ; on prends cette couleur qui se rapproche de l'originale
coull=palette()
Endif ; a la fin , en principe on a la couleur de la palette qui se raproche le plus de la couleur du point original de l'image
; Accelerateur si tolerance est grande ... mais image moins fidele
If distance <=tolerance ; si la distance mesuré est inferieur au curseur de tolerance, on arrete la et on garde la derniere couleur de la palette trouvée
Break
Endif
Next
plot(x,y,coull) ; dessine avec la couleur de la palette en cours , en principe la couleur la plus proche du point d'origine
mem_couleur=palette()
compteur_activity=compteur_activity+1
ccco=ccco+1
if ccco=4000
WaitWindowEvent(2)
ccco=0
Endif
Next x
taa$=str(compteur_activity/100)+"/"+str(largeur_image * Hauteur_image/100) ; affiche l'activité
SetgadgetText (#Text_info,taa$)
Next y
taa$= "Fin dessin"
SetgadgetText (#Text_info,taa$)
SetgadgetText (#Text_info2,"")
if Floyd=1 ; dessine le Floyd
StopDrawing()
mise_en_tab(nb_image,largeur_image,Hauteur_image)
DoOmohundro(nb_image)
Endif
If Flou=1 ; ajoute du Flou
StopDrawing()
mise_en_tab(nb_image,largeur_image,Hauteur_image)
Niveau=1
Flou(nb_image,largeur_image,Hauteur_image, Niveau)
Endif
StopDrawing()
EnableDebugger
EndProcedure
;
Procedure mise_en_tab_ori(nb_image,Largeur_image,Hauteur_image)
; By Dobro
; mise en tableau du resultat de la reduction
;;StartDrawing(ImageOutput(nb_image))
For y=0 to Hauteur_image-1
For x=0 to largeur_image-1
TAB_ori(x,y)=point(x,y)
Next x
Next y
;;StopDrawing()
EndProcedure
Procedure mise_en_tab(nb_image,Largeur_image,Hauteur_image)
; By Dobro
; mise en tableau du resultat de la reduction
StartDrawing(ImageOutput(nb_image))
For y=0 to Hauteur_image-1
For x=0 to largeur_image-1
TAB(x,y)=point(x,y)
Next x
Next y
StopDrawing()
EndProcedure
Procedure Flou(nb_image,ImageX,ImageY, Niveau)
; Le Soldat inconnu
StartDrawing ( ImageOutput (nb_image)) ; on dessine sur l'image
x = 0 ; on se place en x=0 sur l'image
Repeat
y = 0 ; on se place en y=0 sur l'image
Repeat
; on récupère la couleur du point en x et y et alentour
Rouge = 0
Vert = 0
Bleu = 0
NbPixel = 0
For Px = -Niveau To Niveau
For Py = -Niveau To Niveau
If Px + x >= 0 And Px + x < ImageX
If Py + y >= 0 And Py + y < ImageY
; on fait le mélange des couleurs entre le point en x,y et ceux qui sont à sont alentour
Couleur = TAB(Px + x, Py + y)
Rouge = Rouge + Red (Couleur)
Vert = Vert + Green (Couleur)
Bleu = Bleu + Blue (Couleur)
NbPixel + 1
EndIf
EndIf
Next
Next
; On recalcule la nouvelle couleur
Couleur = RGB (Rouge / NbPixel, Vert / NbPixel, Bleu / NbPixel)
; si la taille du nouveau pixel est positive
Plot (x, y, Couleur) ; on dessine un carré qui fait le nouveau pixel de la même couleur que celle récupéré en x et y
; on se déplace sur l'image en y de la taille d'un pixel
y = y + 1
Until y >= ImageY ; si on a finit la colonne de l'image placé en x
; on se déplace sur l'image en x de la taille d'un pixel
x = x + 1
; on fait progresser la barre
;;;SetGadgetState ( #Barre , x)
Until x >= ImageX ; si on a traité toutes les lignes de l'image
StopDrawing ()
EndProcedure
Procedure DoOmohundro(hImg) ; Floyd
Protected nextpixel.f, ierror.f, fer.f, eer.f, teer.f, lr.f
StartDrawing(ImageOutput(hImg))
width = ImageWidth(hImg): height = ImageHeight(hImg)
Protected error.f ;hold error for current pixel
Dim error_arr.f(width)
For y = 2 To height-3
lr = 0
For x = 2 To width-3
val = TruncF0255(RGBtoLum(Point(x,y)) + error_arr(x))
If val > 128
Plot(x,y,TAB(x,y))
error = val-255
Else
r=red(TAB(x,y))/1.5
v=green(TAB(x,y))/1.5
b=blue(TAB(x,y))/1.5
Plot(x,y,rgb(r,v,b))
error = val
EndIf
fer.f = error/4 ;a fourth of the error
eer.f = fer/2 ;an eighth
teer.f = fer + eer ;three eights
error_arr(x-1) + eer
error_arr(x) = teer + lr
lr = eer
error_arr(x+1) + teer
Next x
Next y
StopDrawing()
EndProcedure
Procedure.i TruncF0255 (a.f)
If a > 255: a = 255: ElseIf a < 0: a = 0: EndIf
ProcedureReturn a
EndProcedure
Procedure RGBtoLum(c.l) ;Get luminosity (the min and max RGB levels / 2)
r = (c & $FF) : g = ((c & $FF00) >> 8) : b = ((c & $FF0000) >> 16)
If g < r: min = g: Else: min = r: EndIf
If b < min: min = b: EndIf
If g > r: max = g: Else: max = r: EndIf
If b > max: max = b: EndIf
If b > max: max = b: EndIf
lum = (max + min) >> 1 ;/ 2.0
ProcedureReturn lum
EndProcedure
; Epb