jon-heard / obsidian-inline-scripts

Obsidian plugin: Type text shortcuts that expand into javascript generated text.
MIT License
129 stars 4 forks source link

cannot import deck #74

Open cristianmtr opened 1 year ago

cristianmtr commented 1 year ago

Hello,

I am trying to import from a folder of JPGs into a deck.

Obsidian 1.2.7, Windows 10, plugin version 0.24.12

``` Inline Scripts SHORTCUT-EXPANSION-ERROR Cannot read properties of null (reading '0') line,column: 170,20 shortcut-text: "cards fromfolder horror support/gmahorror" ──────────────────── 0001 // Trigger the event callback calls for a change in what piles are available 0002 function onPileListChanged() 0003 { 0004 _inlineScripts.inlineScripts.HelperFncs. 0005 callEventListenerCollection( 0006 "cards.onPileListChanged", 0007 _inlineScripts.cards.listeners.onPileListChanged); 0008 } 0009 0010 // Trigger the event callback calls for a change in a pile 0011 function onPileChanged(pileName) 0012 { 0013 _inlineScripts.cards.listeners.changedPile = pileName; 0014 _inlineScripts.inlineScripts.HelperFncs. 0015 callEventListenerCollection( 0016 "cards.onPileChanged", 0017 _inlineScripts.cards.listeners.onPileChanged); 0018 } 0019 0020 // Get the current back-image, url 0021 function getBackImage() 0022 { 0023 return _inlineScripts.state.sessionState.cards.backImage || 0024 _inlineScripts.cards.defaultBackImage; 0025 } 0026 0027 // Turn a relative path url into an absolute path url based in the vault's root 0028 function getAbsolutePath(path) 0029 { 0030 if (path.startsWith("data:image")) { return path; } 0031 path = app.vault.fileMap[path]; 0032 if (!path) { return ""; } 0033 return app.vault.getResourcePath(path); 0034 } 0035 0036 // Create a block of html to represent a specific card 0037 function createCardUi(isFaceUp, card, id, scale, includeDataSrc) 0038 { 0039 const result = document.createElement("img"); 0040 result.classList.add("cardUi"); 0041 result.src = getAbsolutePath(isFaceUp ? card.path : getBackImage()); 0042 const size = _inlineScripts.state.sessionState.cards.size * (scale || 1.0); 0043 result.style.width = size + "px"; 0044 result.style.height = (size * card.aspect) + "px"; 0045 result.dataset.id = id; 0046 if (includeDataSrc) 0047 { 0048 result.dataset.src = getAbsolutePath(card.path); 0049 } 0050 if (isFaceUp) 0051 { 0052 switch (card.rotation) 0053 { 0054 case 1: result.classList.add("rotated1"); break; 0055 case 2: result.classList.add("rotated2"); break; 0056 case 3: result.classList.add("rotated3"); break; 0057 } 0058 } 0059 return result; 0060 } 0061 0062 // Create a block of markdown to represent a specific card 0063 function createCardUi_inNote(isFaceUp, card) 0064 { 0065 // Figure out what image to use 0066 let path = isFaceUp ? card.path : getBackImage(); 0067 0068 // Generate and return the text for the markdown card ui 0069 const alt = (!card.rotation || !isFaceUp) ? "" : "rotated" + card.rotation; 0070 const width = _inlineScripts.state.sessionState.cards.size; 0071 const height = Math.trunc(width * card.aspect); 0072 return "![" + alt + "|" + width + "x" + height + "](<" + path + ">) "; 0073 } 0074 let $1 = "horror"; 0075 let $2 = "support/gmahorror"; 0076 // Remove quotes around the path 0077 $2 = $2.replace(/^"(.*)"$/, "$1") 0078 0079 // Get the pile, early out if it doesnt exist 0080 const pile = _inlineScripts.state.sessionState.cards.piles[$1]; 0081 if (!pile) 0082 { 0083 return expFormat( 0084 "Cards not created. The __" + $1 + "__ card-pile was not found."); 0085 } 0086 0087 const folder = app.vault.fileMap[$2]; 0088 0089 // Early out if specified folder (to get cards from) doesn't exist or isn't a folder 0090 if (!folder) 0091 { 0092 return expFormat("Cards not created. Folder __" + $2 + "__ was not found."); 0093 } 0094 if (!folder.children) 0095 { 0096 return expFormat("Cards not created. __" + $2 + "__ is not a folder."); 0097 } 0098 0099 // Helper function - Get an image size by loading and reading its binary content 0100 // Note - has a reliable, but slow backup function "getImageSize_reliable" 0101 async function getImageSize_fast(file) 0102 { 0103 // Testing line 0104 //file = app.vault.fileMap[file]; 0105 0106 // Helper function - turn 4 bytes into an integer 0107 function bytesToInt(v1, v2, v3, v4) 0108 { 0109 return (v1 << 24) + (v2 << 16) + (v3 << 8) + v4; 0110 } 0111 0112 // Load the image's entire binary data (could optimize by not loading all) 0113 const b = new Uint8Array(await app.vault.readBinary(file)); 0114 0115 // Return value initialization 0116 let result = null; 0117 0118 // If PNG file, read size 0119 if (b[1] === 80 && b[2] === 78 && b[3] === 71) 0120 { 0121 result = [ bytesToInt(b[16], b[17], b[18], b[19]), 0122 bytesToInt(b[20], b[21], b[22], b[23]) ]; 0123 } 0124 0125 // If GIF file, read size 0126 else if (b[0] === 71 && b[1] === 73 && b[2] === 70) 0127 { 0128 result = [ bytesToInt(0, 0, b[7], b[6]), 0129 bytesToInt(0, 0, b[9], b[8]) ]; 0130 } 0131 0132 // If BMP file, read size 0133 else if (b[0] === 66 && b[1] === 77) 0134 { 0135 result = [ bytesToInt(b[21], b[20], b[19], b[18]), 0136 bytesToInt(b[25], b[24], b[23], b[22]) ]; 0137 } 0138 0139 // If JPG file, read size 0140 // Note - (JFIF) - https://stackoverflow.com/a/48488655 & further answers 0141 else if (b[0] === 255 && b[1] === 216 && b[2] === 255 && b[3] === 224 && 0142 b[6] === 74 && b[7] === 70 && b[8] === 73 && b[9] === 70 && b[10]===0) 0143 { 0144 let i = 0; 0145 while (i < b.length) 0146 { 0147 if (b[i] !== 255) { break; } 0148 while (b[i] === 255) { i++; } 0149 const mrk = b[i]; 0150 i++; 0151 0152 if(mrk === 1) { continue; } // TEM 0153 if(208 <= mrk && mrk <= 215) continue; 0154 if(mrk === 216) { continue; } // SOI 0155 if(mrk === 217) { break; } // EOI 0156 0157 const len = bytesToInt(0, 0, b[i], b[i+1]); 0158 if (192 <= mrk && mrk <= 207) // C0 to CF 0159 { 0160 i += 3; 0161 result = [ bytesToInt(0, 0, b[i+2], b[i+3]), 0162 bytesToInt(0, 0, b[i+0], b[i+1]) ]; 0163 break; 0164 } 0165 i += len; 0166 } 0167 } 0168 0169 // Return size, nicely formatted ------------------------v 0170 return { w: result[0], h: result[1] }; ------------------------^ 0171 } 0172 0173 // Helper function - Get image size by running image through html system 0174 // NOTE - is a backup for the fast method 0175 async function getImageSize_reliable(file) 0176 { 0177 let result = null; 0178 try 0179 { 0180 // Read in the binary 0181 const buf = await app.vault.readBinary(file); 0182 0183 // Convert binary to base64 0184 let binary = ''; 0185 const bytes = new Uint8Array(buf); 0186 bytes.forEach(b => binary += String.fromCharCode(b)); 0187 const base64Data = window.btoa(binary); 0188 0189 // Create image element, assign base-64 image to it, then read the size 0190 result = await new Promise((onDone) => 0191 { 0192 const i = new Image(1,1); 0193 i.src = `data:${i.type};base64,${base64Data}`; 0194 i.onload = () => 0195 { 0196 onDone({ w: i.naturalWidth, h: i.naturalHeight }); 0197 } 0198 i.onerror = () => 0199 { 0200 onDone(null); 0201 } 0202 }); 0203 } 0204 catch(e) {} 0205 0206 // Return the found image size 0207 return result; 0208 } 0209 0210 // Start expansion result 0211 let result = ""; 0212 0213 // Iterate over all children of the given folder 0214 let createCount = 0; 0215 for (let i = folder.children.length - 1; i >= 0; i--) 0216 { 0217 const childFile = folder.children[i]; 0218 // Ignore sub-folders 0219 if (childFile.children) { continue; } 0220 0221 // Get image size 0222 let size = await getImageSize_fast(childFile); 0223 if (!size) 0224 { 0225 size = await getImageSize_reliable(childFile); 0226 } 0227 0228 // If unable to get a card's size, it's not an image. 0229 // Add notification to the expansion. 0230 if (size == null) 0231 { 0232 result += "Unable to create card from file __" + childFile.name + "__.\n"; 0233 continue; 0234 } 0235 0236 // Create and add the card object based on the current image 0237 pile.cards.push( 0238 { 0239 path: childFile.path, 0240 rotation: 0, 0241 aspect: size.h / size.w, 0242 origin: $1 0243 }); 0244 createCount++; 0245 } 0246 0247 // Trigger the event of the pile changing, if any cards were actually added 0248 if (createCount) 0249 { 0250 onPileChanged($1); 0251 } 0252 0253 return expFormat( 0254 "__" + createCount + "__ cards added to the __" + $1 + "__ card-pile."); ```
skpy commented 1 year ago

I had a similar problem. I think there are some scenarios where it fails to parse EXIF data. Try converting your images to PNG and see if that works. That's what worked for me.

drewt333 commented 10 months ago

I used the file conversion work around, jpg -> png Worked without any problems.

Thanks!