{"id":13427884,"url":"https://github.com/minimagick/minimagick","last_synced_at":"2025-05-12T05:30:28.871Z","repository":{"id":385419,"uuid":"2727","full_name":"minimagick/minimagick","owner":"minimagick","description":"mini replacement for RMagick","archived":false,"fork":false,"pushed_at":"2025-03-21T12:57:02.000Z","size":3765,"stargazers_count":2852,"open_issues_count":2,"forks_count":349,"subscribers_count":47,"default_branch":"master","last_synced_at":"2025-05-11T10:49:42.712Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://rubydoc.info/gems/mini_magick","language":"Ruby","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/minimagick.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"MIT-LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2008-03-06T01:35:38.000Z","updated_at":"2025-05-10T21:50:17.000Z","dependencies_parsed_at":"2024-05-31T09:36:05.001Z","dependency_job_id":"76b95379-99c3-4901-8c33-c9691630003c","html_url":"https://github.com/minimagick/minimagick","commit_stats":{"total_commits":688,"total_committers":124,"mean_commits":5.548387096774194,"dds":0.5959302325581395,"last_synced_commit":"67378773d5b1ccfafc64a1e9d126116ef90dac18"},"previous_names":[],"tags_count":62,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/minimagick%2Fminimagick","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/minimagick%2Fminimagick/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/minimagick%2Fminimagick/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/minimagick%2Fminimagick/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/minimagick","download_url":"https://codeload.github.com/minimagick/minimagick/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253568691,"owners_count":21928909,"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":[],"created_at":"2024-07-31T01:00:41.924Z","updated_at":"2025-05-12T05:30:28.838Z","avatar_url":"https://github.com/minimagick.png","language":"Ruby","readme":"# MiniMagick\n[![Gem Version](https://img.shields.io/gem/v/mini_magick.svg)](http://rubygems.org/gems/mini_magick)\n[![Gem Downloads](https://img.shields.io/gem/dt/mini_magick.svg)](http://rubygems.org/gems/mini_magick)\n[![CI](https://github.com/minimagick/minimagick/actions/workflows/ci.yml/badge.svg)](https://github.com/minimagick/minimagick/actions/workflows/ci.yml)\n[![Code Climate](https://codeclimate.com/github/minimagick/minimagick/badges/gpa.svg)](https://codeclimate.com/github/minimagick/minimagick)\n\nA ruby wrapper for [ImageMagick](http://imagemagick.org/) command line.\n\n## Why?\n\nI was using [RMagick](https://github.com/rmagick/rmagick) and loving it, but it\nwas eating up huge amounts of memory. Even a simple script would use over 100MB\nof RAM. On my local machine this wasn't a problem, but on my hosting server the\nruby apps would crash because of their 100MB memory limit.\n\n## Solution!\n\nUsing MiniMagick the ruby processes memory remains small (it spawns\nImageMagick's command line program mogrify which takes up some memory as well,\nbut is much smaller compared to RMagick). See [Thinking of switching from\nRMagick?](#thinking-of-switching-from-rmagick) below.\n\nMiniMagick gives you access to all the command line options ImageMagick has\n(found [here](http://www.imagemagick.org/script/command-line-options.php)).\n\n## Requirements\n\nImageMagick command-line tool has to be installed. You can check if you have it\ninstalled by running\n\n```sh\n$ magick -version\nVersion: ImageMagick 7.1.1-33 Q16-HDRI aarch64 22263 https://imagemagick.org\nCopyright: (C) 1999 ImageMagick Studio LLC\nLicense: https://imagemagick.org/script/license.php\nFeatures: Cipher DPC HDRI Modules OpenMP(5.0)\nDelegates (built-in): bzlib fontconfig freetype gslib heic jng jp2 jpeg jxl lcms lqr ltdl lzma openexr png ps raw tiff webp xml zlib zstd\nCompiler: gcc (4.2)\n```\n\n## Installation\n\nAdd the gem to your Gemfile:\n\n```sh\n$ bundle add mini_magick\n```\n\n## Information\n\n* [API documentation](https://rubydoc.info/gems/mini_magick)\n\n## Usage\n\nLet's first see a basic example of resizing an image.\n\n```rb\nrequire \"mini_magick\"\n\nimage = MiniMagick::Image.open(\"input.jpg\")\nimage.path #=\u003e \"/var/folders/k7/6zx6dx6x7ys3rv3srh0nyfj00000gn/T/magick20140921-75881-1yho3zc.jpg\"\nimage.resize \"100x100\"\nimage.format \"png\"\nimage.write \"output.png\"\n```\n\n`MiniMagick::Image.open` makes a copy of the image, and further methods modify\nthat copy (the original stays untouched). We then\n[resize](http://www.imagemagick.org/script/command-line-options.php#resize)\nthe image, and write it to a file. The writing part is necessary because\nthe copy is just temporary, it gets garbage collected when we lose reference\nto the image.\n\n`MiniMagick::Image.open` also accepts URLs, and options passed in will be\nforwarded to [open-uri](https://github.com/ruby/open-uri).\n\n```rb\nimage = MiniMagick::Image.open(\"http://example.com/image.jpg\")\nimage.contrast\nimage.write(\"from_internets.jpg\")\n```\n\nOn the other hand, if we want the original image to actually *get* modified,\nwe can use `MiniMagick::Image.new`.\n\n```rb\nimage = MiniMagick::Image.new(\"input.jpg\")\nimage.path #=\u003e \"input.jpg\"\nimage.resize \"100x100\"\n# Not calling #write, because it's not a copy\n```\n\n### Combine options\n\nWhile using methods like `#resize` directly is convenient, if we use more\nmethods in this way, it quickly becomes inefficient, because it calls the\ncommand on each methods call. `MiniMagick::Image#combine_options` takes\nmultiple options and from them builds one single command.\n\n```rb\nimage.combine_options do |b|\n  b.resize \"250x200\u003e\"\n  b.rotate \"-90\"\n  b.flip\nend # the command gets executed\n```\n\nAs a handy shortcut, `MiniMagick::Image.new` also accepts an optional block\nwhich is used to `combine_options`.\n\n```rb\nimage = MiniMagick::Image.new(\"input.jpg\") do |b|\n  b.resize \"250x200\u003e\"\n  b.rotate \"-90\"\n  b.flip\nend # the command gets executed\n```\n\nThe yielded builder is an instance of `MiniMagick::Tool`. To learn more\nabout its interface, see [Tools](#tools) below.\n\n### Attributes\n\nA `MiniMagick::Image` has various handy attributes.\n\n```rb\nimage.type        #=\u003e \"JPEG\"\nimage.width       #=\u003e 250\nimage.height      #=\u003e 300\nimage.dimensions  #=\u003e [250, 300]\nimage.size        #=\u003e 3451 (in bytes)\nimage.colorspace  #=\u003e \"DirectClass sRGB\"\nimage.exif        #=\u003e {\"DateTimeOriginal\" =\u003e \"2013:09:04 08:03:39\", ...}\nimage.resolution  #=\u003e [75, 75]\nimage.signature   #=\u003e \"60a7848c4ca6e36b8e2c5dea632ecdc29e9637791d2c59ebf7a54c0c6a74ef7e\"\n```\n\nIf you need more control, you can also access [raw image\nattributes](http://www.imagemagick.org/script/escape.php):\n\n```rb\nimage[\"%[gamma]\"] # \"0.9\"\n```\n\nTo get the all information about the image, MiniMagick gives you a handy method\nwhich returns the output from `magick input.jpg json:`:\n\n```rb\nimage.data #=\u003e\n# {\n#   \"format\": \"JPEG\",\n#   \"mimeType\": \"image/jpeg\",\n#   \"class\": \"DirectClass\",\n#   \"geometry\": {\n#     \"width\": 200,\n#     \"height\": 276,\n#     \"x\": 0,\n#     \"y\": 0\n#   },\n#   \"resolution\": {\n#     \"x\": \"300\",\n#     \"y\": \"300\"\n#   },\n#   \"colorspace\": \"sRGB\",\n#   \"channelDepth\": {\n#     \"red\": 8,\n#     \"green\": 8,\n#     \"blue\": 8\n#   },\n#   \"quality\": 92,\n#   \"properties\": {\n#     \"date:create\": \"2016-07-11T19:17:53+08:00\",\n#     \"date:modify\": \"2016-07-11T19:17:53+08:00\",\n#     \"exif:ColorSpace\": \"1\",\n#     \"exif:ExifImageLength\": \"276\",\n#     \"exif:ExifImageWidth\": \"200\",\n#     \"exif:ExifOffset\": \"90\",\n#     \"exif:Orientation\": \"1\",\n#     \"exif:ResolutionUnit\": \"2\",\n#     \"exif:XResolution\": \"300/1\",\n#     \"exif:YResolution\": \"300/1\",\n#     \"icc:copyright\": \"Copyright (c) 1998 Hewlett-Packard Company\",\n#     \"icc:description\": \"sRGB IEC61966-2.1\",\n#     \"icc:manufacturer\": \"IEC http://www.iec.ch\",\n#     \"icc:model\": \"IEC 61966-2.1 Default RGB colour space - sRGB\",\n#     \"jpeg:colorspace\": \"2\",\n#     \"jpeg:sampling-factor\": \"1x1,1x1,1x1\",\n#     \"signature\": \"1b2336f023e5be4a9f357848df9803527afacd4987ecc18c4295a272403e52c1\"\n#   },\n#   ...\n# }\n```\n\n### Pixels\n\nWith MiniMagick you can retrieve a matrix of image pixels, where each member of\nthe matrix is a 3-element array of numbers between 0-255, one for each range of\nthe RGB color channels.\n\n```rb\nimage = MiniMagick::Image.open(\"image.jpg\")\npixels = image.get_pixels\npixels[3][2][1] # the green channel value from the 4th-row, 3rd-column pixel\n```\n\nIt can also be called after applying transformations:\n\n```rb\nimage = MiniMagick::Image.open(\"image.jpg\")\nimage.crop \"20x30+10+5\"\nimage.colorspace \"Gray\"\npixels = image.get_pixels\n```\n\n### Pixels To Image\n\nSometimes when you have pixels and want to create image from pixels, you can do this to form an image:\n\n```rb\nimage = MiniMagick::Image.open('/Users/rabin/input.jpg')\npixels = image.get_pixels\ndepth = 8\ndimension = [image.width, image.height]\nmap = 'rgb'\nimage = MiniMagick::Image.get_image_from_pixels(pixels, dimension, map, depth ,'jpg')\nimage.write('/Users/rabin/output.jpg')\n```\n\nIn this example, the returned pixels should now have equal R, G, and B values.\n\n### Configuration\n\nHere are the available configuration options with their default values:\n\n```rb\nMiniMagick.configure do |config|\n  config.timeout = nil # number of seconds IM commands may take\n  config.errors = true # raise errors non nonzero exit status\n  config.warnings = true # forward warnings to standard error\n  config.tmdir = Dir.tmpdir # alternative directory for tempfiles\n  config.logger = Logger.new($stdout) # where to log IM commands\n  config.cli_prefix = nil # add prefix to all IM commands\n  config.cli_env = {} # environment variables to set for IM commands\n  config.restricted_env = false # when true, block IM commands from accessing system environment variables other than those in cli_env\nend\n```\n\nFor a more information, see\n[Configuration](https://rubydoc.info/gems/mini_magick/MiniMagick/Configuration) API documentation.\n\n### Composite\n\nMiniMagick also allows you to\n[composite](http://www.imagemagick.org/script/composite.php) images:\n\n```rb\nfirst_image  = MiniMagick::Image.new(\"first.jpg\")\nsecond_image = MiniMagick::Image.new(\"second.jpg\")\nresult = first_image.composite(second_image) do |c|\n  c.compose \"Over\"    # OverCompositeOp\n  c.geometry \"+20+20\" # copy second_image onto first_image from (20, 20)\nend\nresult.write \"output.jpg\"\n```\n\n### Layers/Frames/Pages\n\nFor multilayered images you can access its layers.\n\n```rb\ngif.frames #=\u003e [...]\npdf.pages  #=\u003e [...]\npsd.layers #=\u003e [...]\n\ngif.frames.each_with_index do |frame, idx|\n  frame.write(\"frame#{idx}.jpg\")\nend\n```\n\n### Image validation\n\nYou can test whether an image is valid by running it through `identify`:\n\n```rb\nimage.valid?\nimage.validate! # raises MiniMagick::Invalid if image is invalid\n```\n\n### Logging\n\nYou can choose to log MiniMagick commands and their execution times:\n\n```rb\nMiniMagick.logger.level = Logger::DEBUG\n```\n```\nD, [2016-03-19T07:31:36.755338 #87191] DEBUG -- : [0.01s] identify /var/folders/k7/6zx6dx6x7ys3rv3srh0nyfj00000gn/T/mini_magick20160319-87191-1ve31n1.jpg\n```\n\nIn Rails you'll probably want to set `MiniMagick.logger = Rails.logger`.\n\n## Tools\n\nIf you prefer not to use the `MiniMagick::Image` abstraction, you can use ImageMagick's command-line tools directly:\n\n```rb\nMiniMagick.convert do |convert|\n  convert \u003c\u003c \"input.jpg\"\n  convert.resize(\"100x100\")\n  convert.negate\n  convert \u003c\u003c \"output.jpg\"\nend #=\u003e `magick input.jpg -resize 100x100 -negate output.jpg`\n\n# OR\n\nconvert = MiniMagick.convert\nconvert \u003c\u003c \"input.jpg\"\nconvert.resize(\"100x100\")\nconvert.negate\nconvert \u003c\u003c \"output.jpg\"\nconvert.call #=\u003e `magick input.jpg -resize 100x100 -negate output.jpg`\n```\n\nThis way of using MiniMagick is highly recommended if you want to maximize performance of your image processing. There are class methods for each CLI tool: `animate`, `compare`, `composite`, `conjure`, `convert`, `display`, `identify`, `import`, `mogrify` and `stream`. The `MiniMagick.convert` method will use `magick` on ImageMagick 7 and `convert` on ImageMagick 6.\n\n### Appending\n\nThe most basic way of building a command is appending strings:\n\n```rb\nMiniMagick.convert do |convert|\n  convert \u003c\u003c \"input.jpg\"\n  convert.merge! [\"-resize\", \"500x500\", \"-negate\"]\n  convert \u003c\u003c \"output.jpg\"\nend\n```\n\nNote that it is important that every command you would pass to the command line\nhas to be separated with `\u003c\u003c`, e.g.:\n\n```rb\n# GOOD\nconvert \u003c\u003c \"-resize\" \u003c\u003c \"500x500\"\n\n# BAD\nconvert \u003c\u003c \"-resize 500x500\"\n```\n\nShell escaping is also handled for you. If an option has a value that has\nspaces inside it, just pass it as a regular string.\n\n```rb\nconvert \u003c\u003c \"-distort\"\nconvert \u003c\u003c \"Perspective\"\nconvert \u003c\u003c \"0,0,0,0 0,45,0,45 69,0,60,10 69,45,60,35\"\n```\n```\nmagick -distort Perspective '0,0,0,0 0,45,0,45 69,0,60,10 69,45,60,35'\n```\n\n### Methods\n\nInstead of passing in options directly, you can use Ruby methods:\n\n```rb\nconvert.resize(\"500x500\")\nconvert.rotate(90)\nconvert.distort(\"Perspective\", \"0,0,0,0 0,45,0,45 69,0,60,10 69,45,60,35\")\n```\n\n### Chaining\n\nEvery method call returns `self`, so you can chain them to create logical groups.\n\n```rb\nMiniMagick.convert do |convert|\n  convert \u003c\u003c \"input.jpg\"\n  convert.clone(0).background('gray').shadow('80x5+5+5')\n  convert.negate\n  convert \u003c\u003c \"output.jpg\"\nend\n```\n\n### \"Plus\" options\n\n```rb\nMiniMagick.convert do |convert|\n  convert \u003c\u003c \"input.jpg\"\n  convert.repage.+\n  convert.distort.+(\"Perspective\", \"more args\")\nend\n```\n```\nmagick input.jpg +repage +distort Perspective 'more args'\n```\n\n### Stacks\n\n```rb\nMiniMagick.convert do |convert|\n  convert \u003c\u003c \"wand.gif\"\n\n  convert.stack do |stack|\n    stack \u003c\u003c \"wand.gif\"\n    stack.rotate(30)\n    stack.foo(\"bar\", \"baz\")\n  end\n  # or\n  convert.stack(\"wand.gif\", { rotate: 30, foo: [\"bar\", \"baz\"] })\n\n  convert \u003c\u003c \"images.gif\"\nend\n```\n```\nmagick wand.gif \\( wand.gif -rotate 90 -foo bar baz \\) images.gif\n```\n\n### STDIN and STDOUT\n\nIf you want to pass something to standard input, you can pass the `:stdin`\noption to `#call`:\n\n```rb\nidentify = MiniMagick.identify\nidentify.stdin # alias for \"-\"\nidentify.call(stdin: image_content)\n```\n\nMiniMagick also has `#stdout` alias for \"-\" for outputting file contents to\nstandard output:\n\n```rb\ncontent = MiniMagick.convert do |convert|\n  convert \u003c\u003c \"input.jpg\"\n  convert.auto_orient\n  convert.stdout # alias for \"-\"\nend\n```\n\n### Capturing STDERR\n\nSome MiniMagick tools such as `compare` output the result of the command on\nstandard error, even if the command succeeded. The result of\n`MiniMagick::Tool#call` is always the standard output, but if you pass it a\nblock, it will yield the stdout, stderr and exit status of the command:\n\n```rb\ncompare = MiniMagick.compare\n# build the command\ncompare.call do |stdout, stderr, status|\n  # ...\nend\n```\n\n## Configuring\n\n### GraphicsMagick\n\nAs of MiniMagick 5+, [GraphicsMagick](http://www.graphicsmagick.org/) isn't\nofficially supported. This means its installation won't be auto-detected, and no\nattempts will be made to handle differences in GraphicsMagick API or output.\n\nHowever, you can still configure MiniMagick to use it:\n\n```rb\nMiniMagick.configure do |config|\n  config.graphicsmagick = true\nend\n```\n\nSome MiniMagick features won't be supported, such as global timeout,\n`MiniMagick::Image#data` and `MiniMagick::Image#exif`.\n\n### Limiting resources\n\nImageMagick supports a number of [environment variables] for controlling its\nresource limits. For example, you can enforce memory or execution time limits by\nsetting the following:\n\n```rb\nMiniMagick.configure do |config|\n  config.cli_env = {\n    \"MAGICK_MEMORY_LIMIT\" =\u003e \"128MiB\",\n    \"MAGICK_MAP_LIMIT\" =\u003e \"64MiB\",\n    \"MAGICK_TIME_LIMIT\" =\u003e \"30\"\n  }\nend\n```\n\nFor time limit you can also use the `timeout` configuration:\n\n```rb\nMiniMagick.configure do |config|\n  config.timeout = 30 # 30 seconds\nend\n```\n\n### Changing temporary directory\n\nImageMagick allows you to change the temporary directory to process the image file:\n\n```rb\nMiniMagick.configure do |config|\n  config.tmpdir = File.join(Dir.tmpdir, \"/my/new/tmp_dir\")\nend\n```\n\nThe example directory `/my/new/tmp_dir` must exist and must be writable.\n\nIf not configured, it will default to `Dir.tmpdir`.\n\n### Ignoring STDERR\n\nIf you're receiving warnings from ImageMagick that you don't care about, you\ncan avoid them being forwarded to standard error:\n\n```rb\nMiniMagick.configure do |config|\n  config.warnings = false\nend\n```\n\n### Avoiding raising errors\n\nThis gem raises an error when ImageMagick returns a nonzero exit code.\nSometimes, however, ImageMagick returns nonzero exit codes when the command\nactually went ok. In these cases, to avoid raising errors, you can add the\nfollowing configuration:\n\n```rb\nMiniMagick.configure do |config|\n  config.errors = false\nend\n```\n\nYou can also pass `errors: false` to individual commands:\n\n```rb\nMiniMagick.identify(errors: false) do |b|\n  b.help\nend\n```\n\n## Thinking of switching from RMagick?\n\nUnlike RMagick, MiniMagick is a much thinner wrapper around ImageMagick.\n\n* To piece together MiniMagick commands refer to the [Mogrify\n  Documentation](https://imagemagick.org/script/mogrify.php). For instance\n  you can use the `-flop` option as `image.flop`.\n* Operations on a MiniMagick image tend to happen in-place as `image.trim`,\n  whereas RMagick has both copying and in-place methods like `image.trim` and\n  `image.trim!`.\n* To open files with MiniMagick you use `MiniMagick::Image.open` as you would\n  `Magick::Image.read`. To open a file and directly edit it, use\n  `MiniMagick::Image.new`.\n\n[environment variables]: https://imagemagick.org/script/resources.php#environment\n","funding_links":[],"categories":["File Uploading","Graphics","Ruby","Image Processing","Gems","Uncategorized","文件上传","Imagery"],"sub_categories":["Omniauth","Image Processing","Graphics","Uncategorized"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fminimagick%2Fminimagick","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fminimagick%2Fminimagick","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fminimagick%2Fminimagick/lists"}