PageRenderTime 43ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

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

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