1!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._posthogChunkIds=e._posthogChunkIds||{},e._posthogChunkIds[n]="01a0f726-7ddf-75e1-8659-bddf4e37c3c2")}catch(e){}}();import{c as O,d as D,u as B,r as s,j as e,o as W,B as v,U as Y}from"./index-DCg2N-ax.js";import{T as _}from"./tool-page-xyzZDU_k.js";import{I as z}from"./input-DF5Vgg2m.js";import{D as I}from"./download-C-n2vFkf.js";/** 2 * @license lucide-react v0.453.0 - ISC 3 * 4 * This source code is licensed under the ISC license. 5 * See the LICENSE file in the root directory of this source tree. 6 */const A=O("Images",[["path",{d:"M18 22H4a2 2 0 0 1-2-2V6",key:"pblm9e"}],["path",{d:"m22 13-1.296-1.296a2.41 2.41 0 0 0-3.408 0L11 18",key:"nf6bnh"}],["circle",{cx:"12",cy:"8",r:"2",key:"1822b1"}],["rect",{width:"16",height:"16",x:"6",y:"2",rx:"2",key:"12espp"}]]);function Q(o,u){return new Promise((i,w)=>{const n=Math.min(u,Math.max(0,o.duration-.01));if(Math.abs(o.currentTime-n)<.001&&o.readyState>=2){i();return}const h=()=>{p(),i()},f=()=>{p(),w(new Error("seek"))},p=()=>{o.removeEventListener("seeked",h),o.removeEventListener("error",f)};o.addEventListener("seeked",h,{once:!0}),o.addEventListener("error",f,{once:!0}),o.currentTime=n})}function te(){D();const{logEvent:o}=B(),u=s.useRef(null),[i,w]=s.useState(""),[n,h]=s.useState(""),[f,p]=s.useState(0),[y,U]=s.useState(0),[j,M]=s.useState(0),[b,N]=s.useState("6"),[d,E]=s.useState("jpeg"),[m,k]=s.useState([]),[c,P]=s.useState(!1),[C,x]=s.useState(""),F=()=>{m.forEach(t=>URL.revokeObjectURL(t.url)),k([])},R=t=>{n&&URL.revokeObjectURL(n),F();const a=URL.createObjectURL(t);h(a),w(t.name),x("");const r=document.createElement("video");r.preload="metadata",r.onloadedmetadata=()=>{p(r.duration),U(r.videoWidth),M(r.videoHeight)},r.onerror=()=>x("Could not read this file. Try an MP4, WebM, or MOV video."),r.src=a},$=async()=>{if(!n||c)return;const t=Math.max(1,Math.min(12,Math.round(Number(b)||1)));N(String(t)),P(!0),x(""),F();try{const a=document.createElement("video");a.muted=!0,a.playsInline=!0,a.preload="auto",a.src=n,await new Promise((l,g)=>{a.onloadeddata=()=>l(),a.onerror=()=>g(new Error("decode"))});const r=document.createElement("canvas");r.width=a.videoWidth,r.height=a.videoHeight;const T=r.getContext("2d",{alpha:!1});if(!T)throw new Error("canvas");const G=[],H=d==="png"?"png":"jpg",V=d==="png"?"image/png":"image/jpeg";for(let l=0;l<t;l+=1){const g=t===1?a.duration/2:a.duration*l/(t-1);await Q(a,g),T.drawImage(a,0,0,r.width,r.height);const L=await new Promise(J=>r.toBlob(J,V,d==="jpeg"?.92:void 0));if(!L)throw new Error("encode");G.push({url:URL.createObjectURL(L),time:g,name:`${i.replace(/\.[^.]+$/,"")||"video"}-frame-${String(l+1).padStart(2,"0")}.${H}`})}k(G),o("seo_tool_used",void 0,{slug:"video-frame-extractor",frames:t,format:d})}catch{x("Frame extraction failed. Try an MP4 (H.264) file in Chrome, Edge, or Firefox.")}finally{P(!1)}},S=t=>{const a=document.createElement("a");a.href=t.url,a.download=t.name,a.click()},q=()=>{m.forEach((t,a)=>window.setTimeout(()=>S(t),a*150))};return e.jsx("div",{className:"opus-home",style:W,children:e.jsx(_,{slug:"video-frame-extractor",metaTitle:"Video Frame Extractor, Free and Private | Viddler",metaDescription:"Extract frames from a video as full-resolution JPG or PNG images. Pick 1 to 12 evenly spaced frames. Free, private, and no upload.",heroTitle:"Video frame extractor",heroSubtitle:"Turn moments from a video into full-resolution JPG or PNG images. Choose how many frames you want. Your video stays on your device.",faqs:[{q:"How do I extract frames from a video?",a:"Choose a video, enter how many frames you want, select JPG or PNG, then click Extract frames. The tool captures evenly spaced moments from the full video."},{q:"Can I save a video frame as an image?",a:"Yes. Each extracted frame has its own download button. You can save it as a JPG or PNG at the source video's full resolution."},{q:"How are the frame times selected?",a:"The tool spaces frames evenly from the start to the end of the video. One frame captures the midpoint. Twelve frames give you a broad visual overview of the clip."},{q:"Should I choose JPG or PNG?",a:"Choose JPG for smaller files and photos. Choose PNG when you want lossless output for graphics, slides, or further editing. Both formats keep the source frame dimensions."},{q:"Is the video uploaded anywhere?",a:"No. Your browser reads the video and creates the images locally. The source file and extracted frames never leave your device, and there is no watermark."}],ctaTitle:"Found the right frame? Share the full story.",ctaSubtitle:"Host the original video on Viddler for an ad-free embed and per-viewer watch tracking.",children:e.jsxs("div",{className:"space-y-5",children:[e.jsxs("div",{className:"flex flex-wrap items-center gap-3",children:[e.jsxs(v,{type:"button",variant:"outline",onClick:()=>{var t;return(t=u.current)==null?void 0:t.click()}
6,disabled:c,children:[e.jsx(Y,{className:"h-4 w-4 mr-2","aria-hidden":"true"}),"Choose video"]}),e.jsx("input",{ref:u,type:"file",accept:"video/mp4,video/webm,video/quicktime,video/*",className:"hidden",onChange:t=>{var r;const a=(r=t.target.files)==null?void 0:r[0];a&&R(a),t.target.value=""}}),i&&e.jsxs("span",{className:"text-sm text-muted-foreground",children:[i,y?` (${y}Ã${j}, ${f.toFixed(1)}s)`:""]})]}),n&&e.jsx("video",{src:n,controls:!0,muted:!0,playsInline:!0,className:"max-h-64 max-w-full rounded-lg border border-border"}),e.jsxs("div",{className:"grid sm:grid-cols-2 gap-4 max-w-lg",children:[e.jsxs("label",{className:"text-sm space-y-1.5",children:[e.jsx("span",{className:"text-muted-foreground",children:"Number of frames"}),e.jsx(z,{type:"number",min:"1",max:"12",value:b,onChange:t=>N(t.target.value),disabled:c})]}),e.jsxs("fieldset",{disabled:c,className:"text-sm",children:[e.jsx("legend",{className:"text-muted-foreground mb-2",children:"Image format"}),e.jsxs("div",{className:"flex gap-4",children:[e.jsxs("label",{className:"flex items-center gap-2",children:[e.jsx("input",{type:"radio",name:"frame-format",checked:d==="jpeg",onChange:()=>E("jpeg"),className:"accent-primary"})," JPG"]}),e.jsxs("label",{className:"flex items-center gap-2",children:[e.jsx("input",{type:"radio",name:"frame-format",checked:d==="png",onChange:()=>E("png"),className:"accent-primary"})," PNG"]})]})]})]}),e.jsxs(v,{type:"button",onClick:$,disabled:!n||c,children:[e.jsx(A,{className:"h-4 w-4 mr-2","aria-hidden":"true"}),c?"Extracting frames":"Extract frames"]}),C&&e.jsx("p",{className:"text-sm text-destructive",role:"alert",children:C}),m.length>0&&e.jsxs("div",{className:"border-t border-border pt-5 space-y-4",children:[e.jsxs("div",{className:"flex flex-wrap items-center justify-between gap-3",children:[e.jsxs("p",{className:"font-medium text-foreground",children:[m.length," frames at ",y,"Ã",j]}),e.jsxs(v,{type:"button",variant:"outline",onClick:q,children:[e.jsx(I,{className:"h-4 w-4 mr-2","aria-hidden":"true"}),"Download all"]})]}),e.jsx("div",{className:"grid grid-cols-2 sm:grid-cols-3 gap-4",children:m.map(t=>e.jsxs("figure",{className:"space-y-2",children:[e.jsx("img",{src:t.url,alt:`Video frame at ${t.time.toFixed(1)} seconds`,className:"w-full rounded-lg border border-border"}),e.jsxs("div",{className:"flex items-center justify-between gap-2",children:[e.jsxs("figcaption",{className:"text-xs text-muted-foreground",children:[t.time.toFixed(1),"s"]}),e.jsx(v,{type:"button",variant:"ghost",size:"sm",onClick:()=>S(t),"aria-label":`Download frame at ${t.time.toFixed(1)} seconds`,children:e.jsx(I,{className:"h-4 w-4","aria-hidden":"true"})})]})]},t.url))})]})]})})})}export{te as default}; 7 8//# chunkId=01a0f726-7ddf-75e1-8659-bddf4e37c3c2
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.