export_thread.py 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. import os
  2. import pathlib
  3. import queue
  4. import subprocess
  5. import threading
  6. from exception import FilterException
  7. import dest_paths
  8. import export_task
  9. import svg
  10. import util
  11. import log
  12. class ExportThread:
  13. """
  14. A class representing and managing a single thread that executes
  15. exporting tasks from the export queue.
  16. """
  17. def __init__(self, queue, name, total, m, input_path, path,
  18. renderer, license_enabled):
  19. self.queue = queue
  20. self.name = name
  21. self.total = total
  22. self.m = m
  23. self.input_path = input_path
  24. self.path = path
  25. self.renderer = renderer
  26. self.license_enabled = license_enabled
  27. self.err = None
  28. # this essentially tells self.run() to stop running if it is True
  29. self.kill_flag = False
  30. # the actual thread part of this thread
  31. self.thread = threading.Thread(target=self.run)
  32. # start the thread part of this thread!
  33. self.thread.start()
  34. def kill(self):
  35. """
  36. Requests this thread to be teriminated by activating the self.kill_flag flag.
  37. (This effectively stops self.run() from running)
  38. """
  39. self.kill_flag = True
  40. def join(self):
  41. """
  42. Wait for this thread to finish and merge it.
  43. """
  44. self.thread.join()
  45. def export_emoji(self, emoji, emoji_svg, f, path, license):
  46. """
  47. Runs a single export batch.
  48. """
  49. final_path = dest_paths.format_path(path, emoji, f)
  50. # try to make the directory for this particular export batch.
  51. dest_paths.make_dir_structure_for_file(final_path)
  52. # svg format doesn't involve a resolution so it can go straight to export.
  53. if f == 'svg':
  54. svg_license = license.get(util.get_license_type_for_format(f))
  55. export_task.to_svg(emoji_svg, final_path, self.name, svg_license, self.license_enabled, optimise=False)
  56. else:
  57. # any format other than svg is a raster, therefore it needs
  58. # to have a number separated by a dash.
  59. raster_format = f.split("-")
  60. try:
  61. size = int(raster_format[1])
  62. except ValueError:
  63. self.err = Exception(f"""A format you gave ('{f}') isn't correct. All formats
  64. that aren't svg must have a number separated by a dash.
  65. (ie 'png-32', 'webp-128')""")
  66. # now the size has been retrieved, try image
  67. # conversion based on the format.
  68. if raster_format[0] == "png":
  69. export_task.to_raster(emoji_svg, final_path, self.renderer, "png", size, self.name)
  70. elif raster_format[0] == "pngc":
  71. export_task.to_raster(emoji_svg, final_path, self.renderer, "pngc", size, self.name)
  72. elif raster_format[0] == "webp":
  73. export_task.to_raster(emoji_svg, final_path, self.renderer, "webp", size, self.name)
  74. elif raster_format[0] == "jxl":
  75. export_task.to_raster(emoji_svg, final_path, self.renderer, "jxl", size, self.name)
  76. else:
  77. self.err = Exception(f"""A format you gave ('{f}') uses a file format
  78. ('{raster_format[0]}') that orxporter
  79. doesn't support.""")
  80. def run(self):
  81. """
  82. The process of getting and executing a single export task in
  83. the queue.
  84. This is what the actual thread part of this class is tasked
  85. with working on.
  86. """
  87. try:
  88. # basically: do stuff as long as it's not requested to
  89. # be killed by the class
  90. while not self.kill_flag:
  91. # try to get an item from the queue.
  92. # break the loop if nothing is left.
  93. try:
  94. i, (emoji, formats) = self.queue.get_nowait()
  95. except queue.Empty:
  96. break
  97. # compose the file path of the emoji.
  98. dest_paths.format_path(self.path, emoji, 'svg')
  99. # check if the src attribute is in the emoji.
  100. # if so, make a proper path out of it.
  101. if 'src' not in emoji:
  102. raise ValueError('Missing src attribute')
  103. srcpath = os.path.join(self.m.homedir, self.input_path,
  104. emoji['src'])
  105. # load the SVG source file
  106. try:
  107. emoji_svg = open(srcpath, 'r').read()
  108. except Exception:
  109. raise ValueError('Could not load file: ' + srcpath)
  110. # convert colormaps (if applicable)
  111. if 'color' in emoji:
  112. pfrom, pto = util.get_color_palettes(emoji, self.m)
  113. emoji_svg = svg.translate_color(emoji_svg, pfrom, pto)
  114. # for each format in the emoji, export it as that
  115. for f in formats:
  116. self.export_emoji(emoji, emoji_svg, f, self.path,
  117. self.m.license)
  118. # tell the progress bar that this task has been completed.
  119. log.export_task_count += 1
  120. except Exception as e:
  121. self.err = e