cssAudio - Activefile-genericCSS - ActiveGeneric - ActiveHTML - ActiveImage - ActiveJS - ActiveSVG - ActiveText - Activefile-genericVideo - ActiveLovehtmlicon-new-collectionicon-personicon-teamlog-outoctocatpop-outspinnerstartv

Pen Settings

CSS Base

Vendor Prefixing

Add External Stylesheets/Pens

Any URL's added here will be added as <link>s in order, and before the CSS in the editor. If you link to another Pen, it will include the CSS from that Pen. If the preprocessor matches, it will attempt to combine them before processing.

+ add another resource

You're using npm packages, so we've auto-selected Babel for you here, which we require to process imports and make it all work. If you need to use a different JavaScript preprocessor, remove the packages in the npm tab.

Add External Scripts/Pens

Any URL's added here will be added as <script>s in order, and run before the JavaScript in the editor. You can use the URL of any other Pen and it will include the JavaScript from that Pen.

+ add another resource

Use npm Packages

We can make npm packages available for you to use in your JavaScript. We use webpack to prepare them and make them available to import. We'll also process your JavaScript with Babel.

⚠️ This feature can only be used by logged in users.

Code Indentation

     

Save Automatically?

If active, Pens will autosave every 30 seconds after being saved once.

Auto-Updating Preview

If enabled, the preview panel updates automatically as you code. If disabled, use the "Run" button to update.

            
              <div id="app">
  <aside>
    <h1 class="nobottom">Dynamically Generated Alt Text<br>
    <span>With Azure's Computer Vision API</span></h1>
    <p><a href="https://aka.ms/Uzrshc" target="_blank">Check out the docs <svg class="arrow" version="1.1" xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 32 32" aria-labelledby="arrow">
<title id="arrow">arrow-right</title>
<path d="M31 16l-15-15v9h-16v12h16v9z"></path>
</svg></a></p>
    <hr>

    <section v-if="!noText2">
      <transition name="fade" mode="out-in">
        <div v-if="desc.length === 0">
          <div class="upload">
            <h2 class="select" ref="selectimg">Select an image here: </h2>
            <input type="file" name="file" id="file" class="inputfile" @change="fileUpload" />
            <label for="file" aria-label="upload image">
              <svg xmlns="http://www.w3.org/2000/svg" width="45" height="45" viewBox="0 0 32 32" aria-labelledby="plus" role="presentation">
                <title id="plus">Plus Sign</title>
                <circle cx="15" cy="15" r="15" fill="#bf310b"/>
                 <line x1="15" x2="15" y1="10" y2="20" fill="none" stroke-weight="2" stroke="#ffffff"/>
                <line x1="10" x2="20" y1="15" y2="15" fill="none" stroke-weight="2" stroke="#ffffff"/>
              </svg>
            </label>
          </div>
          <!--upload-->
          <label for="url">Or enter a url:</label><br>
          <input type="text" id="url" v-model.lazy="image" @keyup.enter="visionReq" />
          <button class="useone" @click="useMine">Or use one of mine</button>
          <p v-if="image.length > 0" class="load">Loading
            <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 32 32" aria-labelledby="loading" role="presentation" class="loading">
              <title id="loading">spinner9</title>
              <path fill="#ffffff" d="M16 0c-8.711 0-15.796 6.961-15.995 15.624 0.185-7.558 5.932-13.624 12.995-13.624 7.18 0 13 6.268 13 14 0 1.657 1.343 3 3 3s3-1.343 3-3c0-8.837-7.163-16-16-16zM16 32c8.711 0 15.796-6.961 15.995-15.624-0.185 7.558-5.932 13.624-12.995 13.624-7.18 0-13-6.268-13-14 0-1.657-1.343-3-3-3s-3 1.343-3 3c0 8.837 7.163 16 16 16z"></path>
          </svg></p>
        </div>
        <div v-else>
          <button @click="removeImage">Try it again!</button>
        </div>
      </transition>
    </section>

    <section v-if="noText && noText2" class="fail">
      <p>Nothing was detected!<br> Sorry about that, care to...</p>
      <button @click="removeImage">Try again!</button>
    </section>

    <hr>

    <div @click="moreInfo = !moreInfo" class="more">
      <button class="more" v-if="!moreInfo">More info...</button>
      <button class="more" v-else>Less info</button>
    </div>
    <transition name="fade">
      <p v-if="moreInfo">I kept hearing about machine learning being used for evil and wanted to use it for something good. Social media posts typically don't have a way to enter alt text and the only users I see that reliably remember to add descriptions to the post are
        accessibility experts or blind people. Hopefully this allows good alt text to be a bit more ubiquitous. You can find <a href="https://aka.ms/Uzrshc" target="_blank">more information on how Azure's Computer Vision API works</a>, as well as how
        to use it in your own projects here.</p>
    </transition>
  </aside>

  <main>
    <transition name="fade">
      <div v-if="Object.keys(desc).length > 0">
        <h3>Alt text:</h3>
        <p role="status"><span class="screen-reader-only">Generated alt text:</span> {{ combinedText | capitalize }}</p>
        <img :src="image" :alt="combinedText" ref="alttextimg" />
      </div>
    </transition>
  </main>

</div>
            
          
!
            
              $red: #bf310b;

body {
  background: #071b6d;
  color: white;
  padding: 20px;
}

* {
  font-family: "Barlow", helvetica, sans-serif;
}

.screen-reader-only {
  position: absolute;
  left: -10000px;
  top: auto;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

button {
  background: $red;
  color: white;
  border: none;
  border-radius: 3px;
  padding: 5px 10px;
  cursor: pointer;
  font-style: italic;
  font-weight: 300;
  font-family: "Lato", sans-serif;
  margin: 10px 0;
  &.more {
    cursor: pointer;
    color: #95a2da;
    background: none;
    border: 0;
    font: inherit;
    line-height: normal;
    overflow: visible;
    padding: 0;
    -webkit-appearance: button; /* for input */
    -webkit-user-select: none; /* for button */
    -moz-user-select: none;
    -ms-user-select: none;
  }
  &.useone {
    cursor: pointer;
    background: none;
    border: 0;
    font: inherit;
    line-height: normal;
    overflow: visible;
    padding: 0;
    -webkit-appearance: button; /* for input */
    -webkit-user-select: none; /* for button */
    -moz-user-select: none;
    -ms-user-select: none;
    margin-top: 18px;
    color: #e8d499;
    font-size: 18px;
    transition: 0.25s all ease;
    &:hover {
      color: #ef9d0e;
    }
  }
}

label {
  font-size: 18px;
}

input {
  margin: 10px 0 0;
}

p,
h3 {
  margin: 5px 0 0;
}

h1 span {
  font-weight: 300;
  font-size: 24px;
  display: block;
  margin: 15px 0;
}

hr {
  opacity: 0.2;
  width: 100%;
  margin-top: 25px;
}

a {
  text-decoration: none;
  color: #fec802;
}

//base layout start
#app {
  display: flex;
  aside {
    width: 300px;
    display: flex;
    flex-direction: column;
  }
  main {
    flex-grow: 2;
  }
}

@media (min-width: 600px) {
  aside {
    height: 85vh;
  }
  main {
    height: 85vh;
  }
}

@media (max-width: 600px) {
  #app {
    display: block;
  }
  aside {
    width: 100vw;
  }
  main {
    width: 85vw;
    height: 300px;
    margin: 0;
  }
  #canvas {
    width: 85%;
    margin-left: 0;
    margin-top: 20px;
  }
  .nomobile {
    display: none;
  }
}
//base layout end

.load {
  margin: 15px 0;
}

.fail {
  margin: 15px 0;
}

img {
  max-width: 400px;
  max-height: 600px;
  width: 90%;
  border: 1px solid #777;
  margin: 15px 0;
}

.arrow {
  margin-left: 2px;
  path {
    fill: #fec802;
  }
}

.inputfile {
  width: 0.1px;
  height: 0.1px;
  opacity: 0;
  overflow: hidden;
  position: absolute;
  z-index: -1;
}

.inputfile + label {
  margin: 4px 10px;
  display: inline-block;
  transition: 0.3s all ease-out;
}

.inputfile:focus + label circle,
.inputfile + label circle:hover {
  fill: #f14619;
}

.inputfile + label {
  cursor: pointer; /* "hand" cursor */
}

.inputfile:focus + label {
  outline: 1px dotted #000;
  outline: -webkit-focus-ring-color auto 5px;
}

.inputfile + label * {
  pointer-events: none;
}

//main

main {
  padding: 20px;
  background: #1f3bad;
  margin: 20px;
  height: 85vh;
  div {
    width: 100%;
    height: 100%;
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
  }
}

main p {
  width: 70%;
  text-align: center;
}

.upload {
  display: flex;
}

//utility

.nobottom {
  margin-bottom: 0;
}

.bottom10 {
  margin-bottom: 10px;
}

.select {
  margin: 10px 0 18px;
  font-weight: 300;
}

.loading {
  animation: load 1s infinite both;
  transform-origin: 50% 50%;
}

@keyframes load {
  35% {
    opacity: 0.35;
  }
  100% {
    transform: rotate(360deg);
  }
}

.fade-enter-active {
  transition: opacity 0.35s ease-out;
}

.fade-leave-active {
  transition: opacity 0.2s ease-in;
}

.fade-enter,
.fade-leave-to {
  opacity: 0;
}

            
          
!
            
              new Vue({
  el: "#app",
  data() {
    return {
      textdesc: {},
      desc: "",
      image: "",
      combinedText: "",
      noText: false,
      noText2: false,
      moreInfo: false
    };
  },
  filters: {
    capitalize(string) {
      return string.charAt(0).toUpperCase() + string.slice(1);
    }
  },
  computed: {
    alttext() {
      if (Object.keys(this.textdesc).length > 0) {
        let textarr = [];
        this.textdesc.regions.forEach(region => {
          region.lines.forEach(line => {
            line.words.forEach(word => {
              textarr.push(word.text);
            });
          });
        });
        return textarr.join(" ");
      }
    }
  },
  methods: {
    apiReq(params, urlPath) {
      let uribase = `https://westcentralus.api.cognitive.microsoft.com/vision/v1.0/${urlPath}`;

      let data, contentType;
      if (typeof this.image === "string") {
        data = { url: this.image };
        contentType = "application/json";
      } else {
        data = this.image;
        contentType = "application/octet-stream";
      }

      return axios({
        method: "post",
        url: uribase,
        data: data,
        params: params,
        headers: {
          "Content-Type": contentType,
          "Ocp-Apim-Subscription-Key": "5cd9392bcf6b4303920916aef005fd37"
        },
        validateStatus: function(status) {
          return status < 500;
        }
      });
    },
    visionReq() {
      let param1 = {
        language: "unk",
        "detectOrientation ": "true"
      };
      let param2 = {
        visualFeatures: "Categories,Description,Color",
        details: "",
        language: "en"
      };

      this.apiReq(param1, "ocr").then(response => {
        if (response.status === 200) {
          this.textdesc = response.data;
        } else {
          this.noText = true;
        }
      });

      this.apiReq(param2, "analyze").then(response => {
        if (response.status === 200) {
          this.desc = response.data.description.captions[0].text;
        } else {
          this.noText2 = true;
        }
      });
    },
    fileUpload(e) {
      var files = e.target.files || e.dataTransfer.files;
      if (!files.length) return;
      this.image = files[0];
      this.createImage();
      this.visionReq();
    },
    useMine() {
      this.image =
        "https://s3-us-west-2.amazonaws.com/s.cdpn.io/28963/heygirl.jpg";
      this.visionReq();
    },
    createImage() {
      var image = new Image();
      var reader = new FileReader();

      reader.onload = e => {
        this.image = e.target.result;
      };
      reader.readAsDataURL(this.image);
    },
    removeImage: function(e) {
      this.image = "";
      this.noText = false;
      this.noText2 = false;
      this.textdesc = {};
      this.desc = "";
      this.altText = "";
      this.combinedText = "";

      setTimeout(() => {
        this.$refs.selectimg.focus();
      }, 1000);
    }
  },
  watch: {
    desc() {
      if (this.desc === undefined) {
        this.combinedText = "";
      } else if (this.desc.length > 0) {
        if (this.alttext !== undefined && this.alttext.length > 0) {
          this.combinedText = `${this.desc}, the text says: "${this.alttext}"`;
        } else {
          this.combinedText = `${this.desc}`;
        }
      }
    }
  }
});

            
          
!
999px
🕑 One or more of the npm packages you are using needs to be built. You're the first person to ever need it! We're building it right now and your preview will start updating again when it's ready.
Loading ..................

Console