PageRenderTime 68ms CodeModel.GetById 29ms RepoModel.GetById 1ms app.codeStats 1ms

/hphp/runtime/ext/imagick/ext_imagick.cpp

https://gitlab.com/iranjith4/hhvm
C++ | 358 lines | 279 code | 47 blank | 32 comment | 62 complexity | e61d15e12d9b8306eaeb33229bf1a70b MD5 | raw file
  1. /*
  2. +----------------------------------------------------------------------+
  3. | HipHop for PHP |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 2010-2016 Facebook, Inc. (http://www.facebook.com) |
  6. | Copyright (c) 1997-2010 The PHP Group |
  7. +----------------------------------------------------------------------+
  8. | This source file is subject to version 3.01 of the PHP license, |
  9. | that is bundled with this package in the file LICENSE, and is |
  10. | available through the world-wide-web at the following url: |
  11. | http://www.php.net/license/3_01.txt |
  12. | If you did not receive a copy of the PHP license and are unable to |
  13. | obtain it through the world-wide-web, please send a note to |
  14. | license@php.net so we can mail you a copy immediately. |
  15. +----------------------------------------------------------------------+
  16. */
  17. #include "hphp/runtime/ext/imagick/ext_imagick.h"
  18. #include <vector>
  19. #include "hphp/runtime/base/file.h"
  20. #include "hphp/runtime/ext/std/ext_std_file.h"
  21. using std::pair;
  22. using std::string;
  23. using std::vector;
  24. namespace HPHP {
  25. //////////////////////////////////////////////////////////////////////////////
  26. // PHP Exceptions and Classes
  27. HPHP::Class* ImagickException::cls = nullptr;
  28. HPHP::Class* ImagickDrawException::cls = nullptr;
  29. HPHP::Class* ImagickPixelException::cls = nullptr;
  30. HPHP::Class* ImagickPixelIteratorException::cls = nullptr;
  31. HPHP::Class* Imagick::cls = nullptr;
  32. HPHP::Class* ImagickDraw::cls = nullptr;
  33. HPHP::Class* ImagickPixel::cls = nullptr;
  34. HPHP::Class* ImagickPixelIterator::cls = nullptr;
  35. //////////////////////////////////////////////////////////////////////////////
  36. // IO
  37. bool isMagickPseudoFormat(const String& path, char mode /* = '*' */) {
  38. static const vector<pair<string, string>> pseudoFormats = {
  39. // Pseudo-image Formats
  40. {"CANVAS:", "R"},
  41. {"CAPTION:", "R"},
  42. {"CLIP:", "RW"},
  43. {"CLIPBOARD:", "RW"},
  44. {"FRACTAL:", "R"},
  45. {"GRADIENT:", "R"},
  46. {"HALD:", "R"},
  47. {"HISTOGRAM:", "W"},
  48. {"LABEL:", "R"},
  49. {"MAP:", "RW"},
  50. {"MASK:", "RW"},
  51. {"MATTE:", "W"},
  52. {"NULL:", "RW"},
  53. {"PANGO:", "R"},
  54. {"PLASMA:", "R"},
  55. {"PREVIEW:", "W"},
  56. {"PRINT:", "W"},
  57. {"SCAN:", "R"},
  58. {"RADIAL_GRADIENT:", "R"},
  59. {"SCANX:", "R"},
  60. {"STEGANO:", "R"},
  61. {"TILE:", "R"},
  62. {"UNIQUE:", "W"},
  63. {"VID:", "RW"},
  64. {"WIN:", "RW"},
  65. {"X:", "RW"},
  66. {"XC:", "R"},
  67. // Built-in Images
  68. {"MAGICK:", "R"},
  69. {"GRANITE:", "R"},
  70. {"LOGO:", "R"},
  71. {"NETSCAPE:", "R"},
  72. {"ROSE:", "R"},
  73. // Built-in Patterns
  74. {"PATTERN:", "R"},
  75. };
  76. for (const auto& i: pseudoFormats) {
  77. if (strncasecmp(path.c_str(), i.first.c_str(), i.first.length()) == 0) {
  78. return mode == '*' || i.second.find(mode) != string::npos;
  79. }
  80. }
  81. return false;
  82. }
  83. #define IMAGICK_THROW imagickThrow<ImagickException>
  84. void imagickReadOp(MagickWand* wand,
  85. const String& path,
  86. const ImagickFileOp& op) {
  87. String realpath;
  88. if (isMagickPseudoFormat(path, 'R')) {
  89. realpath = path;
  90. } else {
  91. auto var = HHVM_FN(realpath)(path);
  92. realpath = var.isString() ? var.toString() : String();
  93. if (realpath.empty() ||
  94. !HHVM_FN(is_file)(realpath) ||
  95. !HHVM_FN(is_readable)(realpath)) {
  96. realpath.reset();
  97. }
  98. }
  99. if (realpath.empty()) {
  100. IMAGICK_THROW("Invalid filename provided");
  101. }
  102. auto status = op(wand, path.c_str());
  103. if (status == MagickFalse) {
  104. IMAGICK_THROW("Unable to read image file");
  105. }
  106. MagickSetImageFilename(wand, realpath.c_str());
  107. MagickSetLastIterator(wand);
  108. }
  109. void imagickWriteOp(MagickWand* wand,
  110. const String& path_,
  111. const ImagickFileOp& op) {
  112. String path = path_;
  113. if (path.empty()) {
  114. path = convertMagickString(MagickGetImageFilename(wand));
  115. }
  116. if (path.empty()) {
  117. IMAGICK_THROW("No image filename specified");
  118. }
  119. String realpath;
  120. if (isMagickPseudoFormat(path, 'W')) {
  121. realpath = path;
  122. } else {
  123. static const int PHP_PATHINFO_DIRNAME = 1;
  124. String dirname = HHVM_FN(pathinfo)(path, PHP_PATHINFO_DIRNAME).toString();
  125. if (!HHVM_FN(is_dir)(dirname)) {
  126. // nothing to do here
  127. } else if (!HHVM_FN(is_file)(path)) {
  128. if (HHVM_FN(is_writable)(dirname)) {
  129. realpath = path;
  130. }
  131. } else {
  132. if (HHVM_FN(is_writable)(path)) {
  133. realpath = HHVM_FN(realpath)(path).toString();
  134. }
  135. }
  136. }
  137. if (realpath.empty()) {
  138. IMAGICK_THROW("Invalid filename provided");
  139. }
  140. auto status = op(wand, path.c_str());
  141. if (status == MagickFalse) {
  142. IMAGICK_THROW("Unable to write image file");
  143. }
  144. }
  145. ALWAYS_INLINE
  146. FILE* getFILE(const Resource& res, bool isWrite) {
  147. auto f = dyn_cast_or_null<File>(res);
  148. if (f == nullptr || f->isClosed()) {
  149. IMAGICK_THROW("Invalid stream resource");
  150. }
  151. FILE* fp;
  152. if (isWrite) {
  153. f->flush();
  154. fp = fdopen(dup(f->fd()), "ab");
  155. } else {
  156. fp = fdopen(dup(f->fd()), "rb");
  157. if (fp != nullptr && f->seekable()) {
  158. fseek(fp, f->tell(), SEEK_SET);
  159. }
  160. }
  161. if (fp == nullptr) {
  162. IMAGICK_THROW("Invalid stream resource");
  163. }
  164. return fp;
  165. }
  166. void imagickReadOp(MagickWand* wand,
  167. const Resource& res,
  168. const ImagickHandleOp& op) {
  169. auto fp = getFILE(res, false);
  170. auto status = op(wand, fp);
  171. fclose(fp);
  172. if (status == MagickFalse) {
  173. IMAGICK_THROW("Unable to read image filehandle");
  174. }
  175. }
  176. void imagickWriteOp(MagickWand* wand,
  177. const Resource& res,
  178. const String& format,
  179. const ImagickHandleOp& op) {
  180. auto fp = getFILE(res, true);
  181. // Get the current name
  182. String filename = convertMagickString(MagickGetImageFilename(wand));
  183. if (!format.empty()) {
  184. MagickSetImageFilename(wand, (format + ":").c_str());
  185. }
  186. auto status = op(wand, fp);
  187. fclose(fp);
  188. // Restore the original name after write
  189. if (!format.empty()) {
  190. MagickSetImageFilename(wand, filename.c_str());
  191. }
  192. if (status == MagickFalse) {
  193. IMAGICK_THROW("Unable to write image filehandle");
  194. }
  195. }
  196. #undef IMAGICK_THROW
  197. //////////////////////////////////////////////////////////////////////////////
  198. // Common Helper
  199. void raiseDeprecated(const char* className, const char* methodName) {
  200. raise_deprecated("%s::%s method is deprecated and it's use should be avoided",
  201. className, methodName);
  202. }
  203. void raiseDeprecated(const char* className,
  204. const char* methodName,
  205. const char* newClass,
  206. const char* newMethod) {
  207. raise_deprecated("%s::%s is deprecated. %s::%s should be used instead",
  208. className, methodName, newClass, newMethod);
  209. }
  210. String convertMagickString(char* &&str) {
  211. if (str == nullptr) {
  212. return String();
  213. } else {
  214. String ret(str);
  215. freeMagickMemory(str);
  216. return ret;
  217. }
  218. }
  219. String convertMagickData(size_t size, unsigned char* &data) {
  220. if (data == nullptr) {
  221. return String();
  222. } else {
  223. String ret((char*)data, size, CopyString);
  224. freeMagickMemory(data);
  225. return ret;
  226. }
  227. }
  228. MagickBooleanType withMagickLocaleFix(
  229. const std::function<MagickBooleanType()>& lambda) {
  230. static const char* const IMAGICK_LC_NUMERIC_LOCALE = "C";
  231. if (!ImagickExtension::hasLocaleFix()) {
  232. return lambda();
  233. }
  234. const char* plocale = setlocale(LC_NUMERIC, nullptr);
  235. if (plocale == nullptr) {
  236. return lambda();
  237. }
  238. // Switch the locale to IMAGICK_LC_NUMERIC_LOCALE if imagick.locale_fix is on
  239. const std::string locale = plocale;
  240. setlocale(LC_NUMERIC, IMAGICK_LC_NUMERIC_LOCALE);
  241. auto ret = lambda();
  242. setlocale(LC_NUMERIC, locale.c_str());
  243. return ret;
  244. }
  245. std::vector<double> toDoubleArray(const Array& array) {
  246. std::vector<double> ret;
  247. for (ArrayIter it(array); it; ++it) {
  248. ret.push_back(it.secondRefPlus().toDouble());
  249. }
  250. return ret;
  251. }
  252. std::vector<PointInfo> toPointInfoArray(const Array& coordinates) {
  253. std::vector<PointInfo> ret(coordinates.size());
  254. int idx = 0;
  255. for (ArrayIter it(coordinates); it; ++it) {
  256. const Variant& element = it.secondRefPlus();
  257. if (!element.isArray()) {
  258. return {};
  259. }
  260. const Array& coordinate = element.toCArrRef();
  261. if (coordinate.size() != 2) {
  262. return {};
  263. }
  264. for (ArrayIter jt(coordinate); jt; ++jt) {
  265. const String& key = jt.first().toString();
  266. double value = jt.secondRefPlus().toDouble();
  267. if (key == s_x) {
  268. ret[idx].x = value;
  269. } else if (key == s_y) {
  270. ret[idx].y = value;
  271. } else {
  272. return {};
  273. }
  274. }
  275. ++idx;
  276. }
  277. return ret;
  278. }
  279. //////////////////////////////////////////////////////////////////////////////
  280. // ImagickExtension
  281. ImagickExtension::ImagickExtension() :
  282. Extension("imagick", "3.2.0b2") {
  283. }
  284. void ImagickExtension::moduleInit() {
  285. loadImagickConstants();
  286. loadImagickClass();
  287. loadImagickDrawClass();
  288. loadImagickPixelClass();
  289. loadImagickPixelIteratorClass();
  290. loadSystemlib();
  291. }
  292. void ImagickExtension::threadInit() {
  293. IniSetting::Bind(this, IniSetting::PHP_INI_ALL,
  294. "imagick.locale_fix", "0",
  295. &s_ini_setting->m_locale_fix);
  296. IniSetting::Bind(this, IniSetting::PHP_INI_ALL,
  297. "imagick.progress_monitor", "0",
  298. &s_ini_setting->m_progress_monitor);
  299. }
  300. bool ImagickExtension::hasLocaleFix() {
  301. return s_ini_setting->m_locale_fix;
  302. }
  303. bool ImagickExtension::hasProgressMonitor() {
  304. return s_ini_setting->m_progress_monitor;
  305. }
  306. IMPLEMENT_THREAD_LOCAL(ImagickExtension::ImagickIniSetting,
  307. ImagickExtension::s_ini_setting);
  308. ImagickExtension s_imagick_extension;
  309. HHVM_GET_MODULE(imagick)
  310. //////////////////////////////////////////////////////////////////////////////
  311. } // namespace HPHP