Разработка и ромхакинг > Ромхакинг
Софт для ромхакинга
<< < (2/3) > >>
Guyver(X.B.M.):
SeregaZ, у тебя изначально картинка кривая. Попробуй свой аватар этой прогой пропустить - и увидишь 15 цветов.
Sharpnull:
SeregaZ, я когда пытался конвертировать картинки в PNG для SGDK, понял что ImaGenesis - дикий мусор (сами видите), XnView и PIL (библиотека для Python) - дают не очень хороший результат, ImageMagick - кажется тоже не устроило, но я до конца не разобрался в настройках, Photoshop - хороший результат, узнать бы алгоритм, чтобы автоматически несколько картинок конвертировать.

Кстати, почему-то не нашёл программы для перестановки цветов в палитре в PNG, то есть чтобы менялся порядок, но цвета на изображении оставались на своём месте. В Photoshop'е с перестановкой цветов в палитре всё плохо, вручную если только. Смотрел в программах для пиксель арта, ничего такого нет, либо плохо смотрел.
Возможно гуру графики делают это как-то по-другому или потому что это самому пишется легко (в том же PIL). Вообще для Genesis есть настолько мощная графическая программа, что я с ходу не вкурил и забил.
--------
Забыл сказать, что хотя у Photoshop хороший результат, при импорте всё равно будет уменьшение диапазона цветов и некоторые могут совпадать, поэтому в идеале нужно самому выстраивать доступную палитру и перерисовывать.
SeregaZ:
Guyver(X.B.M.), да, с аватарой вышло лучше. порассматривал результаты: эта программа делает чуть светлее, моя соответственно темнее. плюс еще у себя в настройках функции нашел параметр Dither что-то такое. какая-то зернистость с ним добавляется. отключил во всех импортах изображений, кажется стало более плавнее.

Sharpnull, по моему у меня проблем, с изменением нумерации цветов возникнуть недолжно. другое дело, что у меня не графический редактор, а редактор для Дюны с элементами графического редактора... и изображение надо будет перевставить. то есть первая вставка создаст палитру этого изображения. потом меняем нужные цвета... эм... видимо вручную придется, перебивая значения RGB (точнее BGR), и после вставляя изображения со "вписыванием" в существующую палитру. то есть у меня два варианта импорта - со своей палитрой, и со "вписыванием" в существующую. тогда порядок в палитре будет изменен, изображение же сохранится. только номера цветов изменятся в самом изображении.

Добавлено позже:
и тем не менее вопрос с импортом своей палитры, с условием что два цвета из палитры должны быть не изменяемые - так и висит :) без него не получится правильно сделать импорт изображений для регионов. только если сохранять старую палитру и при вставке "вписывать" новое изображение в эту палитру.
Sharpnull:
SeregaZ, вот кстати, Photoshop справа (адаптивные 16 цветов, маджента сама встала первой) и слева как импорт сделал SGDK. Почти как ваш вариант, может деталей чуть больше.

--------
Обновил картинку, добавил оригинал справа для сравнения.
--------

--- Цитата: SeregaZ от 04 Сентябрь 2018, 20:24:57 ---нашел параметр Dither что-то такое. какая-то зернистость с ним добавляется.
--- Конец цитаты ---
У вас как раз было с Dither, картинка получается с ним более реалистичная, а без него получается обычная убогая постеризация:
Sharpnull:

--- Цитата: SeregaZ от 04 Сентябрь 2018, 16:43:04 ---есть чтоб на выходе было два постоянных цвета и только 7 те цвета,
--- Конец цитаты ---
В Photoshop и некоторых других программах можно выбрать произвольное количество цветов, вот результат с 7 цветами:

Также Photoshop адаптирует цвета картинки при вставке к палитре, если вставляете в индексируемую картинку (Image -> Mode -> Indexed Color), но можно просто экспортировть (File -> Export -> Save for Web) с 9 цветами (+1 для прозрачности, полагаю) и прям там изменить близкие цвета на те 2.
Или проблема в импорте именно в вашем редакторе Dune?
SeregaZ:
так ежели ужимать до 7 цветов - тот-же самый черный может потеряться, и стать скажем серым цветом. поэтому и хотелось бы подобрать какую-то dll или на худой конец консольную программу, которая могла бы подобное делать. типа назначаешь выходную палитру: 0 цвет фиолетовый, 8 цвет черный. с 1 по 7 программа может как угодно изменять. в моем же случае программа либо как хочет может изменять все цвета, либо ежели я резервирую тот нулевой цвет как фиолетовый - то программа по пастеризации его тупо не использует, создавая второй фиолетовый, по сути выкидывая один цвет. вот надо чтоб программа могла использовать уже заранее подготовленные 2 цвета, которые нельзя изменять, но можно использовать для выходной палитры и потом еще дописывать оставшиеся "динамические" цвета в эти слоты с 1 по 7. несколько сумбурно написал :) но это было бы наиболее верный подход к импорту изображения.

можно, конечно, выкрутится вручную подкрашивая элементы на изображении в существующие цвета. например трамп. фиолетовый фон будет прозрачным, но ведь надо его как-то обозначить. и это убьет один из цветов, если я буду импортировать в своем редакторе. получится трамп конвертится в 14, а не в 15 цветов. что можно сделать - взять этого самого трампа, пипеткой взять цвет из галстука - красный. и залить фиолетовый фон красным. после в редакторе залить этот красный на фоне фиолетовым-прозрачным. в итоге потерянный цвет спасен :) (картинки с отключенным Dither - выше он был включен, что придавало зернистости изображению.)



но это лишние телодвижения мышкой. хотелось бы чтоб программа сама это все делала. но код там замудреный, я смотрю и вижу фигу. что там происходит без малейшего понятия :) уж тем более теорию цветности я не знаю.

в принципе с черным можно сделать точно так-же, но опять таки это ручная работа, что убивает весь мой замысел. хочется однокликовости.
Ogr:

--- Цитата: SeregaZ от 04 Сентябрь 2018, 22:01:26 ---хочется однокликовости.
--- Конец цитаты ---
угу. а еще чтобы кто то твою задумку за тебя тебе реализовал. :lol:
SeregaZ:
ну... я не столько программист, сколько менеджер, собирающий в кучу то, что по плану должно быть в этом приложении :) и конца и края пока еще не видно. еще вагон и маленькую тележку ваять...
Guyver(X.B.M.):
Ну дык как кто-то должен понять, как работает конвертация в твоём редакторе? Хоть бы участки кода выложил, может, кто-то тебе и помог бы... :neznayu: Или ты там ничего не конвертируешь, а берёшь уже готовую картинку с нужным количеством цветов?
SeregaZ:
я беру готовый код, как бы модуль, запиленный юзерами с буржуйского форума для своего горе-языка. и с помощью него импортирую изображение в свой редактор.

сам код выкладывать как бы толку мало, ведь он не на популярных языках запилен :) и пока спал - думал. там среди функций есть некая POPULARITY_PALETTE, то есть согласно моему диванно-икспердному мнению там происходит подсчет количества пикселов одного цвета, и тем самым выставляется некий рейтинг цветов чтоль. какого цвета больше - того и тапки. тогда, опять таки согласно моей диванно-икспердной теории, если я заранее, каким-то образом, втолкаю в итоговый результат работы этой функции фиолетовый и черный с очень большим значением этого самого рейтинга, то эти цвета всегда будут на выходе, а сама функция будет подтягивать ближайшие цвета к этим двум, без их изменения.


--- Код: ---CompilerIf #PB_Compiler_IsMainFile
 
  Enumeration
    #Pal512
  EndEnumeration
 
UsePNGImageDecoder()
UseOGGSoundDecoder()

;{ глобальная палитра
Global Dim FullPalette.l(513)
Dim col.a(8)
col(1) = 0
col(2) = 36
col(3) = 72
col(4) = 109
col(5) = 145
col(6) = 181
col(7) = 219
col(8) = 255
x = 0
y = 0
If CreateImage(#Pal512, 256, 32)
  If StartDrawing(ImageOutput(#Pal512))
    For i = 1 To 8
      For l = 1 To 8
        For k = 1 To 8
          Box(x,y,4,4, RGB(col(k),col(l),col(i)))
          num + 1
          FullPalette(num) = RGB(col(k),col(l),col(i))         
          x + 4
        Next
        x - 32
        y + 4
      Next
      x + 32
      y - 32
    Next     
    StopDrawing()
  EndIf
EndIf ;}

; NearestColor module by Wilbert

; Latest updated : Jan 27, 2016

; Color distance formula based on:
; http://www.compuphase.com/cmetric.htm

; Dithering method:
; Sierra Lite

DeclareModule NearestColor
 
  Prototype ProtoProgressCallback(PercentProgress.i)
 
  Declare   CatchPalette(*MemoryAddress.Long, NumColors.i)
  Declare   CopyPalette(Array DestinationArray.l(1))
  Declare.i DitheredImage(Image.i, DitherLevel.a = 220, Brightness.b = 0, Contrast.b = 0, ProgressCallback.ProtoProgressCallback = 0)
  Declare.l FindNearest(Color.l)
  Declare.i PaletteColorCount()
  Declare   SetPalette(PaletteImage.i)
 
EndDeclareModule

Module NearestColor
 
  EnableASM
  ;EnableExplicit
  ;DisableDebugger
 
  Structure ColorScan
    l.l[524288]
  EndStructure
 
  Global ColorScan.ColorScan
  Global Dim IndexG.l(255)
  Global Dim Palette.l(1)
 
  CompilerIf #PB_Compiler_Processor = #PB_Processor_x86
    Macro rdx : edx : EndMacro
  CompilerEndIf
 
  Procedure.i PaletteColorCount()
    ; Return amount of colors the palette contains
    ProcedureReturn ArraySize(Palette()) - 1
  EndProcedure
 
  Procedure CopyPalette(Array DestinationArray.l(1))
    ; Copy the current palette into a supplied array
    Protected.i cnt = ArraySize(Palette()) - 1
    ReDim DestinationArray(cnt - 1)
    CopyMemory(@Palette(1), @DestinationArray(0), cnt << 2)
  EndProcedure
 
  Procedure CatchPalette(*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 SetPalette(PaletteImage.i)
    ; Set a palette from an image
    Protected.i i, j, b, x, y, cnt
    Protected.l c, c_
    If StartDrawing(ImageOutput(PaletteImage))
      FillMemory(@ColorScan, SizeOf(ColorScan))
      j = OutputHeight() - 1
      i = OutputWidth() - 1
      ; count all used colors
      For y = 0 To j
        For x = 0 To i
          c = Point(x, y)
          !mov eax, [p.v_c]
          !rol ax, 8
          !bswap eax
          !shr eax, 8
          lea rdx, [nearestcolor.v_ColorScan]
          bts [rdx], eax
          !jc nearestcolor.setpalette_cont0
          inc cnt
          !nearestcolor.setpalette_cont0:
        Next
      Next
      StopDrawing()
      ; redim palette with room at top and bottom for zero entry
      ReDim Palette(cnt + 1)
      Palette(0) = 0 : Palette(cnt + 1) = 0
      ; set palette sorted on G, R, B and index on G
      i = 0 : j = 1
      For y = 0 To 255
        IndexG(y) = j
        For x = 0 To 2047
          b = 0 : c_ = ColorScan\l[i]
          While c_
            shr c_, 1
            !jnc nearestcolor.setpalette_cont1         
            !mov eax, [p.v_i]
            !shl eax, 5
            !or eax, [p.v_b]
            !shl eax, 8
            !or eax, 0xff
            !bswap eax
            !rol ax, 8
            !mov [p.v_c], eax
            Palette(j) = c : j + 1
            !nearestcolor.setpalette_cont1:         
            b + 1
          Wend
          i + 1 
        Next
        IndexG(y) = (IndexG(y) + j) >> 1   
      Next
    EndIf 
  EndProcedure
 
  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
 
  Procedure.l FindNearest(Color.l)
    ; Find the nearest color
    Protected.l c, c0, c1, d, bestd = $12000000
    Protected.Long *p0, *p1
    !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)
    ProcedureReturn c
  EndProcedure
 
  Macro M_DitherImage(offset, n = 1)
    !movsx ecx, byte [p.v_err + offset]
    !movsx eax, byte [p.v_err50 + offset]
    !add ecx, eax
    !imul ecx, edx
    !sar ecx, 8
    !movzx eax, byte [p.v_c0 + offset]
    !add eax, [p.v_badd]
    !imul eax, [p.v_cmul]
    !sar eax, 8
    !lea eax, [eax + ecx + 128]
    !neg ah
    !setz cl
    !neg cl
    !and al, cl
    !sar ah, 7
    !or al, ah
    !mov [p.v_c0 + offset], al
  EndMacro
 
  Procedure.i DitheredImage(Image.i, DitherLevel.a = 220, Brightness.b = 0, Contrast.b = 0, ProgressCallback.ProtoProgressCallback = 0)
    ; Return a dithered image
    ; DitherLevel : 0 - 255
    ; Brightness : -128 - 127
    ; Contrast : -128 - 127
    Protected.i result, x, y, w, h
    Protected.l c0, c1, badd, cmul, err50, err
    If ProgressCallback : ProgressCallback(0) : EndIf
    result = CopyImage(Image, #PB_Any)
    If result And StartDrawing(ImageOutput(result))
      h = OutputHeight()
      w = OutputWidth()
      If DitherLevel = 0 And Brightness = 0 And Contrast = 0
        While y < h
          x = 0
          While x < w
            Plot(x, y, FindNearest(Point(x, y)))
            x + 1
          Wend
          y + 1
          If ProgressCallback
            ProgressCallback(100 * y / h)
          EndIf
        Wend
      Else
        badd = Brightness - 128
        cmul = (33280 * Contrast + 4259840) / (16640 - Contrast << 7)
        Dim d_error.l(w)
        While y < h
          x = 0 : err50 = 0
          While x < w
            c0 = Point(x, y)
            ; add previous error
            err = d_error(x)
            !movzx edx, byte [p.v_DitherLevel]
            M_DitherImage(0)
            M_DitherImage(1)
            M_DitherImage(2)
            c1 = FindNearest(c0)
            Plot(x, y, c1)
            ; calculate 50% error
            !mov eax, [p.v_c0]
            !mov ecx, [p.v_c1]
            !mov edx, eax
            !not edx
            !and edx, ecx
            !and edx, 0x01010101
            !or eax, 0x01010101
            !and ecx, 0xfefefefe
            !sub eax, ecx
            !xor eax, 0x01010101
            !shr eax, 1
            !sub eax, edx
            !mov ecx, [p.v_err50]
            !mov [p.v_err50], eax
            ; mix with previous error
            !xor eax, 0x80808080
            !xor ecx, 0x80808080
            !mov edx, eax
            !and edx, ecx
            !and edx, 0x01010101
            !and eax, 0xfefefefe
            !and ecx, 0xfefefefe
            !add eax, ecx
            !shr eax, 1
            !add eax, edx
            !xor eax, 0x80808080
            !mov [p.v_err], eax
            d_error(x) = err
            x + 1
          Wend
          d_error(0) << 1
          y + 1
          If ProgressCallback
            ProgressCallback(100 * y / h)
          EndIf
        Wend
      EndIf
      StopDrawing()
    EndIf
    ProcedureReturn result
  EndProcedure
 
  DisableASM
 
  DataSection
    CGAPalette:
    Data.l $000000, $AA0000, $00AA00, $AAAA00, $0000AA, $AA00AA, $0055AA, $AAAAAA
    Data.l $555555, $FF5555, $55FF55, $FFFF55, $5555FF, $FF55FF, $55FFFF, $FFFFFF
  EndDataSection
 
  ; Set default palette
  CatchPalette(?CGAPalette, 16)
 
EndModule

CompilerEndIf

Structure PopType ; used in POPULARITY_PALETTE() procedure
   clr.l ; color
   pop.i ; popularity
EndStructure
 
Global Dim WK_Pal.l(0) ; <--- this array will contain the final palette

Procedure SCAN_FOR_PALETTE(image.i)
   ; obtain the palette of all colors used in an image
   ; stops if number of colors exceeds 512
   Static NewMap Pmap.i(1024)
   Static Dim Palette.l(0)
   Protected c,i,x,y,Xmax,Ymax
   
   Xmax = ImageWidth(image)-1
   Ymax = ImageHeight(image)-1
   
   StartDrawing(ImageOutput(image))
      For y = 0 To Ymax
         For x = 0 To Xmax
            c = Point(x,y)
               If MapSize(Pmap()) > 512
                  Break 2
               EndIf
            Pmap(Str(c)) = c
         Next
      Next
   StopDrawing()

   ReDim palette(MapSize(Pmap())-1)
   
   i = 0
   ForEach Pmap()
      palette(i) = Pmap()
      i + 1
   Next
   
   ClearMap(Pmap())
   
   ;Debug ArraySize(WK_Pal())
   ;For i = 0 To ArraySize(palette());ArraySize(WK_Pal())
   ;  Debug Str(palette(i)); + " " + Str(WK_Pal(i))
   ;Next
   
   ;SHOW_PALETTE(Palette())
EndProcedure

Procedure ASSEMBLE_TO_PALETTE(Array palette.l(1), ImgRef.i, dither.i)
   ; assign each pixel of an image to the defined palette using NearestColor module
   ; ImgRef  = the source image
   ; dither: 0 = no dither, 1 = dither
   ; A new image is created, the return value is the new image number.
   
   NearestColor::CatchPalette(@palette(), ArraySize(palette())+1)
   
   ProcedureReturn NearestColor::DitheredImage(ImgRef, dither*128)
   
EndProcedure

Procedure COUNT_COLORS(image.i)
   ; returns the number of unique colors in an image (24 bit)
   Protected.i x, y, max_x, max_y, c, count, m
   Dim m.a($1FFFFF)
   StartDrawing(ImageOutput(image))
      max_x = ImageWidth(image) - 1
      max_y = ImageHeight(image) - 1
      For y = 0 To max_y
         For x = 0 To max_x
            c = Point(x, y) & $FFFFFF
            If m(c >> 3) & 1 << (c & 7) = 0
               m(c >> 3) | 1 << (c & 7)
               count + 1
            EndIf
         Next
      Next
   StopDrawing()
   ProcedureReturn count
EndProcedure

Procedure POPULARITY_PALETTE(ImgRef.i,limit.i)
   ; Create a color palette with a modified popularity approach.
   ; ImgRef = the source image.
   ; Limit = the maximum number of colors in result.
   ; Limit count can be specified from 2 to 512. (512 is arbitrary limit)
   ; Required support procedures are:
   ;   'COUNT_COLORS', and 'ASSEMBLE_TO_PALETTE'.
   ; Finished palette is placed in the global array WK_Pal().
   ; This algorithm was created by BasicallyPure.
   
   Static.i kb = $FF0000, kg = $00FF00, kr = $0000FF
   Protected.i ImgWork, count, Xmin,Ymin,Xmax, Ymax, i, x, y, lum, d, br, da, mb, md
     
   If IsImage(ImgRef)
      ImgWork = CopyImage(ImgRef,#PB_Any)
     
      If ImgWork
         count = COUNT_COLORS(ImgWork)
         If count <= limit : limit = count : EndIf
      Else
         ProcedureReturn 0
      EndIf
   Else
      ProcedureReturn 0
   EndIf
   
   Xmax = ImageWidth(ImgWork) - 1
   Ymax = ImageHeight(ImgWork) - 1
   
   ; 1) if color count is > 512 color count will be reduced.
   ;    and palette colors may be altered.
   If count > 512
      ; simple bitmask color reduction method
      StartDrawing(ImageOutput(ImgWork))
         For y = Ymin To yMax
            For x = Xmin To xMax
               Plot(x, y, Point(x,y) & $E0E0E0 | $0F0F0F)
            Next x
         Next y
      StopDrawing()
   EndIf
         
   ; 2) gather popularity data
      NewMap Pmap.i()
      StartDrawing(ImageOutput(ImgWork))
         For y = Ymin To Ymax
            For x = Xmin To Xmax
               Pmap(Str(Point(x,y))) + 1
            Next
         Next
      StopDrawing()
     
      If MapSize(Pmap()) < limit : limit = MapSize(Pmap()) : EndIf
     
   ; 3) subdivide colors into 4 brightness lists
      NewList bright.PopType()
      NewList MedBri.PopType()
      NewList MedDrk.PopType()
      NewList dark.PopType()
     
      ForEach Pmap()
         d = Val(MapKey(Pmap()))
         lum = (d & kr)<<1 + (d & kg) >> 6 + (d & kb) >> 16
         If lum > 1338
            AddElement(bright()) : bright()\clr = d : bright()\pop = Pmap()
         ElseIf lum > 892
            AddElement(MedBri()) : MedBri()\clr = d : MedBri()\pop = Pmap()
         ElseIf lum > 446
            AddElement(MedDrk()) : MedDrk()\clr = d : MedDrk()\pop = Pmap()
         Else
            AddElement(dark())   : dark()\clr   = d : dark()\pop   = Pmap()
         EndIf
      Next
     
   ; 4) sort each brightness lists by popularity
      SortStructuredList(bright(),#PB_Sort_Descending,OffsetOf(PopType\pop),#PB_Integer)
      SortStructuredList(MedBri(),#PB_Sort_Descending,OffsetOf(PopType\pop),#PB_Integer)
      SortStructuredList(MedDrk(),#PB_Sort_Descending,OffsetOf(PopType\pop),#PB_Integer)
      SortStructuredList(dark()  ,#PB_Sort_Descending,OffsetOf(PopType\pop),#PB_Integer)
     
   ; 5) create the final palette
      FirstElement(bright()) : br = ListSize(bright())
      FirstElement(MedBri()) : mb = ListSize(MedBri())
      FirstElement(MedDrk()) : md = ListSize(MedDrk())
      FirstElement(dark())   : da = ListSize(dark())
     
      limit - 1
      ReDim WK_Pal(limit)
     
      i = 0 : d = %00
      Repeat ; pick from each list in turn the most popular color
         If d = %00 And br > 0
            WK_Pal(i) = bright()\clr
            NextElement(bright())
            i + 1 : br - 1
         ElseIf d = %01 And da > 0
            WK_Pal(i) = dark()\clr
            NextElement(dark())
            i + 1 : da - 1
         ElseIf d = %10 And mb > 0
            WK_Pal(i) = MedBri()\clr
            NextElement(MedBri())
            i + 1 : mb - 1
         ElseIf d = %11 And md > 0
            WK_Pal(i) = MedDrk()\clr
            NextElement(MedDrk())
            i + 1 : md - 1
         EndIf
           
         d = (d + %01) & %11
      Until i > limit
     
      If IsImage(ImgWork)
        ;CopyImage(ImgWork, ImgRef)
        FreeImage(ImgWork)
      EndIf
     
      ProcedureReturn 1
EndProcedure

Procedure.a ImportImageWithPallete(ImgRef.l, limit, dither.i)
 
  ret.a = 0
 
  ; repaint into 512 allow colors
  NearestColor::CatchPalette(@FullPalette(), 513)
  CBWidth  = ImageWidth(ImgRef)
  CBHeight = ImageHeight(ImgRef)
  x = 0
  y = 0
  If StartDrawing(ImageOutput(ImgRef)) 
    While y < CBHeight
      x = 0
      While x < CBWidth
        Plot(x, y, NearestColor::FindNearest(Point(x, y)))
        x + 1
      Wend
      y + 1
    Wend                 
    StopDrawing()
   
    If POPULARITY_PALETTE(ImgRef, limit) ;generate the palette
      Qimage = ASSEMBLE_TO_PALETTE(WK_Pal(), ImgRef, dither) ;build the final image
      If IsImage(Qimage)
        ;ImageGadget(#PB_Any,0,0,w,h,ImageID(Qimage)) ;display the result
        SCAN_FOR_PALETTE(Qimage) ; show the palette in a separate window
        If IsImage(ImgRef)
          FreeImage(ImgRef)
        EndIf
        CopyImage(Qimage, ImgRef)
        FreeImage(Qimage)
        ret = 1
      EndIf
    EndIf
   
  EndIf
 
  ProcedureReturn ret
 
EndProcedure

CompilerIf #PB_Compiler_IsMainFile
 
GetClipboardImage(ImgRef, 32)
ImportImageWithPallete(ImgRef, 14, #True)

SaveImage(ImgRef, "D:\test.png")

;For i = 0 To ArraySize(WK_Pal())
;  Debug WK_Pal(i)
;Next

CompilerEndIf


--- Конец кода ---
Guyver(X.B.M.):
Да, код просто монстрический. Я попробовал ради прикола один из алгоритмов реализовать, но у меня картинка сильно тёмная получается. И даже если осветлить её - цвета на оригинальные не всегда похожи... Хотя сам алгоритм похож на твой, с выборкой...





П.С. Опять нас ждёт хак "Трамп против @#тина"?
SeregaZ:
не :) просто более менее фотография Трампа попалась с нужным освещением, чтоб похожа, как освещение ментатов в дюне. а так у него глаза плохие - щелочки. анимацию рисовать для моргания глаз будет не удобно. оригинальные ментаты то с большими глазами, видно как зрачок влево-вправо двигается. а тут-же ничерта невидать :)

сам код из трех частей - моя криворукая часть, в том месте где я создаю палитру, как на приставке из 512 цветов.

после там код с асм вставками - это другого товарища, который растаскивает цвета на изображении к ближайшим разрешенным из 512.

третья часть уже сам код пастеризации второго товарища, с уменьшением количества цветов. вот видимо монструазность в виду подключения этого некоего фильтра или как он по научному - Dither. я думаю что с включенным этим Dither как-то квадратично. без него более плавно, а Sharpnull наоборот пишет что с Dither лучше.

по поводу яркости что-то я не знаю а будут ли соответствовать цвета, после такого изменения яркости тем, что разрешены? в смысле сеговские 512?
Guyver(X.B.M.):
Будут соответствовать, если изменение яркости происходит в пределах этих цветов разрешённых. У тебя в результате палитра получается отдельным файлом? В бмп 16 цветов же не включается палитра, да?

Имхо, Dither - это вообще шляпа. Никогда не использую в своих работах и стараюсь избавляться от этого шакального эффекта в изображениях...
SeregaZ:
палитру выковыривает из bmp изображения. а дальше можно поступить как угодно. в данном коде не сохраняет. там для себя выводил лист получившейся палитры:

--- Код: ---;For i = 0 To ArraySize(WK_Pal())
;  Debug WK_Pal(i)
;Next
--- Конец кода ---

сохранение у меня в других местах :) не в этом коде. там где сохраняются регионы, где ментаты, где экраны и где большие иконки. там цвет надо перевернуть, так сказать, и потом сохранять. для переворачивания сделал что-то типа такого:

--- Код: ---Procedure.a Parse1Color(inp.a, pbtosmd.a=0)
 
  out.a
 
  If pbtosmd = 0
    Select inp
      Case 0
        out = 0
      Case 2
        out = 36
      Case 4
        out = 72
      Case 6
        out = 109
      Case 8
        out = 145
      Case $A
        out = 181
      Case $C
        out = 219
      Case $E
        out = 255
    EndSelect
  Else
    Select inp
      Case 0
        out = 0
      Case 36
        out = 2
      Case 72
        out = 4
      Case 109
        out = 6
      Case 145
        out = 8
      Case 181
        out = $A
      Case 219
        out = $C
      Case 255
        out = $E
    EndSelect
  EndIf
 
  ProcedureReturn out
 
EndProcedure

Procedure.l Parse3Color(inp.u)
 
  out.l
 
  r = GetBits(inp, 0, 3)  ;: Debug Hex(b)
  g = GetBits(inp, 4, 7)  ;: Debug Hex(g)
  b = GetBits(inp, 8, 11) ;: Debug Hex(r)
 
  out = RGB(Parse1Color(r), Parse1Color(g), Parse1Color(b))
 
  ProcedureReturn out
 
EndProcedure

--- Конец кода ---

хотя это чтение. ну сохранение примерно так-же, то есть полученный RGB конвертируется в значение, как оно в файлах палитры идет двухбайтовое... эээ... BGR? хотя насчет таблицы значений я в последнее время не уверен. цвета то похожи, но где-то в соседней теме видел чуть чуть другие значения, то есть числа рядышком, но все-таки другие. ну мне колхознику пойдет :)

Добавлено позже:
и у меня вроде что-то получается :) насильно засунул фиолетовый в просчитываемые цвета и в результате он всегда есть в выходной палитре, независимо от того, есть ли он на изображении или нет. теперь надо сделать вилку, даже тройник. три варианта развития событий - как есть, учитывать фиолетовый есть или нету на изображении, учитывать черный есть или нету на изображении. и то, причем не фиолетовый, а любой какой укажешь. доволен как слон :) НО! спасти красный цвет так и не получилось. слишком мало места красным цветом на Трампе покрашено и в результате у красного маленький рейтинг. не смотря что он ярче, так сказать, в палитру в итоге вошел более блеклый какой-то цвет, просто у него был лучше рейтинг.
Sharpnull:

--- Цитата: Guyver(X.B.M.) от 05 Сентябрь 2018, 14:46:00 ---Имхо, Dither - это вообще шляпа. Никогда не использую в своих работах и стараюсь избавляться от этого шакального эффекта в изображениях...
--- Конец цитаты ---
Не знал, что такие люди бывают. Как же вы играете в игры для ретроконсолей, там же повсеместно используется Dither, невозможно ограничить цвета и чтобы выглядело хорошо без этого (для объёмных изображений, пихать везде очевидно нет смысла).


SeregaZ, я бы на вашем месте не возился из-за одного цвета, а почему с маджентой проблемы не понял, в хорошем алгоритме можно задать что считать прозрачностью и он не должен считать его цветом, а просто отметить отдельным индексом. Если вы управляете "популярностью", то можно занижать мадженту (цвет прозрачности) до минимуму, чтобы никогда не попадал в палитру (так в конвертерах и происходит), и после обработки тупо в те пиксели вставить индекс прозрачного цвета. (UPD: Глупость сморозил, можно же просто игнорить пиксели с прозрачностью.) Хотя наверно я неправильно понял и вам именно маджента и нужна в итоге...

Галстук никогда не будет таким, какой вы хотите. Выход из конвертера нельзя назвать пиксель артом, потому что пиксель арт - это когда художник ставит в определённое место определённый цвет. Я к тому, что красиво автоматом не получится.
--------
И опять же  пастеризуют молоко, а картинки постеризуют.
SeregaZ:
ну вот... неожиданно развязал холивар :)

этот код не различает прозрачный или нет. ему подавай количество выходных цветов и все на этом. поэтому я и делал не в 16, а в 15 цветов постеризацию (гугель хрому не нравится через о), всегда резервируя 0 цвет как фиолетовый. однако если в изображении был фиолетовый - в итоговой палитре оказывалось два фиолетовых. то есть 1 цвет терялся. теперь же, добавив обязательное наличие в выходной палитре фиолетового, я могу делать в 16 цветов. просто в конце нужна будет сортировка палитры, чтоб сдвигать фиолетовый (либо какой другой цвет) на 0 номер. этот же трюк буду проворачивать и с регионами - добавляя обязательно черный, независимо от его наличия на изображении. он должен быть под 15 номером. 0 фиолетовый, 1-7 постеризация может изменять, 8-14 опять фиолетовый, а вобще пустые не используемые и 15 черный.
SeregaZ:
добавил в опциях галку для этого самого Dither и во всех четырех местах, где у меня импорт добавил эту переменную.

--- Код: ---CheckBoxGadget(#OptionsDither, x, y, 915, 20, "Use Dither for import images | Использовать Dither для импорта изображений")
--- Конец кода ---

ну и... пофиксил глаза для Трампа :)))))

morskoyzmey:
Не знаю, актуален ли заголовок топика, но внесу свои 5 копеек.

HxD

Удобный хекс редактор. Есть кодировки, сравнение файлов, чек сумма, настраиваемая тема.
Русский язык можно найти в гугле.
https://mh-nexus.de/en/hxd/

famiROM

Удобный сплиттер ROM файлов (NES-> PRG BIN, CHR BIN).
Сам обрезает iNES, наращивает до нужных размеров. Один клик и можно прошивать флешку.
Также есть и редактор заголовка, и еще куча всего, чего я пока не понимаю.
Ветка автора: http://nintendoage.com/forum/messageview.cfm?catid=22&threadid=63070

DISASM6

Хороший дизассемблер. Работает с CDL файлами статистики Code/Data Logger эмулятора FCEUX.
Красиво оформляет код для ASM6.
https://forums.nesdev.com/viewtopic.php?t=7466

Извините, если это очевидные тулзы, но мало ли кому пригодится.
Omkommersind:
Эмулятор FCE220 имеет потрясающий набор встроенных инструментов для интерактивной отладки, есть ли какие-нибудь схожие аналоги для ромов SMD/Genesis?
MetalliC:
Omkommersind, вагон - Exodus, Gens Kmod, RegenD
или Smd IDA Tools
Навигация
Главная страница сообщений
Следующая страница
Предыдущая страница

Перейти к полной версии