{"id":8565,"date":"2024-01-19T18:30:14","date_gmt":"2024-01-19T18:30:14","guid":{"rendered":"https:\/\/www.satup.xyz\/index.php\/2024\/01\/19\/integrating-the-photoshop-api-with-python-by-raymond-camden\/"},"modified":"2024-01-19T18:30:14","modified_gmt":"2024-01-19T18:30:14","slug":"integrating-the-photoshop-api-with-python-by-raymond-camden","status":"publish","type":"post","link":"https:\/\/www.satup.xyz\/index.php\/2024\/01\/19\/integrating-the-photoshop-api-with-python-by-raymond-camden\/","title":{"rendered":"Integrating the Photoshop API with Python | by Raymond Camden"},"content":{"rendered":"<p><br \/>\n<\/p>\n<div>\n<div>\n<h2 id=\"afe3\" class=\"pw-subtitle-paragraph ho gq gr be b hp hq hr hs ht hu hv hw hx hy hz ia ib ic id cp dt\">How Python can interact with our powerful Photoshop API<\/h2>\n<div class=\"ie if ig ih ii\">\n<div class=\"speechify-ignore ab co\">\n<div class=\"speechify-ignore bg l\">\n<div class=\"ij ik il im in ab\">\n<div>\n<div class=\"ab io\"><a href=\"https:\/\/medium.com\/@cfjedimaster?source=post_page-----859c75e788e4--------------------------------\" rel=\"noopener follow\"><\/p>\n<div>\n<div class=\"bl\" aria-hidden=\"false\">\n<div class=\"l ip iq bx ir is\">\n<div class=\"l fg\"><img loading=\"lazy\" decoding=\"async\" alt=\"Raymond Camden\" class=\"l fa bx dc dd cw\" src=\"https:\/\/miro.medium.com\/v2\/resize:fill:88:88\/1*ldF-FsLonNyTUOmQ7cIV_g.jpeg\" width=\"44\" height=\"44\" loading=\"lazy\" data-testid=\"authorPhoto\"\/><\/div>\n<\/div>\n<\/div>\n<\/div>\n<p><\/a><a href=\"https:\/\/blog.developer.adobe.com\/?source=post_page-----859c75e788e4--------------------------------\" rel=\"noopener  ugc nofollow\"><\/p>\n<div class=\"iv ab fg\">\n<div>\n<div class=\"bl\" aria-hidden=\"false\">\n<div class=\"l iw ix bx ir iy\">\n<div class=\"l fg\"><img loading=\"lazy\" decoding=\"async\" alt=\"Adobe Tech Blog\" class=\"l fa bx bq iz cw\" src=\"https:\/\/miro.medium.com\/v2\/resize:fill:48:48\/1*riyFijvwTfGcWNf1guRNtg.png\" width=\"24\" height=\"24\" loading=\"lazy\" data-testid=\"publicationPhoto\"\/><\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<p><\/a><\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<figure class=\"np nq nr ns nt nu nm nn paragraph-image\">\n<div role=\"button\" tabindex=\"0\" class=\"nv nw fg nx bg ny\">\n<div class=\"nm nn no\"><picture><source srcset=\"https:\/\/miro.medium.com\/v2\/resize:fit:640\/format:webp\/1*X3uTzs55-zrhTgrdb0M7JQ.jpeg 640w, https:\/\/miro.medium.com\/v2\/resize:fit:720\/format:webp\/1*X3uTzs55-zrhTgrdb0M7JQ.jpeg 720w, https:\/\/miro.medium.com\/v2\/resize:fit:750\/format:webp\/1*X3uTzs55-zrhTgrdb0M7JQ.jpeg 750w, https:\/\/miro.medium.com\/v2\/resize:fit:786\/format:webp\/1*X3uTzs55-zrhTgrdb0M7JQ.jpeg 786w, https:\/\/miro.medium.com\/v2\/resize:fit:828\/format:webp\/1*X3uTzs55-zrhTgrdb0M7JQ.jpeg 828w, https:\/\/miro.medium.com\/v2\/resize:fit:1100\/format:webp\/1*X3uTzs55-zrhTgrdb0M7JQ.jpeg 1100w, https:\/\/miro.medium.com\/v2\/resize:fit:1400\/format:webp\/1*X3uTzs55-zrhTgrdb0M7JQ.jpeg 1400w\" sizes=\"(min-resolution: 4dppx) and (max-width: 700px) 50vw, (-webkit-min-device-pixel-ratio: 4) and (max-width: 700px) 50vw, (min-resolution: 3dppx) and (max-width: 700px) 67vw, (-webkit-min-device-pixel-ratio: 3) and (max-width: 700px) 65vw, (min-resolution: 2.5dppx) and (max-width: 700px) 80vw, (-webkit-min-device-pixel-ratio: 2.5) and (max-width: 700px) 80vw, (min-resolution: 2dppx) and (max-width: 700px) 100vw, (-webkit-min-device-pixel-ratio: 2) and (max-width: 700px) 100vw, 700px\" type=\"image\/webp\"\/><source data-testid=\"og\" srcset=\"https:\/\/miro.medium.com\/v2\/resize:fit:640\/1*X3uTzs55-zrhTgrdb0M7JQ.jpeg 640w, https:\/\/miro.medium.com\/v2\/resize:fit:720\/1*X3uTzs55-zrhTgrdb0M7JQ.jpeg 720w, https:\/\/miro.medium.com\/v2\/resize:fit:750\/1*X3uTzs55-zrhTgrdb0M7JQ.jpeg 750w, https:\/\/miro.medium.com\/v2\/resize:fit:786\/1*X3uTzs55-zrhTgrdb0M7JQ.jpeg 786w, https:\/\/miro.medium.com\/v2\/resize:fit:828\/1*X3uTzs55-zrhTgrdb0M7JQ.jpeg 828w, https:\/\/miro.medium.com\/v2\/resize:fit:1100\/1*X3uTzs55-zrhTgrdb0M7JQ.jpeg 1100w, https:\/\/miro.medium.com\/v2\/resize:fit:1400\/1*X3uTzs55-zrhTgrdb0M7JQ.jpeg 1400w\" sizes=\"(min-resolution: 4dppx) and (max-width: 700px) 50vw, (-webkit-min-device-pixel-ratio: 4) and (max-width: 700px) 50vw, (min-resolution: 3dppx) and (max-width: 700px) 67vw, (-webkit-min-device-pixel-ratio: 3) and (max-width: 700px) 65vw, (min-resolution: 2.5dppx) and (max-width: 700px) 80vw, (-webkit-min-device-pixel-ratio: 2.5) and (max-width: 700px) 80vw, (min-resolution: 2dppx) and (max-width: 700px) 100vw, (-webkit-min-device-pixel-ratio: 2) and (max-width: 700px) 100vw, 700px\"\/><img fetchpriority=\"high\" alt=\"\" class=\"bg mu nz c\" width=\"700\" height=\"545\" loading=\"eager\" role=\"presentation\"\/><\/picture><\/div>\n<\/div>\n<\/figure>\n<p id=\"bb7d\" class=\"pw-post-body-paragraph oa ob gr oc b hp od oe of hs og oh oi oj ok ol om on oo op oq or os ot ou ov gk bj\">The <a class=\"af ow\" href=\"https:\/\/developer.adobe.com\/photoshop\/photoshop-api-docs\/\" rel=\"noopener ugc nofollow\" target=\"_blank\">Photoshop API<\/a> is an incredibly powerful REST-based API for performing Photoshop tasks in the cloud and at scale.<\/p>\n<p id=\"bc2c\" class=\"pw-post-body-paragraph oa ob gr oc b hp od oe of hs og oh oi oj ok ol om on oo op oq or os ot ou ov gk bj\">I\u2019ve been demonstrating its features on our blog over the past few months, generally using Node.js, but the API\u2019s simplicity makes it available for any platform out there.<\/p>\n<p id=\"b00b\" class=\"pw-post-body-paragraph oa ob gr oc b hp od oe of hs og oh oi oj ok ol om on oo op oq or os ot ou ov gk bj\">In this article, I\u2019ll share an example of how Python can be used to interact with the Photoshop API. As a warning, I\u2019m fairly new to Python, but one of the best aspects of the language is just how easy it is to pick up and start using it right away.<\/p>\n<p id=\"1b86\" class=\"pw-post-body-paragraph oa ob gr oc b hp od oe of hs og oh oi oj ok ol om on oo op oq or os ot ou ov gk bj\">If you haven\u2019t already done so, grab your <a class=\"af ow\" href=\"https:\/\/developer.adobe.com\/photoshop\/api\/signup\/?ref=signup\" rel=\"noopener ugc nofollow\" target=\"_blank\">free trial credentials<\/a> so you can play with the API yourself. With that, let\u2019s get started!<\/p>\n<p id=\"4ca5\" class=\"pw-post-body-paragraph oa ob gr oc b hp pt oe of hs pu oh oi oj pv ol om on pw op oq or px ot ou ov gk bj\">In general, working with the different parts of the Photoshop APIs involves much the same steps:<\/p>\n<ul class=\"\">\n<li id=\"f955\" class=\"oa ob gr oc b hp od oe of hs og oh oi oj ok ol om on oo op oq or os ot ou ov py pz qa bj\">Convert credentials into an access token<\/li>\n<li id=\"5f23\" class=\"oa ob gr oc b hp qb oe of hs qc oh oi oj qd ol om on qe op oq or qf ot ou ov py pz qa bj\">Determine input and output URLs (as the APIs work with cloud storage, this will depend on your storage system and their SDKs)<\/li>\n<li id=\"c8ab\" class=\"oa ob gr oc b hp qb oe of hs qc oh oi oj qd ol om on qe op oq or qf ot ou ov py pz qa bj\">Call the API endpoint, passing in your URLs and other arguments required for that particular service<\/li>\n<li id=\"461f\" class=\"oa ob gr oc b hp qb oe of hs qc oh oi oj qd ol om on qe op oq or qf ot ou ov py pz qa bj\">Check the result of the API call on a schedule to determine the status of the job<\/li>\n<\/ul>\n<p id=\"c333\" class=\"pw-post-body-paragraph oa ob gr oc b hp od oe of hs og oh oi oj ok ol om on oo op oq or os ot ou ov gk bj\">So Let\u2019s break these down into individual Python examples.<\/p>\n<p id=\"6eb9\" class=\"pw-post-body-paragraph oa ob gr oc b hp pt oe of hs pu oh oi oj pv ol om on pw op oq or px ot ou ov gk bj\">Again, assuming you have your credentials, getting an access token is as simple as a call to Adobe\u2019s <code class=\"cw qg qh qi qj b\">ims<\/code> endpoint. Here&#8217;s an example:<\/p>\n<figure class=\"np nq nr ns nt nu\"\/>\n<p id=\"4f43\" class=\"pw-post-body-paragraph oa ob gr oc b hp od oe of hs og oh oi oj ok ol om on oo op oq or os ot ou ov gk bj\">Note that the assumption is that the credentials, <code class=\"cw qg qh qi qj b\">CLIENT_ID<\/code> and <code class=\"cw qg qh qi qj b\">CLIENT_SECRET<\/code> are available in environment variables. Running this script will dump out the result of the call:<\/p>\n<figure class=\"np nq nr ns nt nu\"\/>\n<p id=\"24a5\" class=\"pw-post-body-paragraph oa ob gr oc b hp od oe of hs og oh oi oj ok ol om on oo op oq or os ot ou ov gk bj\">Typically you can just work with the <code class=\"cw qg qh qi qj b\">access_token<\/code> result of the call.<\/p>\n<p id=\"ce4f\" class=\"pw-post-body-paragraph oa ob gr oc b hp pt oe of hs pu oh oi oj pv ol om on pw op oq or px ot ou ov gk bj\">The next step is completely optional, and not generally recommended in production, but it may be a good idea while learning and testing.<\/p>\n<p id=\"42ba\" class=\"pw-post-body-paragraph oa ob gr oc b hp od oe of hs og oh oi oj ok ol om on oo op oq or os ot ou ov gk bj\">The Photoshop API provides a method that <em class=\"qn\">only<\/em> verifies the access token. This is handy as other calls will require working with cloud storage. The <code class=\"cw qg qh qi qj b\">hello<\/code> endpoint will do simply that: echo back a greeting if you&#8217;ve correctly performed authentication. Let&#8217;s update the Python call with a new function testing that, <code class=\"cw qg qh qi qj b\">sayHello<\/code>:<\/p>\n<figure class=\"np nq nr ns nt nu\"\/>\n<p id=\"9ec2\" class=\"pw-post-body-paragraph oa ob gr oc b hp od oe of hs og oh oi oj ok ol om on oo op oq or os ot ou ov gk bj\">All of our API calls will require two headers for authorization. The first, <code class=\"cw qg qh qi qj b\">Authorization<\/code>, includes the access token returned from the earlier request, while <code class=\"cw qg qh qi qj b\">x-api-key<\/code> uses the <code class=\"cw qg qh qi qj b\">CLIENT_ID<\/code> value from our credentials.<\/p>\n<p id=\"070e\" class=\"pw-post-body-paragraph oa ob gr oc b hp od oe of hs og oh oi oj ok ol om on oo op oq or os ot ou ov gk bj\">The result of this script is simply: <code class=\"cw qg qh qi qj b\">Response from hello endpoint: Welcome to the Photoshop API!<\/code><\/p>\n<p id=\"4da2\" class=\"pw-post-body-paragraph oa ob gr oc b hp pt oe of hs pu oh oi oj pv ol om on pw op oq or px ot ou ov gk bj\">The next thing to do is start a job of some sort. The Photoshop API has <em class=\"qn\">many<\/em> features, but for today, let\u2019s consider the <a class=\"af ow\" href=\"https:\/\/developer.adobe.com\/photoshop\/photoshop-api-docs\/api\/#tag\/Photoshop\/operation\/cutout\" rel=\"noopener ugc nofollow\" target=\"_blank\">Remove Background<\/a> API which, you guessed it, removes the background from an image.<\/p>\n<p id=\"1c39\" class=\"pw-post-body-paragraph oa ob gr oc b hp od oe of hs og oh oi oj ok ol om on oo op oq or os ot ou ov gk bj\">In order to do this, we need both a source for our input and a place to store the output.<\/p>\n<p id=\"2c8c\" class=\"pw-post-body-paragraph oa ob gr oc b hp od oe of hs og oh oi oj ok ol om on oo op oq or os ot ou ov gk bj\">The Photoshop APIs support cloud storage on Amazon S3, Dropbox, and Azure, and the particularities of each depend on their SDKs. For today, let\u2019s just consider a simple S3 bucket. The Photoshop API team created a nice <a class=\"af ow\" href=\"https:\/\/github.com\/AdobeDocs\/cis-photoshop-api-docs\/blob\/main\/sample-code\/storage-app\/aws-s3\/example.py\" rel=\"noopener ugc nofollow\" target=\"_blank\">Python demo<\/a> I can borrow from to simplify making those S3 URLs using the Python <code class=\"cw qg qh qi qj b\">boto3<\/code> package.<\/p>\n<p id=\"6035\" class=\"pw-post-body-paragraph oa ob gr oc b hp od oe of hs og oh oi oj ok ol om on oo op oq or os ot ou ov gk bj\">Let\u2019s look at our updated script:<\/p>\n<figure class=\"np nq nr ns nt nu\"\/>\n<p id=\"43b0\" class=\"pw-post-body-paragraph oa ob gr oc b hp od oe of hs og oh oi oj ok ol om on oo op oq or os ot ou ov gk bj\">There are two big changes here. First note the use of <code class=\"cw qg qh qi qj b\">get_presigned_url<\/code>. This lets us create a readable URL for our source image as well as a writeable URL for the output. You can see that towards the bottom of the script where <code class=\"cw qg qh qi qj b\">inputURL<\/code> and <code class=\"cw qg qh qi qj b\">uploadURL<\/code> are created.<\/p>\n<p id=\"42b3\" class=\"pw-post-body-paragraph oa ob gr oc b hp od oe of hs og oh oi oj ok ol om on oo op oq or os ot ou ov gk bj\">Next, the <code class=\"cw qg qh qi qj b\">create_removebg_job<\/code> function is called with our credentials and URLs. In that function, look at <code class=\"cw qg qh qi qj b\">data<\/code>. This information is passed to the API and defines how it should operate. In general, every single part of the API will be a version of this, with just the parameters changing based on what operation is being used.<\/p>\n<p id=\"75bb\" class=\"pw-post-body-paragraph oa ob gr oc b hp od oe of hs og oh oi oj ok ol om on oo op oq or os ot ou ov gk bj\">The end result of this call is a <code class=\"cw qg qh qi qj b\">job<\/code> that looks like this:<\/p>\n<figure class=\"np nq nr ns nt nu\"\/>\n<p id=\"bc6d\" class=\"pw-post-body-paragraph oa ob gr oc b hp pt oe of hs pu oh oi oj pv ol om on pw op oq or px ot ou ov gk bj\">For the final part of our sample code, let\u2019s check the job and keep checking it until it finishes.<\/p>\n<p id=\"2ef5\" class=\"pw-post-body-paragraph oa ob gr oc b hp od oe of hs og oh oi oj ok ol om on oo op oq or os ot ou ov gk bj\">Technically, you don\u2019t need to do this in the same script. You could, for example, store the job result in a database and use a scheduled process to check the result at a later time. Since the \u201ctypical\u201d call to the Photoshop API will finish rather quickly, it isn\u2019t too difficult to add it to our script.<\/p>\n<p id=\"c84b\" class=\"pw-post-body-paragraph oa ob gr oc b hp od oe of hs og oh oi oj ok ol om on oo op oq or os ot ou ov gk bj\">In the code sample below, I\u2019m only sharing the portion where the job is created and how polling for the result is handled. All the code before this portion is the same as before:<\/p>\n<figure class=\"np nq nr ns nt nu\"\/>\n<p id=\"18d6\" class=\"pw-post-body-paragraph oa ob gr oc b hp od oe of hs og oh oi oj ok ol om on oo op oq or os ot ou ov gk bj\">Now we\u2019re taking the URL from the job creation call and continuing to call it until the status of the response is either good or bad. In that loop, the response is also bring printed out. Here\u2019s an example of what that looks like when done:<\/p>\n<figure class=\"np nq nr ns nt nu\"\/>\n<p id=\"28fd\" class=\"pw-post-body-paragraph oa ob gr oc b hp pt oe of hs pu oh oi oj pv ol om on pw op oq or px ot ou ov gk bj\">If you would like to play with this code, you can find it on my repository here: <a class=\"af ow\" href=\"https:\/\/github.com\/cfjedimaster\/photoshop_api_preso\/tree\/main\/demos\/python\" rel=\"noopener ugc nofollow\" target=\"_blank\">https:\/\/github.com\/cfjedimaster\/photoshop_api_preso\/tree\/main\/demos\/python<\/a>. Also, you can find a notebook version of it <a class=\"af ow\" href=\"https:\/\/colab.research.google.com\/drive\/193MDZDZb8mxTIFNwKw_yZwjDWmfOlAxk?usp=sharing\" rel=\"noopener ugc nofollow\" target=\"_blank\">here<\/a>, but be sure to note the requirements for credentials at the top.<\/p>\n<p id=\"e2b0\" class=\"pw-post-body-paragraph oa ob gr oc b hp od oe of hs og oh oi oj ok ol om on oo op oq or os ot ou ov gk bj\">Let us know how this works for you, and reach out on our <a class=\"af ow\" href=\"https:\/\/community.adobe.com\/t5\/photoshop-developers\/ct-p\/ct-photoshop-developers?page=1&amp;sort=latest_replies&amp;lang=all&amp;tabid=all&amp;topics=label-psautomationapi\" rel=\"noopener ugc nofollow\" target=\"_blank\">forums<\/a> with any questions!<\/p>\n<\/div>\n<p><br \/>\n<br \/><a href=\"https:\/\/blog.developer.adobe.com\/integrating-the-photoshop-api-with-python-859c75e788e4?source=rss----9342990108af---4\">Source link <\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>How Python can interact with our powerful Photoshop API The Photoshop API is an incredibly powerful REST-based API for performing Photoshop tasks in the cloud and at scale. I\u2019ve been demonstrating its features on our blog over the past few months, generally using Node.js, but the API\u2019s simplicity makes it available for any platform out [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":8566,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"inline_featured_image":false,"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"footnotes":""},"categories":[19],"tags":[],"class_list":["post-8565","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-graphics-design"],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/www.satup.xyz\/index.php\/wp-json\/wp\/v2\/posts\/8565","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.satup.xyz\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.satup.xyz\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.satup.xyz\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.satup.xyz\/index.php\/wp-json\/wp\/v2\/comments?post=8565"}],"version-history":[{"count":0,"href":"https:\/\/www.satup.xyz\/index.php\/wp-json\/wp\/v2\/posts\/8565\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.satup.xyz\/index.php\/wp-json\/wp\/v2\/media\/8566"}],"wp:attachment":[{"href":"https:\/\/www.satup.xyz\/index.php\/wp-json\/wp\/v2\/media?parent=8565"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.satup.xyz\/index.php\/wp-json\/wp\/v2\/categories?post=8565"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.satup.xyz\/index.php\/wp-json\/wp\/v2\/tags?post=8565"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}