{"id":18782881,"url":"https://github.com/rescript-react-native/image-editor","last_synced_at":"2025-09-09T07:34:27.044Z","repository":{"id":40724683,"uuid":"252497925","full_name":"rescript-react-native/image-editor","owner":"rescript-react-native","description":"ReScript bindings for @react-native-community/image-editor","archived":false,"fork":false,"pushed_at":"2023-02-09T07:14:32.000Z","size":961,"stargazers_count":1,"open_issues_count":3,"forks_count":1,"subscribers_count":4,"default_branch":"main","last_synced_at":"2025-02-07T23:16:13.250Z","etag":null,"topics":["image-editor","react","react-native","rescript","rescript-react","rescript-react-native"],"latest_commit_sha":null,"homepage":"","language":"ReScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/rescript-react-native.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2020-04-02T15:44:05.000Z","updated_at":"2024-02-19T01:24:11.000Z","dependencies_parsed_at":"2023-07-18T14:30:14.657Z","dependency_job_id":null,"html_url":"https://github.com/rescript-react-native/image-editor","commit_stats":{"total_commits":20,"total_committers":3,"mean_commits":6.666666666666667,"dds":0.09999999999999998,"last_synced_commit":"4bee6c6b9d62614e7a4ee54ea045b93d8965ab20"},"previous_names":["reason-react-native/image-editor"],"tags_count":3,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rescript-react-native%2Fimage-editor","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rescript-react-native%2Fimage-editor/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rescript-react-native%2Fimage-editor/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rescript-react-native%2Fimage-editor/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rescript-react-native","download_url":"https://codeload.github.com/rescript-react-native/image-editor/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":239699581,"owners_count":19682574,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["image-editor","react","react-native","rescript","rescript-react","rescript-react-native"],"created_at":"2024-11-07T20:37:22.646Z","updated_at":"2025-02-19T17:13:08.767Z","avatar_url":"https://github.com/rescript-react-native.png","language":"ReScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# `@rescript-react-native/image-editor`\n\n[![Build Status](https://github.com/rescript-react-native/image-editor/workflows/Build/badge.svg)](https://github.com/rescript-react-native/image-editor/actions)\n[![Version](https://img.shields.io/npm/v/@rescript-react-native/image-editor.svg)](https://www.npmjs.com/@rescript-react-native/image-editor)\n[![ReScript Forum](https://img.shields.io/discourse/posts?color=e6484f\u0026label=ReScript%20Forum\u0026server=https%3A%2F%2Fforum.rescript-lang.org)](https://forum.rescript-lang.org/)\n\n[ReScript](https://rescript-lang.org) bindings for\n[`@react-native-community/image-editor`](https://github.com/react-native-image-editor/react-native-image-editor).\n\nExposed as `ReactNativeImageEditor` module.\n\n`@rescript-react-native/image-editor` X.y.\\* means it's compatible with\n`@react-native-community/image-editor` X.y.\\*\n\n## Installation\n\nWhen\n[`@react-native-community/image-editor`](https://github.com/react-native-image-editor/react-native-image-editor)\nis properly installed \u0026 configured by following their installation instructions,\nyou can install the bindings:\n\n```console\nnpm install @rescript-react-native/image-editor\n# or\nyarn add @rescript-react-native/image-editor\n```\n\n`@rescript-react-native/image-editor` should be added to `bs-dependencies` in your\n`bsconfig.json`:\n\n```diff\n{\n  //...\n  \"bs-dependencies\": [\n    \"@rescript/react\",\n    \"rescript-react-native\",\n    // ...\n+    \"@rescript-react-native/image-editor\"\n  ],\n  //...\n}\n```\n\n## Methods\n\n### `cropImage`\n\n`cropImage` takes arguments of type `source` and `cropData` and, if the image is\nsuccessfully cropped, returns path of the resulting image as a `string`, wrapped\nin a Promise. If a remote image cannot be downloaded or an image cannot be\ncropped, the Promise will be rejected.\n\n```rescript\ncropImage: (source, cropData) =\u003e Js.Promise.t(string)\n```\n\n### `fromRequired`\n\nTo convert a `ReactNative.Packager.required` object into [`source`](#source).\n\n```rescript\nfromRequired: ReactNative.Packager.required =\u003e source\n```\n\n### `fromUriSource`\n\nTo convert a URI given as a `string` into [`source`](#source).\n\n```rescript\nfromUriSource: string =\u003e source\n```\n\n## Types\n\n### `source`\n\nAn abstract type created using the [`fromRequired`](#fromrequired) and\n[`fromUriSource`](#fromurisource) methods.\n\n### `offset`\n\nAn abstract type created using the constructor of the same name which takes\nnamed arguments `x` and `y` of type `int`.\n\n```rescript\noffset: (~x: int, ~y: int) =\u003e offset\n```\n\n### `size`\n\nAn abstract type created using the constructor of the same name which takes\nnamed arguments `width` and `height` of type `int`.\n\n```rescript\nsize: (~width: int, ~height: int) =\u003e size\n```\n\n### `cropData`\n\nAn abstract type created using the constructor of the same name which takes\nnamed arguments `offset` (of type `offset`) and `size` (of type `size`) and\noptional arguments `displaySize` (of type `size`) and `resizeMode` (one of\npolymorphic variants `` `contain ``, `` `cover ``, `` `stretch ``).\n\n```rescript\ncropData: (\n  ~offset: offset,\n  ~size: size,\n  ~displaySize: size=?,\n  ~resizeMode=[ | `contain | `cover | `stretch]=?,\n  unit\n) =\u003e cropData\n```\n\n## Example\n\n```rescript\nopen ReactNative;\n\n// hardcoding actual image dimensions\nlet imageWidth = 3396.;\nlet imageHeight = 2388.;\n\nlet windowWidth = Dimensions.get(`window)##width;\nlet windowHeight = Dimensions.get(`window)##height;\n\nlet displayWidth = windowWidth *. 0.9;\nlet displayHeight = windowWidth *. 0.9 *. imageHeight /. imageWidth;\n\nlet styles =\n  Style.(\n    StyleSheet.create({\n      \"container\":\n        style(\n          ~width=windowWidth-\u003edp,\n          ~height=windowHeight-\u003edp,\n          ~flexDirection=`column,\n          ~alignItems=`center,\n          ~justifyContent=`center,\n          (),\n        ),\n      \"frame\":\n        style(\n          ~width=displayWidth-\u003edp,\n          ~height=displayHeight-\u003edp,\n          ~alignItems=`center,\n          ~justifyContent=`center,\n          ~borderWidth=StyleSheet.hairlineWidth,\n          (),\n        ),\n    })\n  );\n\ntype state = {\n  path: option(string),\n  imageLoaded: bool,\n};\n\ntype action =\n  | SetPath(option(string))\n  | SetImageLoaded;\n\nlet imageUri = \"https://images.unsplash.com/photo-1520453803296-c39eabe2dab4\";\nlet uri = ReactNativeImageEditor.fromUriSource(imageUri);\n\nlet handleCropImage = (cropData, send, handler) =\u003e\n\tJs.Promise.(\n\t\tReactNativeImageEditor.cropImage(uri, cropData)\n\t\t|\u003e then_(successURI =\u003e resolve(send(handler(successURI))))\n    |\u003e catch(err =\u003e resolve(Js.Console.warn(err)))\n    |\u003e ignore\n  );\n\n[@react.component]\nlet make = () =\u003e {\n  let (state, dispatch) =\n    React.useReducer(\n      (state, action) =\u003e\n        switch (action) {\n        | SetPath(p) =\u003e {...state, path: p}\n        | SetImageLoaded =\u003e {...state, imageLoaded: true}\n        },\n      {path: None, imageLoaded: false},\n    );\n\n  let size =\n    ReactNativeImageEditor.size(\n      ~width=(imageWidth *. 0.5)-\u003efloor-\u003etruncate,\n      ~height=(imageHeight *. 0.5)-\u003efloor-\u003etruncate,\n    );\n\n  let cropData = offset =\u003e\n    ReactNativeImageEditor.cropData(\n      ~offset,\n      ~size,\n      ~resizeMode=`cover,\n      (),\n    );\n\n  \u003cView style=styles##container\u003e\n      \u003cText\u003e\n        \"Click on a quadrant of the image to crop it.\"-\u003eReact.string\n      \u003c/Text\u003e\n      \u003cView style=styles##frame\u003e\n        \u003cTouchableOpacity\n          onPress={e =\u003e\n            handleCropImage(\n              ReactNativeImageEditor.offset(\n                ~x=\n                  {e##nativeEvent##locationX /. displayWidth \u003c 0.5\n                     ? 0 : (0.5 *. imageWidth)-\u003efloor-\u003etruncate},\n                ~y=\n                  {e##nativeEvent##locationY /. displayHeight \u003c 0.5\n                     ? 0 : (0.5 *. imageHeight)-\u003efloor-\u003etruncate},\n              )\n              -\u003ecropData,\n              dispatch,\n              link =\u003e\n              SetPath(Some(link))\n            )\n          }\u003e\n          \u003cImage\n            source={Image.Source.fromUriSource(\n              Image.uriSource(\n                ~uri=\n                  Belt.Option.getWithDefault(\n                    state.path,\n                    imageUri,\n                  ),\n                ~width=displayWidth,\n                ~height=\n                  if (state.imageLoaded) {\n                    displayHeight;\n                  } else {\n                    0.;\n                  },\n                (),\n              ),\n            )}\n            resizeMode=`contain\n            onLoadEnd={() =\u003e dispatch(SetImageLoaded)}\n          /\u003e\n        \u003c/TouchableOpacity\u003e\n        {state.imageLoaded\n           ? React.null\n           : \u003cText\u003e \"Please wait while image is loaded.\"-\u003eReact.string \u003c/Text\u003e}\n      \u003c/View\u003e\n      \u003cButton title=\"Reset Image\" onPress={_ =\u003e dispatch(SetPath(None))} /\u003e\n    \u003c/View\u003e;\n};\n```\n\n---\n\n## Changelog\n\nCheck the [changelog](./CHANGELOG.md) for more informations about recent\nreleases.\n\n---\n\n## Contribute\n\nRead the\n[contribution guidelines](https://github.com/rescript-react-native/.github/blob/master/CONTRIBUTING.md)\nbefore contributing.\n\n## Code of Conduct\n\nWe want this community to be friendly and respectful to each other. Please read\n[our full code of conduct](https://github.com/rescript-react-native/.github/blob/master/CODE_OF_CONDUCT.md)\nso that you can understand what actions will and will not be tolerated.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frescript-react-native%2Fimage-editor","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frescript-react-native%2Fimage-editor","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frescript-react-native%2Fimage-editor/lists"}