如何在Android平台用Java打开Skim笔记文件(.skim)
Android导入Skim(.skim)笔记文件的实现思路与示例代码
一、先明确Skim文件的本质
Skim的.skim文件是XML格式的Apple Property List(plist),内部存储了PDF关联的所有笔记数据,包括高亮、批注、下划线、页码、位置坐标、笔记内容等核心信息。实现导入的核心是解析该plist文件,再将数据映射到你现有App的笔记系统中。
二、核心实现步骤与代码示例
1. 读取并解析XML plist
Android原生可通过XmlPullParser解析XML格式的plist,也可使用第三方plist解析库简化操作。以下是原生解析的核心代码片段:
// 假设已获取.skim文件的输入流 InputStream inputStream = new FileInputStream(skimFile); XmlPullParser parser = Xml.newPullParser(); parser.setInput(inputStream, "UTF-8"); int eventType = parser.getEventType(); boolean inNotesArray = false; boolean inNoteItem = false; HashMap<String, String> currentNote = null; List<HashMap<String, String>> skimNotes = new ArrayList<>(); while (eventType != XmlPullParser.END_DOCUMENT) { String tagName = parser.getName(); switch (eventType) { case XmlPullParser.START_TAG: if ("array".equals(tagName)) { String key = parser.getAttributeValue(null, "key"); if ("Notes".equals(key)) { inNotesArray = true; } } else if ("dict".equals(tagName) && inNotesArray) { inNoteItem = true; currentNote = new HashMap<>(); } else if ("key".equals(tagName) && inNoteItem) { String key = parser.nextText(); eventType = parser.next(); if (eventType == XmlPullParser.TEXT) { currentNote.put(key, parser.getText()); } } break; case XmlPullParser.END_TAG: if ("dict".equals(tagName) && inNoteItem) { inNoteItem = false; skimNotes.add(currentNote); } else if ("array".equals(tagName) && inNotesArray) { inNotesArray = false; } break; } eventType = parser.next(); } inputStream.close();
2. 解析Skim笔记的关键字段
每个Skim笔记条目(dict节点)的核心字段:
Type:笔记类型,如Highlight(高亮)、Note(批注)、Underline(下划线)Page:关联的PDF页码(从1开始,与多数PDF渲染库规则一致)Content:批注文本内容(仅Note类型包含)Rect:笔记在PDF页面的位置,格式为x,y,width,height(PDF坐标原点在左下角)Color:笔记颜色,格式为RGB值(如1.0,0.0,0.0代表红色)
3. 映射到现有笔记系统
将解析出的Skim数据转换为你App的笔记模型,示例如下:
// 假设你已有NoteModel类,包含type、page、content、rect、color等字段 List<NoteModel> appNotes = new ArrayList<>(); for (HashMap<String, String> skimNote : skimNotes) { NoteModel note = new NoteModel(); // 映射笔记类型 String skimType = skimNote.get("Type"); if ("Highlight".equals(skimType)) { note.setType(NoteModel.TYPE_HIGHLIGHT); } else if ("Note".equals(skimType)) { note.setType(NoteModel.TYPE_NOTE); note.setContent(skimNote.get("Content")); } else if ("Underline".equals(skimType)) { note.setType(NoteModel.TYPE_UNDERLINE); } // 映射页码 note.setPage(Integer.parseInt(skimNote.get("Page"))); // 映射位置Rect(需注意坐标转换) String rectStr = skimNote.get("Rect"); String[] rectParts = rectStr.split(","); float x = Float.parseFloat(rectParts[0]); float y = Float.parseFloat(rectParts[1]); float width = Float.parseFloat(rectParts[2]); float height = Float.parseFloat(rectParts[3]); // PDF原点在左下角,若你的视图原点在左上角,需转换y坐标:y = pageHeight - y - height note.setRect(new RectF(x, y, x + width, y + height)); // 映射颜色 String colorStr = skimNote.get("Color"); String[] colorParts = colorStr.split(","); float r = Float.parseFloat(colorParts[0]); float g = Float.parseFloat(colorParts[1]); float b = Float.parseFloat(colorParts[2]); note.setColor(Color.rgb((int)(r*255), (int)(g*255), (int)(b*255))); appNotes.add(note); } // 将转换后的笔记存入现有存储 yourNoteManager.addNotes(appNotes);
三、注意事项
- 部分
.skim文件为二进制plist格式,需先转换为XML格式再解析,可使用Android端二进制plist解析库处理。 - 坐标转换:PDF坐标原点在左下角,Android视图原点通常在左上角,需根据PDF页面高度调整y坐标。
- 扩展支持:Skim还支持
StrikeThrough(删除线)等类型,可按需扩展映射逻辑。
内容的提问来源于stack exchange,提问作者Gin371
相关产品推荐
相关产品推荐

