* Helper function for loading GIF-based images
(arrayBuffer, pImg)
| 601 | * Helper function for loading GIF-based images |
| 602 | */ |
| 603 | async function _createGif(arrayBuffer, pImg) { |
| 604 | // TODO: Replace with ImageDecoder once it is widely available |
| 605 | // https://developer.mozilla.org/en-US/docs/Web/API/ImageDecoder |
| 606 | const gifReader = new omggif.GifReader(arrayBuffer); |
| 607 | pImg.width = pImg.canvas.width = gifReader.width; |
| 608 | pImg.height = pImg.canvas.height = gifReader.height; |
| 609 | const frames = []; |
| 610 | const numFrames = gifReader.numFrames(); |
| 611 | let framePixels = new Uint8ClampedArray(pImg.width * pImg.height * 4); |
| 612 | |
| 613 | const loadGIFFrameIntoImage = (frameNum, gifReader) => { |
| 614 | try { |
| 615 | gifReader.decodeAndBlitFrameRGBA(frameNum, framePixels); |
| 616 | } catch (e) { |
| 617 | p5._friendlyFileLoadError(8, pImg.src); |
| 618 | throw e; |
| 619 | } |
| 620 | }; |
| 621 | |
| 622 | for (let j = 0; j < numFrames; j++) { |
| 623 | const frameInfo = gifReader.frameInfo(j); |
| 624 | const prevFrameData = pImg.drawingContext.getImageData( |
| 625 | 0, |
| 626 | 0, |
| 627 | pImg.width, |
| 628 | pImg.height |
| 629 | ); |
| 630 | framePixels = prevFrameData.data.slice(); |
| 631 | loadGIFFrameIntoImage(j, gifReader); |
| 632 | const imageData = new ImageData(framePixels, pImg.width, pImg.height); |
| 633 | pImg.drawingContext.putImageData(imageData, 0, 0); |
| 634 | let frameDelay = frameInfo.delay; |
| 635 | // To maintain the default of 10FPS when frameInfo.delay equals to 0 |
| 636 | if (frameDelay === 0) { |
| 637 | frameDelay = 10; |
| 638 | } |
| 639 | frames.push({ |
| 640 | image: pImg.drawingContext.getImageData(0, 0, pImg.width, pImg.height), |
| 641 | delay: frameDelay * 10 //GIF stores delay in one-hundredth of a second, shift to ms |
| 642 | }); |
| 643 | |
| 644 | // Some GIFs are encoded so that they expect the previous frame |
| 645 | // to be under the current frame. This can occur at a sub-frame level |
| 646 | // |
| 647 | // Values : 0 - No disposal specified. The decoder is |
| 648 | // not required to take any action. |
| 649 | // 1 - Do not dispose. The graphic is to be left |
| 650 | // in place. |
| 651 | // 2 - Restore to background color. The area used by the |
| 652 | // graphic must be restored to the background color. |
| 653 | // 3 - Restore to previous. The decoder is required to |
| 654 | // restore the area overwritten by the graphic with |
| 655 | // what was there prior to rendering the graphic. |
| 656 | // 4-7 - To be defined. |
| 657 | if (frameInfo.disposal === 2) { |
| 658 | // Restore background color |
| 659 | pImg.drawingContext.clearRect( |
| 660 | frameInfo.x, |
no test coverage detected