Loading

RGB DESTROYER v1

  1. import math
  2. import time
  3. import datetime
  4. import os
  5. from os import remove
  6. from PIL import Image
  7. from multiprocessing import Pool
  8. import multiprocessing
  9. from copy import deepcopy
  10. import argparse
  11.  
  12. # print functions for control from debug_level parameter
  13. def print_start(bool, string):
  14.   if bool == True:
  15.     print(str(string))
  16. def print_lvl_0(debug_level, string):
  17.   print(str(string))
  18. def print_lvl_1(debug_level, string):
  19.   if debug_level > 0:
  20.     print(str(string))
  21. def print_lvl_2(debug_level, string):
  22.   if debug_level > 1:
  23.     print(str(string))
  24. def print_lvl_3(debug_level, string):
  25.   if debug_level > 2:
  26.     print(str(string))
  27. def print_lvl_4(debug_level, string):
  28.   if debug_level > 3:
  29.     print(str(string))
  30. def print_lvl_5(debug_level, string):
  31.   if debug_level > 4:
  32.     print(str(string))
  33. def print_lvl_6(debug_level, string):
  34.   if debug_level > 5:
  35.     print(str(string))
  36. def print_lvl_7(debug_level, string):
  37.   if debug_level > 6:
  38.     print(str(string))
  39.  
  40. # centralized way to turn off messages at the start of the script
  41. show_starting_messages = False
  42. # starting message
  43. print_start(show_starting_messages, '-'*79)
  44. print_start(show_starting_messages, 'Starting...')
  45.  
  46. # path definition
  47. diskPath = ''# only fill if you want it to work in some absolute path
  48. inputFolder = diskPath + 'input/'
  49. outputFolder = diskPath + 'output/'
  50. tempFolder = outputFolder + 'temp/'#don't change this
  51. # make sure the output folders exist
  52. os.makedirs(outputFolder, exist_ok = True)
  53. os.makedirs(tempFolder, exist_ok = True)
  54. # printing path just to check
  55. print_start(show_starting_messages, 'inputFolder is ' + inputFolder)
  56. print_start(show_starting_messages, 'outputFolder is ' + outputFolder)
  57.  
  58. # starting timer
  59. tt = time.time()
  60. # format the time. I forgot how this works but it does.
  61. startedTime = datetime.datetime.fromtimestamp(tt).strftime('%H:%M:%S')
  62.  
  63. # open palette images
  64. # -----------------------------------------------------------------------------------------------------------------
  65. # image for palette data
  66. palette_img_indexed = Image.open(inputFolder + 'palette_key.png')
  67. palette_data = deepcopy(palette_img_indexed.palette)
  68. print_start(show_starting_messages, 'Opening and loading palette: ' + 'openttd-palette-dos-RGBA.png')  
  69. # image for colour comparing
  70. palette_img = Image.open(inputFolder + 'openttd-palette-dos-RGBA.png')
  71. # creating palette list of RGB pixels
  72. p=[]
  73. for b in range(0,palette_img.height):
  74.   for a in range(0, palette_img.width):
  75.     p.append(palette_img.getpixel((a,b)))
  76. print_start(show_starting_messages, 'Palette loaded.')
  77.  
  78. # ----------------------------------------------------------------------------------------------------------------
  79. # ----------------------------------------------------------------------------------------------------------------
  80. # ----------------------------------------------------------------------------------------------------------------
  81. #                                   D E F I N I N G   O F   F U N C T I O N S
  82. # ----------------------------------------------------------------------------------------------------------------
  83. # ----------------------------------------------------------------------------------------------------------------
  84. # ----------------------------------------------------------------------------------------------------------------
  85.  
  86. def rgb2palette(args):
  87.   # extract the arguments from the big args list
  88.   thread_id = args[0]
  89.   input_image = args[1]
  90.   x_start = args[2]
  91.   x_end = args[3]
  92.   allowed_colour_types = args[4]
  93.   disallowed_colour_types = args[5]
  94.   allowed_colour_indexes = args[6]
  95.   disallowed_colour_indexes = args[7]
  96.   alpha_ignore = args[8]
  97.   alpha_offset_2 = args[9]
  98.   alpha_offset_1 = args[10]
  99.   red_weight = args[11]
  100.   green_weight = args[12]
  101.   blue_weight = args[13]
  102.   arg_colour_shift = args[14]
  103.   arg_debug_level = args[15]
  104.   offset_list = args[16]
  105.   arg_individual_temp = args[17]
  106.   print('individual_temp - rgb2palette = ' + str(arg_individual_temp))
  107.   print_lvl_5(arg_debug_level, 'rgb2palette args: ' + str(args))
  108.  
  109.   # create allowed colours list
  110.   colours_to_filter = []
  111.   for coltype in allowed_colour_types:
  112.     if coltype == 'ALL':
  113.       for n in range(1, 80):
  114.         colours_to_filter.append(n)
  115.       for n in range(88, 197):
  116.         colours_to_filter.append(n)
  117.       for n in range(205, 215):
  118.         colours_to_filter.append(n)
  119.     if coltype == 'GRAYSCALE':
  120.       for n in range(1, 16):
  121.         colours_to_filter.append(n)
  122.     if coltype == 'METAL':
  123.       for n in range(16, 24):
  124.         colours_to_filter.append(n)
  125.     if coltype == 'LIME_GREEN':
  126.       for n in range(24, 32):
  127.         colours_to_filter.append(n)
  128.     if coltype == 'BEIGE':
  129.       for n in range(32, 40):
  130.         colours_to_filter.append(n)
  131.     if coltype == 'DARK_PINK':
  132.       for n in range(40, 48):
  133.         colours_to_filter.append(n)
  134.     if coltype == 'YELLOW':
  135.       for n in range(50, 53):
  136.         colours_to_filter.append(n)
  137.     if coltype == 'DARK_BEIGE':
  138.       for n in range(53, 60):
  139.         colours_to_filter.append(n)
  140.     if coltype == 'YELLOW':
  141.       for n in range(60, 70):
  142.         colours_to_filter.append(n)
  143.     if coltype == 'BROWN_1':
  144.       for n in range(70, 80):
  145.         colours_to_filter.append(n)
  146.     if coltype == 'CC2':
  147.       for n in range(80, 88):
  148.         colours_to_filter.append(n)
  149.     if coltype == 'DARK_GREEN':
  150.       for n in range(88, 96):
  151.         colours_to_filter.append(n)
  152.     if coltype == 'PALE_GREEN':
  153.       for n in range(96, 104):
  154.         colours_to_filter.append(n)
  155.     if coltype == 'BROWN_2':
  156.       for n in range(104, 112):
  157.         colours_to_filter.append(n)
  158.     if coltype == 'BROWN_3':
  159.       for n in range(112, 122):
  160.         colours_to_filter.append(n)
  161.     if coltype == 'BROWN_4':
  162.       for n in range(122, 128):
  163.         colours_to_filter.append(n)
  164.     if coltype == 'MAUVE':
  165.       for n in range(128, 136):
  166.         colours_to_filter.append(n)
  167.     if coltype == 'PURPLE':
  168.       for n in range(136, 144):
  169.         colours_to_filter.append(n)
  170.     if coltype == 'BLUE':
  171.       for n in range(144, 154):
  172.         colours_to_filter.append(n)
  173.     if coltype == 'LIGHT_BLUE':
  174.       for n in range(154, 162):
  175.         colours_to_filter.append(n)
  176.     if coltype == 'PINK':
  177.       for n in range(162, 170):
  178.         colours_to_filter.append(n)
  179.     if coltype == 'LIGHT_PURPLE':
  180.       for n in range(170, 178):
  181.         colours_to_filter.append(n)
  182.     if coltype == 'RED_1':
  183.       for n in range(178, 185):
  184.         colours_to_filter.append(n)
  185.     if coltype == 'RED_2':
  186.       for n in range(185, 192):
  187.         colours_to_filter.append(n)
  188.     if coltype == 'ORANGE':
  189.       for n in range(192, 198):
  190.         colours_to_filter.append(n)
  191.     if coltype == 'CC1':
  192.       for n in range(198, 206):
  193.         colours_to_filter.append(n)
  194.     if coltype == 'GREEN':
  195.       for n in range(206, 210):
  196.         colours_to_filter.append(n)
  197.     if coltype =='CYAN':
  198.       for n in range(210, 215):
  199.         colours_to_filter.append(n)
  200.     if coltype == 'COLA':
  201.       for n in range(227, 232):
  202.         colours_to_filter.append(n)
  203.     if coltype == 'FIRE':
  204.       for n in range(232, 239):
  205.         colours_to_filter.append(n)
  206.     if coltype == 'LED_RED':
  207.       for n in range(239, 241):
  208.         colours_to_filter.append(n)
  209.     if coltype == 'LED_YELLOW':
  210.       for n in range(241, 245):
  211.         colours_to_filter.append(n)
  212.     if coltype == 'WATER':
  213.       for n in range(245, 255):
  214.         colours_to_filter.append(n)
  215.     if coltype == 'WHITE':
  216.       for n in range(255, 256):
  217.         colours_to_filter.append(n)
  218.  
  219.   # create disallowed colours list
  220.   disallowed_colours = []
  221.   for coltype in disallowed_colour_types:
  222.     if coltype == 'ALL':
  223.       for n in range(1, 80):
  224.         disallowed_colours.append(n)
  225.       for n in range(88, 197):
  226.         disallowed_colours.append(n)
  227.       for n in range(205, 215):
  228.         disallowed_colours.append(n)
  229.     if coltype == 'GRAYSCALE':
  230.       for n in range(1, 16):
  231.         disallowed_colours.append(n)
  232.     if coltype == 'METAL':
  233.       for n in range(16, 24):
  234.         disallowed_colours.append(n)
  235.     if coltype == 'LIME_GREEN':
  236.       for n in range(24, 32):
  237.         disallowed_colours.append(n)
  238.     if coltype == 'BEIGE':
  239.       for n in range(32, 40):
  240.         disallowed_colours.append(n)
  241.     if coltype == 'DARK_PINK':
  242.       for n in range(40, 48):
  243.         disallowed_colours.append(n)
  244.     if coltype == 'YELLOW':
  245.       for n in range(50, 53):
  246.         disallowed_colours.append(n)
  247.     if coltype == 'DARK_BEIGE':
  248.       for n in range(53, 60):
  249.         disallowed_colours.append(n)
  250.     if coltype == 'YELLOW':
  251.       for n in range(60, 70):
  252.         disallowed_colours.append(n)
  253.     if coltype == 'BROWN_1':
  254.       for n in range(70, 80):
  255.         disallowed_colours.append(n)
  256.     if coltype == 'CC2':
  257.       for n in range(80, 88):
  258.         disallowed_colours.append(n)
  259.     if coltype == 'DARK_GREEN':
  260.       for n in range(88, 96):
  261.         disallowed_colours.append(n)
  262.     if coltype == 'PALE_GREEN':
  263.       for n in range(96, 104):
  264.         disallowed_colours.append(n)
  265.     if coltype == 'BROWN_2':
  266.       for n in range(104, 112):
  267.         disallowed_colours.append(n)
  268.     if coltype == 'BROWN_3':
  269.       for n in range(112, 122):
  270.         disallowed_colours.append(n)
  271.     if coltype == 'BROWN_4':
  272.       for n in range(122, 128):
  273.         disallowed_colours.append(n)
  274.     if coltype == 'MAUVE':
  275.       for n in range(128, 136):
  276.         disallowed_colours.append(n)
  277.     if coltype == 'PURPLE':
  278.       for n in range(136, 144):
  279.         disallowed_colours.append(n)
  280.     if coltype == 'BLUE':
  281.       for n in range(144, 154):
  282.         disallowed_colours.append(n)
  283.     if coltype == 'LIGHT_BLUE':
  284.       for n in range(154, 162):
  285.         disallowed_colours.append(n)
  286.     if coltype == 'PINK':
  287.       for n in range(162, 170):
  288.         disallowed_colours.append(n)
  289.     if coltype == 'LIGHT_PURPLE':
  290.       for n in range(170, 178):
  291.         disallowed_colours.append(n)
  292.     if coltype == 'RED_1':
  293.       for n in range(178, 185):
  294.         disallowed_colours.append(n)
  295.     if coltype == 'RED_2':
  296.       for n in range(185, 192):
  297.         disallowed_colours.append(n)
  298.     if coltype == 'ORANGE':
  299.       for n in range(192, 198):
  300.         disallowed_colours.append(n)
  301.     if coltype == 'CC1':
  302.       for n in range(198, 206):
  303.         disallowed_colours.append(n)
  304.     if coltype == 'GREEN':
  305.       for n in range(206, 210):
  306.         disallowed_colours.append(n)
  307.     if coltype =='CYAN':
  308.       for n in range(210, 215):
  309.         disallowed_colours.append(n)
  310.     if coltype == 'COLA':
  311.       for n in range(227, 232):
  312.         disallowed_colours.append(n)
  313.     if coltype == 'FIRE':
  314.       for n in range(232, 239):
  315.         disallowed_colours.append(n)
  316.     if coltype == 'LED_RED':
  317.       for n in range(239, 241):
  318.         disallowed_colours.append(n)
  319.     if coltype == 'LED_YELLOW':
  320.       for n in range(241, 245):
  321.         disallowed_colours.append(n)
  322.     if coltype == 'WATER':
  323.       for n in range(245, 255):
  324.         disallowed_colours.append(n)
  325.     if coltype == 'WHITE':
  326.       for n in range(255, 256):
  327.         disallowed_colours.append(n)
  328.  
  329.   # add individual disallowed colours
  330.   for n in disallowed_colour_indexes:
  331.     disallowed_colours.append(n)
  332.  
  333.   # move non-disallowed colours to a new list
  334.   filtered_colours_to_filter = []
  335.   for c in colours_to_filter:
  336.     skip = 0
  337.     for d in disallowed_colours:
  338.       if c == d:
  339.         skip = 1
  340.     if skip == 0:
  341.       filtered_colours_to_filter.append(c)
  342.  
  343.   # add individual allowed colours
  344.   for n in allowed_colour_indexes:
  345.     filtered_colours_to_filter.append(n)
  346.  
  347.   print_lvl_4(arg_debug_level, 'Colours to filter: ' + str(filtered_colours_to_filter))
  348.  
  349.   # open input image
  350.   i = Image.open(inputFolder + input_image + '.png')
  351.   print_lvl_2(arg_debug_level, 'Thread ' + str(thread_id) + ' Opening: ' + input_image + '.png')  
  352.  
  353.   # create new empty indexed image for output
  354.   imageOutput = Image.new('L', (i.width,i.height), color = 0)
  355.  
  356.   # go through the input image - y axis
  357.   for y in range (0, i.height):
  358.     # timestamp for debug
  359.     ts = time.time()
  360.     timeStamp = datetime.datetime.fromtimestamp(ts).strftime('%H:%M:%S')
  361.     if y%32 == 0:
  362.       print_lvl_5(arg_debug_level, 'Thread ' + str(thread_id) + ' ' + timeStamp + ' - ' + input_image + ' row {}'.format(y))
  363.  
  364.     # go through the input image - x axis, limited by threaded strips
  365.     for x in range (x_start, x_end):
  366.       # defining winner variables just so they exist
  367.       winnerDistance = 100000000
  368.       winnerID = 0
  369.       # loading pixel from image and separating RGBA
  370.       pixelNumber = x + (y * i.width)
  371.       pix = i.getpixel((x,y))
  372.       pixRed = pix[0]
  373.       pixGreen = pix[1]
  374.       pixBlue = pix[2]
  375.       pixAlpha = pix[3]
  376.  
  377.       # check Alpha in pixel, and output alpha/color offset
  378.       if pixAlpha < alpha_ignore:
  379.         finalAlpha = 0
  380.         colorOffset = 0
  381.       if pixAlpha >= alpha_ignore and pixAlpha < 178:
  382.         finalAlpha = 255
  383.         colorOffset = 2
  384.       if pixAlpha >= alpha_offset_1 and pixAlpha < alpha_offset_2:
  385.         finalAlpha = 255
  386.         colorOffset = 1
  387.       if pixAlpha >= alpha_offset_2:
  388.         finalAlpha = 255
  389.         colorOffset = 0
  390.          
  391.       # if alpha above 50%, do colour comparing to palette
  392.       if pixAlpha >= alpha_ignore:
  393.         # go through all of the specified colours to filter
  394.         for colour_id in filtered_colours_to_filter:
  395.           rgb1 = p[colour_id]
  396.           r1 = rgb1[0]
  397.           g1 = rgb1[1]
  398.           b1 = rgb1[2]
  399.  
  400.           l1 = (r1*red_weight + g1*green_weight + b1*blue_weight) / 255000
  401.           l2 = (pixRed*red_weight + pixGreen*green_weight + pixBlue*blue_weight) / 255000
  402.           dL = l1-l2
  403.           dR = (r1-pixRed)/255
  404.           dG = (g1-pixGreen)/255
  405.           dB = (b1-pixBlue)/255
  406.           distance = (dR*dR*red_weight*0.001 + dG*dG*blue_weight*0.001 + dB*dB*blue_weight*0.001)*0.75 + dL*dL
  407.           # if it's better match than the previous tries, save it as the new winner
  408.           if distance < winnerDistance:
  409.             winnerDistance = distance
  410.             winnerID = colour_id
  411.  
  412.       # final color changed by colorOffset
  413.       finalID = offset_list[winnerID][colorOffset] #winnerID - colorOffset
  414.       # finalAlpha taken from the if output above palette colour comparing
  415.  
  416.       # making sure that disallowed colours don't appear even by color offset.
  417.       # if the disallowed colour appears with color offset = 2, try with color offset = 1.
  418.       # if the problem persists, remove color offset
  419.       if colorOffset == 2:
  420.         for g in disallowed_colours:
  421.           if g == finalID:
  422.             colorOffset = 1
  423.             finalID = offset_list[winnerID][colorOffset]
  424.       if colorOffset == 1:
  425.         for g in disallowed_colours:
  426.           if g == finalID:
  427.             colorOffset = 0
  428.             finalID = offset_list[winnerID][colorOffset]
  429.          
  430.       # argument to ignore colorOffset
  431.       if arg_colour_shift == False:
  432.         finalID = winnerID
  433.  
  434.       # put the final pixel into the output picture
  435.       imageOutput.putpixel((x,y),(finalID))
  436.  
  437.   # crop the output image based on the threaded strip values
  438.   # because indexed images don't have alpha, this makes it easier to combine them later
  439.   cropped_imageOutput = imageOutput.crop((x_start, 0,x_end,i.height))
  440.   # put the palette data into the output
  441.   cropped_imageOutput.putpalette(palette_data)
  442.   # save the output image to temp folder (with individual parameter or without)
  443.   if arg_individual_temp == True:
  444.     cropped_imageOutput.save(outputFolder + 'temp/' + str(input_image) + '_'  + str(thread_id) + '_8bpp.png')
  445.   elif arg_individual_temp == False:
  446.     cropped_imageOutput.save(outputFolder + 'temp/' + 'temp' + '_'  + str(thread_id) + '_8bpp.png')
  447.   # close the images
  448.   # we won't need i anymore, and output will need to be loaded again later
  449.   i.close()
  450.   cropped_imageOutput.close()    
  451.    
  452. # function for combining the outputs of different threads
  453. def combineResults(args, thread_count, palette_data, arg_debug_level, arg_individual_temp, arg_auto_clean_temp):
  454.   print('individual_temp = ' + str(arg_individual_temp))
  455.   # extract arguments from the big args list
  456.   thread_id = args[0]
  457.   combine_input_image = args[1]
  458.   x_start = args[2]
  459.   x_end = args[3]
  460.   # print arguments for debug
  461.   print_lvl_5(arg_debug_level, 'combineResults args: ' + str(args))
  462.  
  463.   # get the final output resolution based on input image
  464.   image_for_resolution = Image.open(inputFolder + str(combine_input_image[1]) + '.png')
  465.   # create new empty input image with indexed colour
  466.   final_image = Image.new('L', (image_for_resolution.width, image_for_resolution.height), color = 0)
  467.   # put palette in the final output image
  468.   final_image.putpalette(palette_data)
  469.   # print the height of the output
  470.   print_lvl_3(arg_debug_level, 'img_resolution.height = ' + str(image_for_resolution.height))
  471.  
  472.   # args is a list of commands for the combiner
  473.   for combine_order in args:
  474.     # take the image we want to paste into the final output image
  475.     if arg_individual_temp == True:
  476.       image_to_paste = Image.open(outputFolder + 'temp/' + str(combine_order[1]) + '_'  + str(combine_order[0]) + '_8bpp.png')
  477.     elif arg_individual_temp == False:
  478.       image_to_paste = Image.open(outputFolder + 'temp/' + 'temp' + '_'  + str(combine_order[0]) + '_8bpp.png')
  479.     # print which strip we are pasting
  480.     print_lvl_3(arg_debug_level, 'Combine strip with x_start = ' + str(combine_order[2]))
  481.     # paste the strip into the correct position of x_start
  482.     final_image.paste(image_to_paste, box = (combine_order[2], 0))
  483.  
  484.   # put the palette data in there again just to make sure (not sure which one is necessary, it works now)
  485.   final_image.putpalette(palette_data)
  486.   # save the final output image
  487.   final_image.save(outputFolder + str(combine_input_image[1]) + '_8bpp.png')
  488.  
  489.   # optionally remove the temp files
  490.   if arg_auto_clean_temp == True:
  491.     for combine_order in args:
  492.       if arg_individual_temp == True:
  493.         os.remove(outputFolder + 'temp/' + str(combine_order[1]) + '_'  + str(combine_order[0]) + '_8bpp.png')
  494.       elif arg_individual_temp == False:
  495.         os.remove(outputFolder + 'temp/' + 'temp' + '_'  + str(combine_order[0]) + '_8bpp.png')
  496.  
  497. # function for easy debug of constructing the long and rather unreadable offset list
  498. def check_list_count(arg_debug_level, list_to_check, n):
  499.   #define some variable
  500.   w = 0
  501.   for stuff in list_to_check:
  502.     # add +1 to w for every item in the list
  503.     w += 1
  504.   # print amount of items in the list(w), and n for easy comparison. They should be equal.
  505.   print_lvl_5(arg_debug_level, 'Offset list item count: ' + str(w) + ' , last n is: ' + str(n))
  506.  
  507. # function to append only sub-lists instead of appending the whole list
  508. def append_offset_list(offset_list, temp_list):
  509.   for t in temp_list:
  510.     offset_list.append(t)
  511.  
  512. # function to make a template for 6-index colours for index offset list
  513. def add_6_index_list(offset_list, n):
  514.     temp_list = [
  515.         [   n,  n+1,  n+2],#1
  516.         [ n+1,  n+2,  n+3],#2
  517.         [ n+2,  n+3,  n+3],#3--
  518.         [ n+3,  n+3,  n+2],#4--
  519.         [ n+4,  n+3,  n+2],#5
  520.         [ n+5,  n+4,  n+3]# 6
  521.       ]
  522.     append_offset_list(offset_list,temp_list)
  523.  
  524. # function to make a template for 8-index colours for index offset list
  525. def add_8_index_list(offset_list, n):
  526.     temp_list = [
  527.         [   n,  n+1,  n+2],#1
  528.         [ n+1,  n+2,  n+3],#2
  529.         [ n+2,  n+3,  n+4],#3
  530.         [ n+3,  n+4,  n+4],#4--
  531.         [ n+4,  n+4,  n+3],#5--
  532.         [ n+5,  n+4,  n+3],#6
  533.         [ n+6,  n+5,  n+4],#7
  534.         [ n+7,  n+6,  n+5]# 8
  535.       ]
  536.     append_offset_list(offset_list,temp_list)
  537.  
  538. # function to make a template for 10-index colours for index offset list
  539. def add_10_index_list(offset_list, n):
  540.     temp_list = [
  541.         [   n,  n+1,  n+2],#1
  542.         [ n+1,  n+2,  n+3],#2
  543.         [ n+2,  n+3,  n+4],#3
  544.         [ n+3,  n+4,  n+5],#4
  545.         [ n+4,  n+5,  n+5],#5--
  546.         [ n+5,  n+5,  n+4],#6--
  547.         [ n+6,  n+5,  n+4],#7
  548.         [ n+7,  n+6,  n+5],#8
  549.         [ n+8,  n+7,  n+6],#9
  550.         [ n+9,  n+8,  n+7]#10
  551.       ]
  552.     append_offset_list(offset_list,temp_list)
  553.      
  554. def run():
  555.   # define thread count
  556.   thread_count = options['thread_count']
  557.  
  558.   # define what should the queue for rgb2palette include
  559.   job_list = [  
  560.       [
  561.       options['input_name'],        
  562.       options['allowed_colour_types'],#allowed colour types (string list)
  563.       options['disallowed_colour_types'],#disallowed colour types (string list)
  564.       options['allowed_colour_indexes'],#allowed colour indexes (number list)
  565.       options['disallowed_colour_indexes'],#disallowed colour indexes (number list)
  566.       options['alpha_ignore'],
  567.       options['alpha_offset_2'],
  568.       options['alpha_offset_1'],
  569.       options['red_weight'],#red weight (number, default = 1)
  570.       options['green_weight'],#green weight (number, default = 1)
  571.       options['blue_weight'],#blue weight (number, default = 1)
  572.       options['colour_shift'],
  573.       options['debug_level'],
  574.       options['individual_temp']
  575.       ]
  576.     ]
  577.   # job_list-related stuff to be continued later down after creating offset list...
  578.  
  579.   #--------------------------------------------------------------------------------
  580.   #creating offset list -----------------------------------------------------------
  581.   #--------------------------------------------------------------------------------
  582.   offset_list = []
  583.  
  584.   #TRANSPARENCY BLUE
  585.   n = 0
  586.   check_list_count(options['debug_level'], offset_list, n)
  587.   temp_list = [
  588.     [n,n,n]
  589.   ]
  590.   append_offset_list(offset_list,temp_list)
  591.  
  592.   #GRAYSCALE
  593.   n = 1
  594.   check_list_count(options['debug_level'], offset_list, n)
  595.   temp_list = [
  596.       [   n,  n+1,  n+2],#1
  597.       [ n+1,  n+2,  n+3],#2
  598.       [ n+2,  n+3,  n+4],#3
  599.       [ n+3,  n+4,  n+5],#4
  600.       [ n+4,  n+5,  n+6],#5
  601.       [ n+5,  n+6,  n+7],#6
  602.       [ n+6,  n+7,  n+7],#7--
  603.       [ n+7,  n+8,  n+8],#8--
  604.       [ n+8,  n+8,  n+7],#9--
  605.       [ n+9,  n+8,  n+7],#10
  606.       [n+10,  n+9,  n+8],#11
  607.       [n+11, n+10,  n+9],#12
  608.       [n+12, n+11, n+10],#13
  609.       [n+13, n+12, n+11],#14
  610.       [n+14, n+13, n+12],#15
  611.   ]
  612.   append_offset_list(offset_list, temp_list)
  613.  
  614.   #METAL
  615.   n = 16
  616.   check_list_count(options['debug_level'], offset_list, n)
  617.   add_8_index_list(offset_list, n)
  618.  
  619.   #LIME_GREEN
  620.   n = 24
  621.   check_list_count(options['debug_level'], offset_list, n)
  622.   add_8_index_list(offset_list, n)
  623.  
  624.   #BEIGE
  625.   n = 32
  626.   check_list_count(options['debug_level'], offset_list, n)
  627.   add_8_index_list(offset_list, n)
  628.  
  629.   #DARK_PINK
  630.   n = 40
  631.   check_list_count(options['debug_level'], offset_list, n)
  632.   add_10_index_list(offset_list, n)
  633.  
  634.   #YELLOW
  635.   n = 50
  636.   check_list_count(options['debug_level'], offset_list, n)
  637.   temp_list = [
  638.     [   n,  189,  188],#1
  639.     [ n+1,  n+0,  188],#2
  640.     [ n+2,  n+1,  n+0]# 3
  641.   ]
  642.   append_offset_list(offset_list, temp_list)
  643.  
  644.   #DARK_BEIGE
  645.   n = 53
  646.   check_list_count(options['debug_level'], offset_list, n)
  647.   temp_list = [
  648.     [   n,  n+1,  n+2],#1
  649.     [ n+1,  n+2,  n+3],#2
  650.     [ n+2,  n+3,  n+3],#3--
  651.     [ n+3,  n+3,  n+4],#4--
  652.     [ n+4,  n+3,  n+3],#5--
  653.     [ n+5,  n+4,  n+3],#6
  654.     [ n+6,  n+5,  n+4]# 7
  655.   ]
  656.   append_offset_list(offset_list, temp_list)
  657.  
  658.   #YELLOW
  659.   n = 60
  660.   check_list_count(options['debug_level'], offset_list, n)
  661.   add_10_index_list(offset_list, n)
  662.  
  663.   #BROWN_1
  664.   n = 70
  665.   check_list_count(options['debug_level'], offset_list, n)
  666.   add_10_index_list(offset_list, n)
  667.  
  668.   #CC2,
  669.   n = 80
  670.   check_list_count(options['debug_level'], offset_list, n)
  671.   add_8_index_list(offset_list, n)
  672.  
  673.   #DARK_GREEN
  674.   n = 88
  675.   check_list_count(options['debug_level'], offset_list, n)
  676.   add_8_index_list(offset_list, n)
  677.  
  678.   #PALE_GREEN
  679.   n = 96
  680.   check_list_count(options['debug_level'], offset_list, n)
  681.   add_8_index_list(offset_list, n)
  682.  
  683.   #BROWN_2
  684.   n = 104
  685.   check_list_count(options['debug_level'], offset_list, n)
  686.   add_8_index_list(offset_list, n)
  687.  
  688.   #BROWN_3
  689.   n = 112
  690.   check_list_count(options['debug_level'], offset_list, n)
  691.   add_10_index_list(offset_list, n)
  692.  
  693.   #BROWN_4
  694.   n = 122
  695.   check_list_count(options['debug_level'], offset_list, n)
  696.   add_6_index_list(offset_list, n)
  697.  
  698.   #MAUVE
  699.   n = 128
  700.   check_list_count(options['debug_level'], offset_list, n)
  701.   add_8_index_list(offset_list, n)
  702.  
  703.   #PURPLE
  704.   n = 136
  705.   check_list_count(options['debug_level'], offset_list, n)
  706.   add_8_index_list(offset_list, n)
  707.  
  708.   #BLUE
  709.   n = 144
  710.   check_list_count(options['debug_level'], offset_list, n)
  711.   add_10_index_list(offset_list, n)
  712.  
  713.   #LIGHT_BLUE
  714.   n = 154
  715.   check_list_count(options['debug_level'], offset_list, n)
  716.   add_8_index_list(offset_list, n)
  717.  
  718.   #PINK
  719.   n = 162
  720.   check_list_count(options['debug_level'], offset_list, n)
  721.   add_8_index_list(offset_list, n)
  722.  
  723.   #LIGHT_PURPLE
  724.   n = 170
  725.   check_list_count(options['debug_level'], offset_list, n)
  726.   add_8_index_list(offset_list, n)
  727.  
  728.   #RED
  729.   n = 178
  730.   check_list_count(options['debug_level'], offset_list, n)
  731.   temp_list = [
  732.     [   n,  n+1,  n+2],#1
  733.     [ n+1,  n+2,  n+3],#2
  734.     [ n+2,  n+3,  n+4],#3
  735.     [ n+3,  n+4,  n+5],#4
  736.     [ n+4,  n+5,  n+6],#5
  737.     [ n+5,  n+6,  n+7],#6
  738.     [ n+6,  n+7,  n+7],#7--
  739.     [ n+7,  n+6,  n+6],#8--
  740.     [ n+8,  n+7,  n+6],#9
  741.     [ n+9,  n+8,  n+7],#10
  742.     [n+10,  n+9,  n+8],#11
  743.     [n+11, n+10,  n+9],#12
  744.     [n+12, n+11, n+10],#13
  745.     [n+13, n+12, n+11]#14
  746.   ]
  747.   append_offset_list(offset_list, temp_list)
  748.  
  749.   #ORANGE
  750.   n = 192
  751.   check_list_count(options['debug_level'], offset_list, n)
  752.   temp_list = [
  753.     [  n,   64,  63],#1
  754.     [ n+1, n+0,  64],#2
  755.     [ n+2, n+1, n+0],#3
  756.     [ n+3, n+2,  n+1],#4
  757.     [ n+4, n+3, n+2],#5
  758.     [ n+5, n+4, n+3]#6
  759.   ]
  760.   append_offset_list(offset_list, temp_list)
  761.  
  762.   #CC1
  763.   n = 198
  764.   check_list_count(options['debug_level'], offset_list, n)
  765.   add_8_index_list(offset_list, n)
  766.  
  767.   #GREEN
  768.   n = 206
  769.   check_list_count(options['debug_level'], offset_list, n)
  770.   temp_list = [
  771.     [    n, 93,  92],#1
  772.     [ n+1, n+0,  93],#2
  773.     [ n+2, n+1, n+0],#3
  774.     [ n+3, n+2, n+1]# 4
  775.   ]
  776.   append_offset_list(offset_list, temp_list)
  777.  
  778.   #CYAN
  779.   n = 210
  780.   check_list_count(options['debug_level'], offset_list, n)
  781.   temp_list = [
  782.     [  n, n+1, n+2],#1
  783.     [n+1, n+2, n+2],#2
  784.     [n+2, n+3, n+3],#3
  785.     [n+3, n+2, n+2],#4
  786.     [n+4, n+3, n+2]# 5
  787.   ]
  788.   append_offset_list(offset_list, temp_list)
  789.  
  790.   #ALPHAPINK & ACT
  791.   n = 215
  792.   check_list_count(options['debug_level'], offset_list, n)
  793.   temp_list = [
  794.     [  n+0,  n+0,  n+0],#1  - index 215
  795.     [  n+1,  n+1,  n+1],#2  - index 216
  796.     [  n+2,  n+2,  n+2],#3  - index 217
  797.     [  n+3,  n+3,  n+3],#4  - index 218
  798.     [  n+4,  n+4,  n+4],#5  - index 219
  799.     [  n+5,  n+5,  n+5],#6  - index 220
  800.     [  n+6,  n+6,  n+6],#7  - index 221
  801.     [  n+7,  n+7,  n+7],#8  - index 222
  802.     [  n+8,  n+8,  n+8],#9  - index 223
  803.     [  n+9,  n+9,  n+9],#10 - index 224
  804.     [ n+10, n+10, n+10],#11 - index 225
  805.     [ n+11, n+11, n+11],#12 - index 226
  806.     [ n+12, n+12, n+12],#13 - index 227
  807.     [ n+13, n+13, n+13],#14 - index 228
  808.     [ n+14, n+14, n+14],#15 - index 229
  809.     [ n+15, n+15, n+15],#16 - index 230
  810.     [ n+16, n+16, n+16],#17 - index 231
  811.     [ n+17, n+17, n+17],#18 - index 232
  812.     [ n+18, n+18, n+18],#19 - index 233
  813.     [ n+19, n+19, n+19],#20 - index 234
  814.     [ n+20, n+20, n+20],#21 - index 235
  815.     [ n+21, n+21, n+21],#22 - index 236
  816.     [ n+22, n+22, n+22],#23 - index 237
  817.     [ n+23, n+23, n+23],#24 - index 238
  818.     [ n+24, n+24, n+24],#25 - index 239
  819.     [ n+25, n+25, n+25],#26 - index 240
  820.     [ n+26, n+26, n+26],#27 - index 241
  821.     [ n+27, n+27, n+27],#28 - index 242
  822.     [ n+28, n+28, n+28],#29 - index 243
  823.     [ n+29, n+29, n+29],#30 - index 244
  824.     [ n+30, n+30, n+30],#31 - index 245
  825.     [ n+31, n+31, n+31],#32 - index 246
  826.     [ n+32, n+32, n+32],#33 - index 247
  827.     [ n+33, n+33, n+33],#34 - index 248
  828.     [ n+34, n+34, n+34],#35 - index 249
  829.     [ n+35, n+35, n+35],#36 - index 250
  830.     [ n+36, n+36, n+36],#37 - index 251
  831.     [ n+37, n+37, n+37],#38 - index 252
  832.     [ n+38, n+38, n+38],#39 - index 253
  833.     [ n+39, n+39, n+39],#40 - index 254
  834.     [ n+40, n+40, n+40] #41 - index 255
  835.   ]
  836.   append_offset_list(offset_list, temp_list)
  837.  
  838.   # final check
  839.   n = 256
  840.   check_list_count(options['debug_level'], offset_list, n)
  841.  
  842.   # continuation of job_list-related stuff from before creating offset list...
  843.   for job in job_list:
  844.     # defining lists just so they exist
  845.     all_jobs = []
  846.     job_chunks = []
  847.     queue = []
  848.     # variable for adding a pixel to some threads in case full image result can't be divided by thread count
  849.     extra = 0
  850.     # open image
  851.     chunk_image = Image.open(inputFolder + job[0] + '.png')
  852.     # get their average size, rounded down
  853.     chunk_average_size = math.floor(chunk_image.width/thread_count)
  854.     # get the remaining pixel columns after rounded down division
  855.     chunk_modulo_size = chunk_image.width % thread_count
  856.     # get x-axis starts and ends of strips
  857.     for thread in range(0, thread_count):
  858.       start = chunk_average_size * thread
  859.       end = (chunk_average_size * (thread+1))
  860.       # add extra pixels in case full image width can't be divided by thread count
  861.       start += extra
  862.       if thread < chunk_modulo_size:  
  863.         extra += 1
  864.       end += extra
  865.  
  866.       # define a list to append into a big chunk of jobs for 1 task
  867.       # (not utilized anymore but can be if parameters are overridden
  868.       # and everything is launched from python with changing the options from here)
  869.       job_chunk_list = [
  870.                         thread, #0 - threadID
  871.                         job[0], #1 - input_name
  872.                         start,  #2 - x_start
  873.                         end,    #3 - x_end
  874.                         job[1], #4 - allowed_colour_types
  875.                         job[2], #5 - disallowed_colour_types
  876.                         job[3], #6 - allowed_colour_indexes
  877.                         job[4], #7 - disallowed_colour_indexes
  878.                         job[5], #8 - alpha_ignore
  879.                         job[6], #9 - alpha_offset_1
  880.                         job[7], #10- alpha_offset_2
  881.                         job[8], #11- red_weight
  882.                         job[9], #12- green_weight
  883.                         job[10],#13- blue_weight
  884.                         job[11],#14- colour_shift
  885.                         job[12],#15- debug_level
  886.                         offset_list,#16
  887.                         options['individual_temp']#17
  888.                       ]
  889.       # append the job chunk list in to job chunks
  890.       job_chunks.append(job_chunk_list)
  891.       # append the list of job pieces into queue
  892.       queue.append( [thread, job[0], start, end, job[1], job[2], job[3], job[4], job[5], job[6], job[7], job[8], job[9], job[10], job[11], job[12], offset_list, options['individual_temp'] ])
  893.     # append the job chunks into all jobs
  894.     all_jobs.append(job_chunks)
  895.  
  896.     # go through all jobs and print what they are about to do
  897.     for a_job in all_jobs:
  898.       print_lvl_5(options['debug_level'], '-'*32)
  899.       thread_id = 0
  900.       for b_thread in a_job:
  901.         if thread_id == 0:
  902.           thread_id += 1
  903.           print_lvl_5(options['debug_level'], 'Job: ' + str(b_thread[0]))
  904.           print_lvl_5(options['debug_level'], ' '*10 + 'Start, ' + 'End')
  905.           print_lvl_5(options['debug_level'], 'Thread ' + str(thread_id) + ': ' + str(b_thread[1]) + ', ' + str(b_thread[2]))#
  906.     # print the whole queue (debug level 7, this thing is LONG)
  907.     print_lvl_7(options['debug_level'], (queue))
  908.    
  909.  
  910.     # ----------------------------------------------------------------------------------------------------------------
  911.     #     M U L T I T H R E A D E D       P R O C E S S     S T A R T
  912.     # ----------------------------------------------------------------------------------------------------------------
  913.     # pool used on rgb2palette
  914.     pool = multiprocessing.Pool(processes = thread_count)
  915.     pool.map(rgb2palette, queue)
  916.     pool.close()
  917.     pool.join()
  918.     # ----------------------------------------------------------------------------------------------------------------
  919.     #     M U L T I T H R E A D E D       P R O C E S S    E N D
  920.     # ----------------------------------------------------------------------------------------------------------------
  921.  
  922.     # combine the results of the individual threads
  923.     combineResults(queue, thread_count, palette_data, options['debug_level'], options['individual_temp'], options['auto_clean_temp'])
  924.  
  925.     # finished time for timestamp
  926.     tx = time.time()
  927.     # format the time. I forgot how this works but it does.
  928.     finishedTime = datetime.datetime.fromtimestamp(tx).strftime('%H:%M:%S')
  929.     # elapsed time for timestamp
  930.     te = tx - tt
  931.     # format the elapsed time. I forgot how this works but it does.
  932.     elapsedTime = str(datetime.timedelta(seconds=int(te)))
  933.  
  934.     # print the time it took to do all this mess
  935.     print('Started:  ' + startedTime)
  936.     print('Finished: ' + finishedTime)
  937.     print('-'*18)
  938.     print('Elapsed:  ' + elapsedTime)
  939.  
  940. if __name__ == '__main__':
  941.   # define arguments/parameters
  942.   parser = argparse.ArgumentParser(description = 'Process some arguments.')
  943.   parser.add_argument('-t','--thread_count',
  944.                       help='Number of theads to run, Default: 16',
  945.                       type = int,
  946.                       required = False)
  947.   parser.add_argument('-n','--input_name',
  948.                       help='File to process. Without .png extension. File can only be RGBA (not RGB)',
  949.                       required = True)
  950.   parser.add_argument('-e','--allowed_colour_types',
  951.                       help='Allowed colour types (list of strings), Default: "ALL"',
  952.                       nargs = '+',
  953.                       required = False)
  954.   parser.add_argument('-f','--disallowed_colour_types',
  955.                       help='Disallowed colour types (list of strings), Default: nothing',
  956.                       nargs = '+',
  957.                       required = False)
  958.   parser.add_argument('-i','--allowed_colour_indexes',
  959.                       help='Allowed colour indexes (list of numbers), Default: nothing',
  960.                       nargs = '+',
  961.                       type = int,
  962.                       required = False)
  963.   parser.add_argument('-y','--disallowed_colour_indexes',
  964.                       help='Disallowed colour indexes (list of numbers), Default: nothing',
  965.                       nargs = '+',
  966.                       type = int,
  967.                       required = False)
  968.   parser.add_argument('-a','--alpha_ignore',
  969.                       help='Threshold of ignoring transparency. Default: 128',
  970.                       type = int,
  971.                       required = False)
  972.   parser.add_argument('-o','--alpha_offset_1',
  973.                       help='Threshold of transparency to colour shift by 1 index. Default: 178',
  974.                       type = int,
  975.                       required = False)
  976.   parser.add_argument('-p','--alpha_offset_2',
  977.                       help='Threshold of transparency to colour shift by 2 indexes. Default: 230',
  978.                       type = int,
  979.                       required = False)
  980.   parser.add_argument('-r','--red_weight',
  981.                       help='Weight of red input for colour comparing. Default: 1',
  982.                       type = float,
  983.                       required = False)
  984.   parser.add_argument('-g','--green_weight',
  985.                       help='Weight of green input for colour comparing. Default: 1',
  986.                       type = float,
  987.                       required = False)
  988.   parser.add_argument('-b','--blue_weight',
  989.                       help='Weight of blue input for colour comparing. Default: 1',
  990.                       type = float,
  991.                       required = False)
  992.   parser.add_argument('-c','--colour_shift',
  993.                       help='For semi-transparent pixels, shifts index to attempt to compensate alpha. Default: True',
  994.                       type = bool,
  995.                       required = False)
  996.   parser.add_argument('-d', '--debug_level',
  997.                       help='Amount of info shown in console. Default: 1, Min: 1, Max: 7',
  998.                       type = int,
  999.                       required = False)
  1000.   parser.add_argument('-z', '--individual_temp',
  1001.                       help='Filenames in temp folder are unique for each input filename, to allow running on multiple inputs at the same time. (Temp folder can get larger)',
  1002.                       type = bool,
  1003.                       required = False)
  1004.   parser.add_argument('-x', '--auto_clean_temp',
  1005.                       help='Automatically remove temp files after results are combined.',
  1006.                       type = bool,
  1007.                       required = False)
  1008.   options = vars(parser.parse_args())
  1009.   # defaults for parameters
  1010.   default_values = [
  1011.       ('thread_count',              16),
  1012.       ('allowed_colour_types',      ['ALL']),
  1013.       ('disallowed_colour_types',   []),
  1014.       ('allowed_colour_indexes',    []),
  1015.       ('disallowed_colour_indexes', []),
  1016.       ('alpha_ignore',              128),
  1017.       ('alpha_offset_1',            178),
  1018.       ('alpha_offset_2',            230),
  1019.       ('red_weight',                1),
  1020.       ('green_weight',              1),
  1021.       ('blue_weight',               1),
  1022.       ('colour_shift',              False),
  1023.       ('debug_level',               1),
  1024.       ('individual_temp',           False),
  1025.       ('auto_clean_temp',           False),
  1026.   ]
  1027.   for name, def_value in default_values:
  1028.     if not options[name]:
  1029.       options[name] = def_value
  1030.  
  1031.   run()

Comments