You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

130 lines
5.2 KiB

  1. import os
  2. # import hashlib
  3. from calculate.utils.files import Process, join_paths
  4. from calculate.templates.format.base_format import FormatError
  5. from typing import NoReturn, Union, List, Tuple, Optional
  6. class ImageMagickError(FormatError):
  7. pass
  8. class ImageMagick:
  9. def __init__(self, chroot: str = '/'):
  10. self._chroot_path: str = chroot
  11. self.init_commands(chroot)
  12. self.default_opts: List[str] = []
  13. @property
  14. def available(self) -> bool:
  15. return bool(self.convert_cmd and self.identify_cmd)
  16. @property
  17. def chrooted(self) -> bool:
  18. return self._chroot_path != '/'
  19. def init_commands(self, chroot: str) -> NoReturn:
  20. self.convert_cmd: str = "/usr/bin/convert"
  21. self.identify_cmd: str = "/usr/bin/identify"
  22. self.chroot_cmd: str = "/bin/chroot"
  23. self.bash_cmd: str = "/bin/bash"
  24. if not os.path.exists(join_paths(chroot, self.convert_cmd)):
  25. self.convert_cmd = None
  26. if not os.path.exists(join_paths(chroot, self.identify_cmd)):
  27. self.identify_cmd = None
  28. def trim_prefix_path(self, filename: str) -> Union[str, None]:
  29. retpath = "/{}".format(os.path.relpath(filename, self._chroot_path))
  30. if retpath.startswith("/.."):
  31. return None
  32. return retpath
  33. def get_image_resolution(self, source: str
  34. ) -> Union[None, Tuple[int, int]]:
  35. '''Метод для получения разрешения указанного изображения,
  36. с помощью команды 'identify -format %w %h <path_to_image>'.'''
  37. if self.chrooted:
  38. identify = Process(self.chroot_cmd, self._chroot_path,
  39. self.bash_cmd, "-c",
  40. " ".join([self.identify_cmd,
  41. "-format '%w %h'", source]))
  42. else:
  43. identify = Process(self.identify_cmd, "-format", "%w %h", source)
  44. if identify.success():
  45. result = identify.read()
  46. swidth, sheight = result.split(" ")
  47. if swidth.isdigit() and sheight.isdigit():
  48. return int(swidth), int(sheight)
  49. else:
  50. raise ImageMagickError(f"Can not parse: '{result}'")
  51. else:
  52. raise ImageMagickError(identify.read_error())
  53. def convert(self, source: str, target: str, *opts: List[str],
  54. image_format: Optional[str] = None) -> bool:
  55. command = [self.convert_cmd, "-quality", "95",
  56. source]
  57. command.extend(self.default_opts)
  58. command.extend(opts)
  59. if image_format is not None:
  60. command.append(f"{image_format}:{target}")
  61. else:
  62. command.append(target)
  63. if self.chrooted:
  64. convert = Process(self.chroot_cmd, self._chroot_path,
  65. self.bash_cmd, "-c",
  66. " ".join(command))
  67. else:
  68. convert = Process(*command)
  69. if convert.success():
  70. return True
  71. else:
  72. raise ImageMagickError(convert.read_error())
  73. def convert_resize_crop_center(self, source: str, target: str,
  74. height: int, width: int,
  75. image_format: Optional[str] = None) -> bool:
  76. # if ((width == self.source_width and height == self.source_height) and
  77. # (source.rpartition('.')[2] == target.rpartition('.')[2])):
  78. # with write_file(target) as sf:
  79. # sf.write(read_file(source))
  80. # return True
  81. res = f"{width}x{height}"
  82. return self.convert(source, target, "-quality", "95",
  83. "-resize", f"{res}^",
  84. "-strip", "-gravity", "center",
  85. "-crop", f"{res}+0+0",
  86. image_format=image_format)
  87. def convert_resize_gfxboot(self, source: str, target: str,
  88. height: int, width: int,
  89. image_format: Optional[str] = None) -> bool:
  90. res = f"{width}x{height}"
  91. return self.convert(source, target, "-quality", "95",
  92. "-resize", f"{res}^",
  93. "-strip", "-gravity", "center",
  94. "-crop", f"{res}+0+0",
  95. "-sampling-factor", "2x2",
  96. "-interlace", "none",
  97. "-set", "units", "PixelsPerSecond",
  98. image_format=image_format)
  99. def get_image_format(self, source: str) -> str:
  100. """Метод для получения формата указанного файла."""
  101. if self.chrooted:
  102. identify = Process(self.chroot_cmd, self._chroot_path,
  103. self.bash_cmd, "-c",
  104. " ".join([self.identify_cmd,
  105. "-format '%m'", source]))
  106. else:
  107. identify = Process(self.identify_cmd, "-format", "%m", source)
  108. if identify.success():
  109. image_format = identify.read()
  110. return image_format
  111. else:
  112. raise ImageMagickError(f"{identify.read_error()}")