Hello.

I am Paul Kinlan.

A Developer Advocate for Chrome and the Open Web at Google.

Puppeteer Go🔗

Paul Kinlan

Saya suka Puppeteer - ini memungkinkan saya bermain-main dengan ide-ide The Headless Web - yang menjalankan web di browser tanpa browser yang terlihat dan bahkan membangun alat-alat seperti DOM-curl (Curl yang menjalankan JavaScript). Secara khusus saya suka membuat skrip pada browser untuk mengikis, memanipulasi, dan berinteraksi dengan halaman.

Satu demo yang ingin saya buat terinspirasi oleh posting Capturing 422 live images Ire di mana ia menjalankan skrip dalang yang akan menavigasi ke banyak halaman dan mengambil tangkapan layar. Alih-alih pergi ke banyak halaman, saya ingin mengambil banyak screenshot elemen di halaman.

Masalah yang saya miliki dengan Dalang adalah bait pembuka yang perlu Anda lakukan apa pun. Luncurkan, Buka tab, navigasi - ini tidak rumit, hanya lebih sederhana daripada yang ingin saya buat untuk skrip sederhana. Itu sebabnya saya membuat Puppeteer Go . Itu hanya skrip kecil yang membantu saya membangun utilitas CLI dengan mudah yang membuka browser, menavigasi ke halaman, melakukan tindakan your dan kemudian membersihkan sendiri.

Saksikan berikut ini.

const { go } = require('puppeteer-go');

go('https://paul.kinlan.me', async (page) => {
    const elements = await page.$$("h1");
    let count = 0;
    for(let element of elements) {
      try {
        await element.screenshot({ path: `${count++}.png`});
      } catch (err) {
        console.log(count, err);
      }
    }
});

Kode di atas akan menemukan elemen h1 di blog saya dan mengambil tangkapan layar. Ini sama sekali tidak sebagus karya Ire, tapi saya pikir itu rapi untuk melihat apakah kita dapat dengan cepat menarik tangkapan layar dari canisuse.com langsung dari halaman.

const { go } = require('puppeteer-go');

go('https://caniuse.com/#search=css', async (page) => {
    const elements = await page.$$("article.feature-block.feature-block--feature");
    let count = 0;
    for(let element of elements) {
      try {
        await element.screenshot({ path: `${count++}.png`});
      } catch (err) {
        console.log(count, err);
      }
    }
});
4.png
3.png
2.png
1.png
0.png

Nikmati!

About Me: Paul Kinlan

I lead the Chrome Developer Relations team at Google.

We want people to have the best experience possible on the web without having to install a native app or produce content in a walled garden.

Our team tries to make it easier for developers to build on the web by supporting every Chrome release, creating great content to support developers on web.dev, contributing to MDN, helping to improve browser compatibility, and some of the best developer tools like Lighthouse, Workbox, Squoosh to name just a few.

A simple video insertion tool for EditorJS🔗

Paul Kinlan

Saya sangat suka EditorJS . Biarkan saya membuat antarmuka web-host yang sangat sederhana untuk blog Hugo statis saya.

EditorJS memiliki sebagian besar dari apa yang saya butuhkan dalam editor berbasis blok sederhana. Ini memiliki plugin untuk header, kode, dan bahkan cara sederhana untuk menambahkan gambar ke editor tanpa memerlukan infrastruktur hosting. Tidak ada cara sederhana untuk menambahkan video ke editor, sampai sekarang.

Aku mengambil simple-image repositori plugin yang dan berubah itu (hanya anak laki-laki) untuk membuat simple-video plugin ( npm module ). Sekarang saya dapat memasukkan video dengan mudah di blog ini.

Jika Anda terbiasa dengan EditorJS, itu agak sederhana untuk dimasukkan dalam proyek Anda. Instal saja sebagai berikut

npm i simple-video-editorjs

Dan kemudian sertakan saja dalam proyek Anda sesuai keinginan Anda.

const SimpleVideo = require('simple-video-editorjs');

var editor = EditorJS({
  ...
  
  tools: {
    ...
    video: SimpleVideo,
  }
  
  ...
});

Editor memiliki beberapa opsi sederhana yang memungkinkan Anda mengonfigurasi bagaimana video harus di-host di halaman:

  1. Putar otomatis - akan memutar video secara otomatis saat halaman dimuat
  2. dibisukan - apakah video tidak memiliki suara aktif secara default (diperlukan untuk putar otomatis)
  3. kontrol - apakah video memiliki kontrol HTML default.

Di bawah ini adalah contoh cepat video yang disematkan (dan menampilkan beberapa opsi).

Ngomong-ngomong, saya senang membuat plugin kecil ini - tidak terlalu sulit untuk membuat dan satu-satunya hal yang saya lakukan adalah menunda konversi ke base64 yang menggunakan gambar sederhana dan sebagai gantinya hanya menggunakan Blob URL.

Test post Video upload

Paul Kinlan

Jika Anda melihat video di sini, maka itu berhasil.

Read More

Friendly Project Name Generator with Zeit🔗

Paul Kinlan

Saya punya beberapa ide untuk proyek yang membuatnya lebih mudah untuk membuat situs di web - salah satu idenya adalah membuat netlify-like drag and drop interface untuk proyek-proyek berbasis zeit (saya suka zeit tetapi membutuhkan sedikit cli magic untuk digunakan).

Posting ini hanya mencakup satu bagian kecil dari teka-teki: membuat nama proyek.

Glitch adalah contoh yang bagus untuk hal ini, ketika Anda membuat proyek, itu memberikannya nama acak yang dibuat secara aneh. Tim juga menciptakan good dictionary of fairly safe words yang menggabungkan dengan baik (dan jika Anda ingin mereka memiliki server sederhana untuk di-host).

Jadi, proyek sampingan hari Minggu ini adalah untuk membuat layanan mikro sederhana untuk menghasilkan nama proyek acak menggunakan Zeit's serverless-functions dan kamus dari Glitch.

And here it is ( code ), cukup pendek dan tidak terlalu rumit.

const words = require("friendly-words");

function generate(count = 1, separator = "-") {
  const { predicates, objects } = words;
  const pCount = predicates.length;
  const oCount = objects.length;
  const output = [];

  for (let i = 0; i < count; i++) {
    const pair = [predicates[Math.floor(Math.random() * pCount)], objects[Math.floor(Math.random() * oCount)]];
    output.push(pair.join(separator));
  }

  return output;
}

module.exports = { generate }

Jika Anda tidak ingin memasukkannya dalam proyek Anda secara langsung, Anda dapat menggunakan titik akhir HTTP untuk menghasilkan nama proyek acak (dalam bentuk "XY") dengan membuat permintaan web ke https: // friendly-project-name. kinlan.now.sh/api/names, yang akan mengembalikan sesuatu seperti berikut ini.

["momentous-professor"]

Anda juga dapat mengontrol berapa banyak nama yang akan dihasilkan dengan parameter string-string count = x , mis. Https://friendly-project-name.kinlan.now.sh/api/names?count=100

["melon-tangerine","broad-jury","rebel-hardcover","far-friend","notch-hornet","principled-wildcat","level-pilot","steadfast-bovid","holistic-plant","expensive-ulna","sixth-gear","political-wrench","marred-spatula","aware-weaver","awake-pair","nosy-hub","absorbing-petunia","rhetorical-birth","paint-sprint","stripe-reward","fine-guardian","coconut-jumbo","spangle-eye","sudden-euphonium","familiar-fossa","third-seaplane","workable-cough","hot-light","diligent-ceratonykus","literate-cobalt","tranquil-sandalwood","alabaster-pest","sage-detail","mousy-diascia","burly-food","fern-pie","confusion-capybara","harsh-asterisk","simple-triangle","brindle-collard","destiny-poppy","power-globeflower","ruby-crush","absorbed-trollius","meadow-blackberry","fierce-zipper","coal-mailbox","sponge-language","snow-lawyer","adjoining-bramble","deserted-flower","able-tortoise","equatorial-bugle","neat-evergreen","pointy-quart","occipital-tax","balsam-fork","dear-fairy","polished-produce","darkened-gondola","sugar-pantry","broad-slouch","safe-cormorant","foregoing-ostrich","quasar-mailman","glittery-marble","abalone-titanosaurus","descriptive-arch","nickel-ostrich","historical-candy","mire-mistake","painted-eater","pineapple-sassafras","pastoral-thief","holy-waterlily","mewing-humor","bubbly-cave","pepper-situation","nosy-colony","sprout-aries","cyan-bestseller","humorous-plywood","heavy-beauty","spiral-riverbed","gifted-income","lead-kiwi","pointed-catshark","ninth-ocean","purple-toucan","tundra-cut","coal-geography","icy-lunaria","agate-wildcat","respected-garlic","polar-almandine","periodic-narcissus","carbonated-waiter","lavish-breadfruit","confirmed-brand","repeated-period"]

Anda dapat mengontrol pemisah dengan parameter pemisah kueri-string. yaitu, separator = @, mis. https://friendly-project-name.kinlan.now.sh/api/names?separator=@

["handsomely@asterisk"]

Aspek yang sangat berguna dari proyek ini adalah bahwa jika kombinasi kata-kata cenderung menyinggung, mudah untuk memperbarui repo Glitch untuk memastikan bahwa itu tidak terjadi lagi.

Dengan asumsi bahwa proyek hosting tidak menjadi terlalu mahal, saya akan terus meningkatkan layanan, tetapi merasa bebas untuk mengkloningnya sendiri jika Anda ingin membuat layanan mikro serupa.

Contoh langsung

Berikut ini adalah contoh super cepat dari API yang sedang beraksi.

const render = (promise, elementId) => {
  promise.then(async(response) => {
    const el = document.getElementById(elementId);
    el.innerText = await response.text();
  })
};


onload = () => {
  render(fetch("https://friendly-project-name.kinlan.now.sh/api/names"), "basic");
  render(fetch("https://friendly-project-name.kinlan.now.sh/api/names?count=100"), "many");
  render(fetch("https://friendly-project-name.kinlan.now.sh/api/names?separator=@"), "separator");
}

Respons tunggal


Banyak resposnses


Pemisah khusus


{{<raw-html>}}

{{</ raw-html>}}

Frankie and Bennys: Pay for your meal via the web

Paul Kinlan

Setiap kali saya melihat sebuah restoran mengatakan bahwa Anda dapat membayar melalui ponsel, saya selalu memeriksanya, terutama agar saya dapat meratapi kenyataan bahwa Anda perlu menggunakan aplikasi. Bayangkan betapa terkejutnya saya ketika kode QR mengarah ke aliran pembayaran berbasis web ..... dan berhasil. Pekerjaan yang luar biasa Frankie dan Benny! Pada titik ini, saya memang memilih Google Pay, tetapi tidak berfungsi (email dikirim secara internal!)

Read More

Podroll

Adding "dark mode" to my blog

Paul Kinlan

Saya melihat post about adding dark mode to his blog Jeremy Keith dan itu tampak sederhana, jadi saya memutuskan untuk berputar. Ini adalah diff of the work untuk dilihat semua orang. Ternyata sangat mudah (di luar kesalahan konyol di pihak saya). Ada refactor kecil untuk mendukung variabel CSS dan memastikan saya memiliki mundur jika ada browser yang tidak mendukung properti kustom CSS, tapi itu saja. Saya melakukan hal yang hampir sama dengan yang dilakukan Jeremy.

Read More

Using Web Mentions in a static site (Hugo)

Paul Kinlan

Blog saya adalah situs yang sepenuhnya statis, dibangun dengan Hugo dan di-host dengan Zeit. Ini adalah solusi yang bagus untuk saya, sebuah blog sederhana memiliki proses penyebaran yang cukup sederhana dan memuat sangat cepat. Situs yang dihasilkan secara statis memang memiliki beberapa kelemahan, yang terbesar adalah ketika Anda membutuhkan sesuatu yang dinamis untuk diintegrasikan ke dalam halaman Anda (misalnya komentar). Tidak dapat meng-host konten dinamis dengan mudah berarti Anda akhirnya mengandalkan JavaScript pihak ketiga yang kemudian akan mendapatkan akses penuh ke halaman Anda dan Anda tidak akan tahu apa yang dilakukannya - itu bisa melacak pengguna Anda atau memperlambat halaman Anda beban.

Read More

Creating a pop-out iframe with adoptNode and "magic iframes"

Paul Kinlan

Pembaruan: 8 Oktober - Masalah signifikan dengan dokumen ini. Saya terjebak dengan Jake Archibald tentang pos ini karena saya pikir saya memiliki sesuatu yang baru, selama percakapan kami menemukan banyak hal yang membuat beberapa pos ini tidak valid, dan saya juga belajar banyak dalam proses yang menurut saya sebagian besar pengembang tidak tahu. Memanggil .append() dan .appendChild() mengadopsi node. Ini membuat penggunaan adoptNode dalam contoh ini menjadi tidak berguna karena append Algoritma memastikan bahwa node diadopsi.

Read More

Meatspace Augmented Reality: From Chester to Nagoya

Paul Kinlan

Some thoughts on AR after finding some during my travels. TL;DR - cheaper content creation and better discovery tools are needed.

Read More

Photos from Carlisle Castle

Paul Kinlan

Saya baru-baru ini pergi berlibur dengan anak laki-laki dan kami berayun melewati Carlisle Castle (tempat kelahiran dunia rebound Jake Archibald). Ini adalah salah satu kastil yang lebih baik yang pernah kami kunjungi di Inggris dan saya sungguh-sungguh merekomendasikan untuk menghabiskan waktu mengunjunginya jika Anda berada di area tersebut. Saya tidak seberapa penting peran yang dimainkan Kastil Carlisle dalam sejarah Inggris dan Skotlandia, dan itu bagus untuk mengetahui lebih banyak sementara kami berada di sana.

Read More

Idle observation: Indexing text in images

Paul Kinlan

Saya keluar dengan anak-anak lelaki di Llangollen tempo hari (itu adalah kota yang indah) dan saya mengambil gambar tanda-tanda informasi yang berisi beberapa sejarah daerah sehingga saya bisa membacanya nanti, dan saya berpikir bahwa saya akan melihat pada web untuk melihat apakah informasi itu tersedia untuk lebih dari sekedar orang yang berjalan melewati tanda - dan itu tidak. Saya kemudian berpikir tentang selebaran, konten di dalamnya hampir tidak mungkin ditemukan di web.

Read More

Liverpool World Museum

Paul Kinlan

Saya membawa anak-anak ke Liverpool World History Museum minggu lalu, itu cukup rapi. Bagian Ruang dan Waktu tidak berubah dalam sekitar 30 tahun, sebagian besar kandang Bug ditutup, dan Akuarium tampak sedikit lebih kecil daripada yang kuingat. Bagian Mesir terbuka (bukan ketika saya pergi terakhir) dan itu agak mengagumkan.

Read More

Bookstore - Llangollen

Paul Kinlan

Saya suka tempat ini, ada di atas sebuah kafe di Llangollen. Saya datang ke sini bersama kakek-nenek saya hampir 30 tahun yang lalu dan itu hampir sama sekarang. Satu-satunya harapan saya adalah bahwa ada lebih banyak buku Commix - saya bersumpah ada tumpukan lebih ketika saya masih kecil. Check it out

Read More

Webmention.app🔗

Paul Kinlan

Saya menyukai gagasan Webmentions , namun saya belum punya waktu untuk mengimplementasikannya di situs saya. Pada web tingkat tinggi, Anda dapat berkomentar, menyukai, dan membalas konten lain di web dan membuatnya dapat dilihat oleh konten itu tanpa dipusatkan dengan alat-alat seperti Disqus (yang ingin saya hapus dari situs saya).

Sebutan Web dibagi menjadi dua komponen, pengirim dan penerima. Penerima adalah situs tempat saya menulis posting dan mereka mungkin memiliki sesuatu di situs mereka yang menunjukkan tautan masuk atau reaksi ke blog mereka; dan pengirimnya adalah, yah, saya. Saya perlu membiarkan situs jarak jauh yang saya tulis atau bereaksi terhadap beberapa konten yang mereka buat.

Remy Sharp agak luar Remy Sharp menciptakan webmention.app untuk menyelesaikan satu bagian dari masalah: mengirim ping. Alat Remy memudahkan untuk mengirim 'ping' ke penerima potensial yang telah saya tautkan, hanya dengan memanggil skrip CLI.

Saya meng-host blog saya menggunakan Zeit menggunakan Hugo dan alat pembangun statis, jadi itu relatively trivial for me to add in support for webmention app . Saya hanya npm i webmention dan kemudian memanggil versi CLI alat dari file build.sh saya - itu benar-benar sederhana.

Sekarang ketika saya membuat posting, itu harus mengirim ping cepat ke semua URL baru yang saya buat beberapa konten tentang situs mereka.

Creating a commit with multiple files to Github with JS on the web

Paul Kinlan

Situs saya adalah entirely static . Dibangun dengan Hugo dan di-host dengan Zeit . Saya cukup senang dengan pengaturannya, saya mendapatkan build instan dan pengiriman konten CDN yang sangat cepat dan saya dapat melakukan semua hal yang saya perlukan karena saya tidak perlu mengatur keadaan apa pun. Saya telah membuat simple UI untuk situs ini dan juga podcast creator saya yang memungkinkan saya untuk dengan cepat mengirim konten baru ke situs saya yang dihosting secara statis.

Read More

Screen Recorder: recording microphone and the desktop audio at the same time🔗

Paul Kinlan

Saya memiliki tujuan membangun perangkat lunak perekaman layar paling sederhana di dunia dan saya perlahan-lahan mencari-cari proyek selama beberapa bulan terakhir (maksud saya benar-benar lambat).

Dalam posting sebelumnya, saya telah mendapatkan screen recording and a voice overlay dengan screen recording and a voice overlay - screen recording and a voice overlay dengan aliran dari semua sumber input. Satu hal yang membuat frustrasi adalah saya tidak dapat menemukan cara untuk mendapatkan audio dari desktop * dan * overlay audio dari speaker. Saya akhirnya berhasil melakukannya.

Pertama, getDisplayMedia di Chrome sekarang memungkinkan penangkapan audio, sepertinya ada kekeliruan yang aneh dalam Spec karena itu tidak memungkinkan Anda untuk menentukan audio: true dalam pemanggilan fungsi, sekarang Anda bisa.

const audio = audioToggle.checked || false;
desktopStream = await navigator.mediaDevices.getDisplayMedia({ video:true, audio: audio });

Kedua, saya awalnya berpikir bahwa dengan membuat dua lagu dalam aliran audio saya akan bisa mendapatkan apa yang saya inginkan, namun saya belajar bahwa API MediaRecorder Chrome hanya dapat menghasilkan satu lagu, dan ke-2, itu tidak akan berhasil karena trek seperti DVD trek audio mutliple di mana hanya satu yang dapat diputar pada satu waktu.

Solusinya mungkin sederhana bagi banyak orang, tetapi itu baru bagi saya: Gunakan Audio Web.

Ternyata WebAudio API memiliki createMediaStreamSource dan createMediaStreamDestination , keduanya merupakan API yang diperlukan untuk menyelesaikan masalah. createMediaStreamSource dapat mengambil stream dari audio desktop dan mikrofon saya, dan dengan menghubungkan keduanya bersama-sama ke objek yang dibuat oleh createMediaStreamDestination itu memberi saya kemampuan untuk menyalurkan aliran yang satu ini ke dalam MediaRecorder API.

const mergeAudioStreams = (desktopStream, voiceStream) => {
  const context = new AudioContext();
    
  // Create a couple of sources
  const source1 = context.createMediaStreamSource(desktopStream);
  const source2 = context.createMediaStreamSource(voiceStream);
  const destination = context.createMediaStreamDestination();
  
  const desktopGain = context.createGain();
  const voiceGain = context.createGain();
    
  desktopGain.gain.value = 0.7;
  voiceGain.gain.value = 0.7;
   
  source1.connect(desktopGain).connect(destination);
  // Connect source2
  source2.connect(voiceGain).connect(destination);
    
  return destination.stream.getAudioTracks();
};

Sederhana.

Kode lengkap dapat ditemukan di my glitch , dan demo dapat ditemukan di sini: https://screen-record-voice.glitch.me/

{{<fast-youtube oGIdqcMFKlA>}}

Extracting text from an image: Experiments with Shape Detection🔗

Paul Kinlan

Saya memiliki sedikit waktu luang setelah Google IO dan saya ingin menggaruk gatal jangka panjang yang saya alami. Saya hanya ingin dapat menyalin teks yang disimpan di dalam gambar di browser. Itu semuanya. Saya pikir itu akan menjadi fitur yang rapi untuk semua orang.

Tidak mudah untuk menambahkan fungsionalitas secara langsung ke Chrome, tetapi saya tahu saya dapat memanfaatkan sistem niat di Android dan sekarang saya dapat melakukannya dengan Web (atau setidaknya Chrome di Android).

Dua tambahan baru pada platform web - Target Target Level 2 (atau seperti saya suka menyebutnya File Share) dan TextDetector di Shape Detection API - have allowed me to build a utility that I can Share images to and get the text held inside them .

Implementasi dasar relatif lurus ke depan, Anda membuat Target Saham dan penangan di Pekerja Layanan, dan kemudian setelah Anda memiliki gambar bahwa pengguna telah berbagi Anda menjalankan TextDetector di atasnya.

Share Target API memungkinkan aplikasi web Anda menjadi bagian dari sub-sistem berbagi asli, dan dalam hal ini Anda sekarang dapat mendaftar untuk menangani semua jenis image/* dengan mendeklarasikannya di dalam Web App Manifest Anda sebagai berikut.

"share_target": {
  "action": "/index.html",
  "method": "POST",
  "enctype": "multipart/form-data",
  "params": {
    "files": [
      {
        "name": "file",
        "accept": ["image/*"]
      }
    ]
  }
}

Ketika PWA Anda diinstal maka Anda akan melihatnya di semua tempat Anda berbagi gambar sebagai berikut:

API Share Target memperlakukan file berbagi seperti pos formulir. Ketika file dibagikan ke Aplikasi Web pekerja layanan diaktifkan penangan fetch dipanggil dengan data file. Data sekarang di dalam Pekerja Layanan tetapi saya membutuhkannya di jendela saat ini sehingga saya bisa memprosesnya, layanan tahu jendela mana yang memohon, sehingga Anda dapat dengan mudah menargetkan klien dan mengirimkannya data.

self.addEventListener('fetch', event => {
  if (event.request.method === 'POST') {
    event.respondWith(Response.redirect('/index.html'));
    event.waitUntil(async function () {
      const data = await event.request.formData();
      const client = await self.clients.get(event.resultingClientId || event.clientId);
      const file = data.get('file');
      client.postMessage({ file, action: 'load-image' });
    }());
    
    return;
  }
  ...
  ...
}

Setelah gambar berada di antarmuka pengguna, saya kemudian memprosesnya dengan API deteksi teks.

navigator.serviceWorker.onmessage = (event) => {  
  const file = event.data.file;
  const imgEl = document.getElementById('img');
  const outputEl = document.getElementById('output');
  const objUrl = URL.createObjectURL(file);
  imgEl.src = objUrl;
  imgEl.onload = () => {
    const texts = await textDetector.detect(imgEl);
    texts.forEach(text => {
      const textEl = document.createElement('p');
      textEl.textContent = text.rawValue;
      outputEl.appendChild(textEl);
    });
  };
  ...
};

Masalah terbesar adalah bahwa browser tidak memutar gambar secara alami (seperti yang Anda lihat di bawah), dan Shape Detection API membutuhkan teks berada dalam orientasi membaca yang benar.

Saya menggunakan EXIF-Js library agak mudah digunakan untuk mendeteksi rotasi dan kemudian melakukan beberapa manipulasi kanvas dasar untuk mengarahkan ulang gambar.

EXIF.getData(imgEl, async function() {
  // http://sylvana.net/jpegcrop/exif_orientation.html
  const orientation = EXIF.getTag(this, 'Orientation');
  const [width, height] = (orientation > 4) 
                  ? [ imgEl.naturalWidth, imgEl.naturalHeight ]
                  : [ imgEl.naturalHeight, imgEl.naturalWidth ];

  canvas.width = width;
  canvas.height = height;
  const context = canvas.getContext('2d');
  // We have to get the correct orientation for the image
  // See also https://stackoverflow.com/questions/20600800/js-client-side-exif-orientation-rotate-and-mirror-jpeg-images
  switch(orientation) {
    case 2: context.transform(-1, 0, 0, 1, width, 0); break;
    case 3: context.transform(-1, 0, 0, -1, width, height); break;
    case 4: context.transform(1, 0, 0, -1, 0, height); break;
    case 5: context.transform(0, 1, 1, 0, 0, 0); break;
    case 6: context.transform(0, 1, -1, 0, height, 0); break;
    case 7: context.transform(0, -1, -1, 0, height, width); break;
    case 8: context.transform(0, -1, 1, 0, 0, width); break;
  }
  context.drawImage(imgEl, 0, 0);
}

Dan Voila, jika Anda berbagi gambar ke aplikasi itu akan memutar gambar dan kemudian menganalisanya mengembalikan hasil teks yang telah ditemukan.

Sangat menyenangkan untuk membuat eksperimen kecil ini, dan ini langsung berguna bagi saya. Namun demikian, sorot inconsistency of the web platform . API ini tidak tersedia di semua browser, mereka bahkan tidak tersedia di semua versi Chrome - ini berarti bahwa ketika saya menulis artikel ini Chrome OS, saya tidak bisa menggunakan aplikasi, tetapi pada saat yang sama, ketika saya bisa menggunakannya ... OMG, sangat keren.

Wood Carving found in Engakuji Shrine near Kamakura

Sakura

Paul Kinlan

Saya diberitahu bahwa lebih khusus bahwa ini adalah 'Yaezakura'

Read More