Auto scale picture with imgproxy

Time:2019-12-20

No map, pure dry goods, large amount of information, careful!

The achievements in recent days are condensed into such a line of code:

document.getElementById('img1').src = 'http://www.mysite.com/imgproxy' + imgproxy(document.getElementById("img1").getAttribute('data-src'), 135, 85);

Find the right drawing bed

At the beginning, I only saw that the size of my personal blog pictures was different, which was ugly. I tried to find a way to unify the height of each picture. The result of searching on the Internet is that severalJykellIn addition to srcset, IMG tag also has an additional picture tag. Originally, I wanted to use this plug-in, but the author of Jekyll cloud, another plug-in, said that the picture tag is not good, so I should directly use cloud cloud Library’s services.

This reminds me of a tutorial that I mentioned in my last article about making a picture bed with domestic qiniu cloud, so I began to try to move the pictures used in my website article to qiniu cloud, which is not a problem, but I want to add HTTPS service to the blog website, so after asking my friend Ma Zhuang, I opened HTTPS service on cloudflare, but this Another problem: Although there are my pictures on qiniu cloud, it does not support HTTPS service, so we have to find a way to move the pictures to cloudinary.

So far, my personal blog can be concluded. be honest,Seven cattle cloudAt least it’s good forURLTreatment ratio ofCloudinarySimple, but the only regret is that it doesn’t supporthttps。 And if the picture doesn’t supporthttpsAnd the website useshttpsThen,ChromeWill be inConsoleThere is a warning error in the internal report, and my requirement for the website is that no warning can be given.

URL auto adjust picture

In the process, I began to think about a question: SinceCloudinaryandSeven cattle cloudBased onURLAddress image transformation, so how do they do it? According to my pairPHPThe most stupid way is toPHPThe way of reading file is to read the source file of the picture from the hard disk first, and then output it to the page in the way of stream after conversion, but the efficiency is very low. After searching, we found the libvips library recommended by many people, and then we searched furtherGithubThere are many stars in the imgproxy library. It seems that this is what I want.

So I started to try to deploy it on the company’s serversimgproxy。 But at this time, I encountered a problem, which wasCentOSUp,imgproxyDid notyumInstall the package manuallylibvips, and then compile, and the most important thing is that the company’s server is in China, unable to passwgetIn this way, I need to download the installation package to the local, and then upload it to the company’s server. At this time, I want to use the built-in SCP of iterm to upload files by mouse drag. According to the instructions of operation steps, after installation, it was found thatitermOfscpThe button is still gray, then it is found that it is due to thefishVersion too low, only1.3, and the latest is already2.6Now. Then install repo of 2.6 and try to update itfishBut always report conflicts. So I think thatfish 1.3Uninstall first, and then disaster happens.

disaster

I did it directlyyum remove fishBut before doing this, I didn’trootUsershellSwitch backbash, resulting inrootThe user could not find itsshellBecause it’s still trying to findfish。 This is a fatal mistake. I remember that I had a vague premonition at that time, but I didn’t pay special attention to it. I thought maybeLinuxThe system will automaticallyrootThe user assigns a defaultshell。 I overestimated itLinuxSystem capabilities.

After logging out, I foundrootUser login failed! If you don’t observe it carefully, you will feel that its sign in failure symptoms and password errors are very similar, but the actual performance is slightly differentSSHIt’s not obvious. My first reaction was ifrootUser cannot passSSHLog in, then you should go throughconsoleEnd login.

But that afternoon, it was amazing that LianconsoleI can’t get on the end! At this time I realized that the problem was serious. The result of searching on the Internet is that some people say that they should log in as runlevel 1, and then try to fix it/etc/shadow。 But I have no idea how a virtual machine should enterrunlevel 1。 I have to submit the work order to customer service. We should know the technical level of customer service, just suggest I reset the password and try again. And reset password must be shut down and then restart, so back and forth after a long time is not good.

After a long wait, a technician was finally alerted. He pointed out that if I had to enterrunlevel 1If so, you can press the e key of the keyboard between the first three seconds of the system power on, and then you can enterrunlevel 1Now.

But the problem is that this is a virtual machine. How can I press the key three seconds before starting? Fortunately, today’s virtual machineconsoleIt’s very functional. You can drive itconsoleRestart. At this time, the network will be disconnected and refreshed continuouslyconsole, you will see a black screen with words at the moment when the computer is turned on, and then press it quicklyeThe key can also enter the system. Then press againe, change the startup mode toLinux single

Under his guidance, I was finally able torunlevel 1First try to use the/etc/passwdreconstruction/etc/shadow, restart again, no result, or log in. So far, all efforts on passwords have failed. I think the only way to do this is to try and see if you can switchrootUsershell

chsh -s /bin/bash

holdrootUsershellSwitch tobashAfter that, restart the computer again, and you can log in successfully!

repair

Next, I still need to installfishButyum install fishResultfishstill1.3。 I’m going to continue my unsuccessful journey. Once againfishfrom1.3change into2.6。 There is still conflict. This time I’m good at learningrootOfshellScript switch tobashAnd thenyum remove fish, install again, find thisfish 1.3The source is a name that I don’t know when I put it ondagOfrepo, so try to put thisdagOfrepoNo:

yum-config-manager --disable dag

And then install it again, and finally install itfish 2.6

So far, almost all the blocking factors have been eliminated, and I started tolibvipsThe code is dragged into the server and compiled. But then the problem came again,imgproxyMust run ondockerAnd the document only says you need tobuildOnedocker, but it does not specify the operating system basedbuildFortunately, the government provided their owndockerFile, can run directlyimgproxy

Ah! If I had known that, why should I make such a big circle? And almost destroyed my system. But I learned a lot. OK, so we started to install it directlyimgproxyOfficialdocker

$ docker pull darthsim/imgproxy:latest
$ docker run -e IMGPROXY_KEY=$YOUR_KEY -e IMGPROXY_SALT=$YOUR_SALT -p 8080:8080 -t darthsim/imgproxy

But thisimgproxyIt’s very unfriendly. It’s not likeSeven cattle cloudperhapsCloudinaryThat’s right thereURLJust build on the address. It needs to be built according to its ownkeyandsaltGenerate signature, then build it with signatureURLIt gives examples of different languages, but nonejavaIn the end, I had to follow its ownjavascriptBuilding a language examplejsCode to replace the picture link in the page.

programming

But the problem comes again. The package it gives is anodeOfjsScript, it hasrequireStatement, cannot be used directly for browsers. At this time, please come out againbrowerify, use it to compilenodeThe script of is a script that can be used directly by the browser. Fortunately, the process is not complicated, and you get it after compilingbundle.jsFile, we can reference it directly in the page. So you get the first line of code:

<!DOCTYPE html>
<html>
<head>
</head>
<body>
  <img id="img1" src="http://www.mysite.com/img/somepic.png" />
  <script></script>
  <script>
    window.onload = function() {
      document.getElementById('img1').src = 'http://www.mysite.com/imgproxy' + imgproxy(document.getElementById("img1").getAttribute('data-src'), 135, 85);
    }
  </script>
</body>
</html>

And related JS:

window.imgproxy = function (url, width, height) {
  const crypto = require('crypto')

  const KEY = 'somekey'
  const SALT = 'somesalt'

  const urlSafeBase64 = (string) => {
    return new Buffer(string).toString('base64').replace(/=/g, '').replace(/\+/g, '-').replace(/\//g, '_')
  }

  const hexDecode = (hex) => Buffer.from(hex, 'hex')

  const sign = (salt, target, secret) => {
    const hmac = crypto.createHmac('sha256', hexDecode(secret))
    hmac.update(hexDecode(salt))
    hmac.update(target)
    return urlSafeBase64(hmac.digest())
  }

  const resizing_type = 'fit'
  const gravity = 'no'
  const enlarge = 0
  const extension = 'jpg'
  const encoded_url = urlSafeBase64(url)
  const path = `/${resizing_type}/${width}/${height}/${gravity}/${enlarge}/${encoded_url}.${extension}`

  const signature = sign(SALT, path, KEY)
  const result = `/${signature}${path}`
  return result;
}

Of course you neednpm install crypto, and then compile:

browserify main.js > bundle.js

You can get it yourselfURLGo to build with this websiteURLBy contrast, if it is completely consistent, it means that your code is configured correctly, otherwise it may not succeed.

This is the result of these two days. I’ve learned a lot. Have you?