{"record":{"id":"49b1698257d367d4","repo":"siyuan-note/siyuan","slug":"decode-heif-image-w","errorCode":null,"errorMessage":"decode HEIF image: %w","messagePattern":"decode HEIF image: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/heif/convert.go","lineNumber":198,"sourceCode":"\t\t\terr = fmt.Errorf(\"decode HEIF image: %v\", recovered)\n\t\t}\n\t}()\n\n\tconfig, err := goheic.DecodeConfigBytes(source)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"read HEIF image dimensions: %w\", err)\n\t}\n\tif !validDimensions(config.Width, config.Height) {\n\t\treturn nil, ErrImageTooLarge\n\t}\n\n\timg, err = goheic.DecodeBytes(source, goheic.Options{\n\t\tAutoRotate:     true,\n\t\tFrameSizeLimit: maxPixels,\n\t\tThreads:        1,\n\t})\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"decode HEIF image: %w\", err)\n\t}\n\treturn img, nil\n}\n\nfunc validDimensions(width, height int) bool {\n\treturn width > 0 && height > 0 && width <= maxDimension && height <= maxDimension &&\n\t\tuint64(width)*uint64(height) <= uint64(maxPixels)\n}\n\nfunc estimatedJPEGSize(img image.Image) int {\n\tpixels := int64(img.Bounds().Dx()) * int64(img.Bounds().Dy())\n\testimate := pixels / 2\n\tif estimate < 64*1024 {\n\t\testimate = 64 * 1024\n\t}\n\tif estimate > 32*1024*1024 {\n\t\testimate = 32 * 1024 * 1024\n\t}","sourceCodeStart":180,"sourceCodeEnd":216,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/9f775e8a12daef8255556097396f9b2739078892/kernel/heif/convert.go#L180-L216","documentation":"decodeImage wraps a failure from goheic.DecodeBytes (full pixel decode) as \"decode HEIF image: %w\", preserving the cause via %w. DecodeConfig succeeded (dimensions valid), but the actual lossy/lossless decode failed — e.g. frame size limit exceeded at full decode, unsupported codec profile, or decoder thread/alloc failure. Raised to convert and ImageSize callers.","triggerScenarios":"goheic.DecodeBytes returns error for a container whose header parsed fine: unsupported HEVC/AV1 profile, decoder-internal frame size limit hit despite validDimensions, corrupted tile data after the header.","commonSituations":"Exotic HEIF profiles (10-bit HDR, image sequences, aux images) the decoder rejects, bit-rot or bit-flips in compressed payload, decoder resource limits under memory pressure.","solutions":["Read the wrapped cause (errors.Unwrap) to distinguish profile-unsupported vs corrupt data","Re-encode the image to a standard 8-bit HEIC or JPEG using an external tool and re-import","Retry once in case of transient memory/alloc failure; if persistent, mark the asset corrupt"],"exampleFix":"// before\nresult, err := heif.GetOrCreate(ctx, data, opts)\nif err != nil { return err }\n// after\nresult, err := heif.GetOrCreate(ctx, data, opts)\nif err != nil {\n\tif strings.Contains(err.Error(), \"decode HEIF image:\") {\n\t\treturn fmt.Errorf(\"HEIF decode failed (unsupported profile or corrupt data): %v\", err)\n\t}\n\treturn err\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"result, err := heif.GetOrCreate(ctx, data, opts)\nif err != nil {\n\tif strings.Contains(err.Error(), \"decode HEIF image:\") && !strings.Contains(err.Error(), \"dimensions\") {\n\t\t// full decode failed after header ok: unsupported profile or corrupt payload\n\t}\n\treturn err\n}","preventionTips":["Prefer standard 8-bit SDR HEIC assets; exotic HDR/sequence profiles may not decode","Retry once for transient alloc failures, then mark corrupt","Unwrap the error to read the goheic cause for triage"],"tags":["heif","decoding","codec"],"backgroundTag":"file-read-failed","analyzedSha":"9f775e8a12daef8255556097396f9b2739078892","analyzedAt":"2026-09-19T03:17:15.984Z","contentChangedAt":"2026-09-19T03:17:15.984Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}