diff --git a/res/petpet/Nanomachine son/0.png b/res/petpet/Nanomachine son/0.png new file mode 100644 index 00000000..2892ca68 Binary files /dev/null and b/res/petpet/Nanomachine son/0.png differ diff --git a/res/petpet/Nanomachine son/1.png b/res/petpet/Nanomachine son/1.png new file mode 100644 index 00000000..c74611d7 Binary files /dev/null and b/res/petpet/Nanomachine son/1.png differ diff --git a/res/petpet/Nanomachine son/2.png b/res/petpet/Nanomachine son/2.png new file mode 100644 index 00000000..28d483fc Binary files /dev/null and b/res/petpet/Nanomachine son/2.png differ diff --git a/res/petpet/Nanomachine son/3.png b/res/petpet/Nanomachine son/3.png new file mode 100644 index 00000000..77c85085 Binary files /dev/null and b/res/petpet/Nanomachine son/3.png differ diff --git a/res/petpet/Nanomachine son/4.png b/res/petpet/Nanomachine son/4.png new file mode 100644 index 00000000..17b6c87a Binary files /dev/null and b/res/petpet/Nanomachine son/4.png differ diff --git a/res/petpet/Nanomachine son/5.png b/res/petpet/Nanomachine son/5.png new file mode 100644 index 00000000..e290fc95 Binary files /dev/null and b/res/petpet/Nanomachine son/5.png differ diff --git a/res/petpet/Nanomachine son/6.png b/res/petpet/Nanomachine son/6.png new file mode 100644 index 00000000..92165c29 Binary files /dev/null and b/res/petpet/Nanomachine son/6.png differ diff --git a/res/petpet/Nanomachine son/7.png b/res/petpet/Nanomachine son/7.png new file mode 100644 index 00000000..f348c3ae Binary files /dev/null and b/res/petpet/Nanomachine son/7.png differ diff --git a/res/petpet/Nanomachine son/data.json b/res/petpet/Nanomachine son/data.json new file mode 100644 index 00000000..6e909af8 --- /dev/null +++ b/res/petpet/Nanomachine son/data.json @@ -0,0 +1,18 @@ +{ + + "type": "GIF", + "avatar": "DOUBLE", + "pos": [ + [ + [90, 60, 70, 70],[88, 58, 70, 70],[80, 56, 70, 70],[70, 65, 70, 70], + [90, 98, 70, 70],[70, 102, 70, 70],[65, 120, 70, 70],[85, 85, 70, 70] + ],[ + [260, 5, 70, 70],[257, 0, 70, 70],[250, -10, 70, 70],[257, 0, 70, 70], + [260, 5, 70, 70],[257, 0, 70, 70],[260, 10, 70, 70],[270, 10, 70, 70] + ] + ], + "text": "", + "round": true, + "rotate": false, + "avatarOnTop": true +} \ No newline at end of file diff --git a/res/petpet/bite/data.json b/res/petpet/bite/data.json new file mode 100644 index 00000000..d104377a --- /dev/null +++ b/res/petpet/bite/data.json @@ -0,0 +1,14 @@ +{ + "type": "GIF", + "avatar": "SINGLE", + "pos": [ + [90, 90, 105, 150], [90, 83, 96, 172], [90, 90, 106, 148], + [88, 88, 97, 167], [90, 85, 89, 179], [90, 90, 106, 151], + [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], + [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0] + ], + "text": "", + "round": true, + "rotate": false, + "avatarOnTop": false +} diff --git a/res/petpet/hammer/data.json b/res/petpet/hammer/data.json new file mode 100644 index 00000000..2f055903 --- /dev/null +++ b/res/petpet/hammer/data.json @@ -0,0 +1,12 @@ +{ + "type": "GIF", + "avatar": "SINGLE", + "pos": [ + [62, 143, 158, 113], [52, 177, 173, 105], [42, 192, 192, 92], [46, 182, 184, 100], + [54, 169, 174, 110], [69, 128, 144, 135], [65, 130, 152, 124] + ], + "text": "", + "round": true, + "rotate": false, + "avatarOnTop": false +} diff --git a/res/petpet/kiss/data.json b/res/petpet/kiss/data.json new file mode 100644 index 00000000..36505938 --- /dev/null +++ b/res/petpet/kiss/data.json @@ -0,0 +1,18 @@ +{ + "type": "GIF", + "avatar": "DOUBLE", + "pos": [ + [ [92, 64, 40, 40], [135, 40, 40, 40], [84, 105, 40, 40], [80, 110, 40, 40], + [155, 82, 40, 40], [60, 96, 40, 40], [50, 80, 40, 40], [98, 55, 40, 40], + [35, 65, 40, 40], [38, 100, 40, 40], [70, 80, 40, 40], [84, 65, 40, 40], + [75, 65, 40, 40]], + [[58, 90, 50, 50], [62, 95, 50, 50], [42, 100, 50, 50], [50, 100, 50, 50], + [56, 100, 50, 50], [18, 120, 50, 50], [28, 110, 50, 50], [54, 100, 50, 50], + [46, 100, 50, 50], [60, 100, 50, 50], [35, 115, 50, 50], [20, 120, 50, 50], + [40, 96, 50, 50]] + ], + "text": "", + "round": true, + "rotate": false, + "avatarOnTop": true +} diff --git a/res/petpet/knock/data.json b/res/petpet/knock/data.json new file mode 100644 index 00000000..0c38f0e8 --- /dev/null +++ b/res/petpet/knock/data.json @@ -0,0 +1,12 @@ +{ + "type": "GIF", + "avatar": "SINGLE", + "pos": [ + [60, 308, 210, 195], [60, 308, 210, 198], [45, 330, 250, 172], [58, 320, 218, 180], + [60, 310, 215, 193], [40, 320, 250, 285], [48, 308, 226, 192], [51, 301, 223, 200] + ], + "text": "", + "round": true, + "rotate": false, + "avatarOnTop": false +} diff --git a/res/petpet/petpet/data.json b/res/petpet/petpet/data.json new file mode 100644 index 00000000..9279f427 --- /dev/null +++ b/res/petpet/petpet/data.json @@ -0,0 +1,12 @@ +{ + + "type": "GIF", + "avatar": "SINGLE", + "pos": [ + [14, 20, 98, 98], [12, 33, 101, 85], [8, 40, 110, 76], [10, 33, 102, 84], [12, 20, 98, 98] + ], + "text": "", + "round": true, + "rotate": false, + "avatarOnTop": false +} \ No newline at end of file diff --git a/res/petpet/play/data.json b/res/petpet/play/data.json new file mode 100644 index 00000000..810be147 --- /dev/null +++ b/res/petpet/play/data.json @@ -0,0 +1,18 @@ +{ + + "type": "GIF", + "avatar": "SINGLE", + "pos": [ + [180, 60, 100, 100], [184, 75, 100, 100], [183, 98, 100, 100], + [179, 118, 110, 100], [156, 194, 150, 48], [178, 136, 122, 69], + [175, 66, 122, 85], [170, 42, 130, 96], [175, 34, 118, 95], + [179, 35, 110, 93], [180, 54, 102, 93], [183, 58, 97, 92], + [174, 35, 120, 94], [179, 35, 109, 93], [181, 54, 101, 92], + [182, 59, 98, 92], [183, 71, 90, 96], [180, 131, 92, 101], + [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0] + ], + "text": "", + "round": true, + "rotate": false, + "avatarOnTop": false +} \ No newline at end of file diff --git a/res/petpet/pound/data.json b/res/petpet/pound/data.json new file mode 100644 index 00000000..eba54888 --- /dev/null +++ b/res/petpet/pound/data.json @@ -0,0 +1,13 @@ +{ + + "type": "GIF", + "avatar": "SINGLE", + "pos": [ + [135, 240, 138, 47], [135, 240, 138, 47], [150, 190, 105, 95], [150, 190, 105, 95], + [148, 188, 106, 98], [146, 196, 110, 88], [145, 223, 112, 61], [145, 223, 112, 61] + ], + "text": "", + "round": true, + "rotate": false, + "avatarOnTop": false +} \ No newline at end of file diff --git a/res/petpet/roll/data.json b/res/petpet/roll/data.json new file mode 100644 index 00000000..5c9a740d --- /dev/null +++ b/res/petpet/roll/data.json @@ -0,0 +1,13 @@ +{ + + "type": "GIF", + "avatar": "SINGLE", + "pos": [ + [87, 77, 220, 220], [96, 85, 220, 220], [92, 79, 220, 220], [92, 78, 220, 220], + [92, 75, 220, 220], [92, 75, 220, 220], [93, 76, 220, 220], [90, 80, 220, 220] + ], + "text": "", + "round": true, + "rotate": true, + "avatarOnTop": false +} \ No newline at end of file diff --git a/res/petpet/rub/data.json b/res/petpet/rub/data.json new file mode 100644 index 00000000..14d98518 --- /dev/null +++ b/res/petpet/rub/data.json @@ -0,0 +1,15 @@ +{ + + "type": "GIF", + "avatar": "DOUBLE", + "pos": [ + [[102, 95, 70, 80], [108, 60, 50, 100], [97, 18, 65, 95], + [65, 5, 75, 75], [95, 57, 100, 55], [109, 107, 65, 75]], + [[39, 91, 75, 75], [49, 101, 75, 75], [67, 98, 75, 75], + [55, 86, 75, 75], [61, 109, 75, 75], [65, 101, 75, 75]] + ], + "text": "", + "round": true, + "rotate": false, + "avatarOnTop": true +} \ No newline at end of file diff --git a/res/petpet/suck/data.json b/res/petpet/suck/data.json new file mode 100644 index 00000000..bf304d75 --- /dev/null +++ b/res/petpet/suck/data.json @@ -0,0 +1,14 @@ +{ + + "type": "GIF", + "avatar": "SINGLE", + "pos": [ + [82, 100, 130, 119], [82, 94, 126, 125], [82, 120, 128, 99], [81, 164, 132, 55], + [79, 163, 132, 55], [82, 140, 127, 79], [83, 152, 125, 67], [75, 157, 140, 62], + [72, 165, 144, 54], [80, 132, 128, 87], [81, 127, 127, 92], [79, 111, 132, 108] + ], + "text": "", + "round": true, + "rotate": false, + "avatarOnTop": false +} \ No newline at end of file diff --git a/res/petpet/throw/data.json b/res/petpet/throw/data.json new file mode 100644 index 00000000..f16ca03c --- /dev/null +++ b/res/petpet/throw/data.json @@ -0,0 +1,15 @@ +{ + + "type": "GIF", + "avatar": "DOUBLE", + "pos": [ + [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], + [289, 70, 33, 33], [280, 73, 32, 32], [259, 31, 35, 35], [-50, 220, 175, 175]], + [[108, 36, 32, 32], [122, 36, 32, 32], [0, 0, 0, 0], [19, 129, 123, 123], + [-50, 200, 185, 185], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]] + ], + "text": "", + "round": true, + "rotate": false, + "avatarOnTop": true +} \ No newline at end of file diff --git a/res/petpet/thump/data.json b/res/petpet/thump/data.json new file mode 100644 index 00000000..58698c80 --- /dev/null +++ b/res/petpet/thump/data.json @@ -0,0 +1,11 @@ +{ + "type": "GIF", + "avatar": "SINGLE", + "pos": [ + [65, 128, 77, 72], [67, 128, 73, 72], [54, 139, 94, 61], [57, 135, 86, 65] + ], + "text": "", + "round": true, + "rotate": false, + "avatarOnTop": false +} \ No newline at end of file diff --git a/res/petpet/tightly/data.json b/res/petpet/tightly/data.json new file mode 100644 index 00000000..6639c95d --- /dev/null +++ b/res/petpet/tightly/data.json @@ -0,0 +1,14 @@ +{ + "type": "GIF", + "avatar": "SINGLE", + "pos": [ + [39, 169, 267, 141], [40, 167, 264, 143], [38, 174, 270, 135], [40, 167, 264, 143], [38, 174, 270, 135], + [40, 167, 264, 143], [38, 174, 270, 135], [40, 167, 264, 143], [38, 174, 270, 135], [28, 176, 293, 134], + [5, 215, 333, 96], [10, 210, 321, 102], [3, 210, 330, 104], [4, 210, 328, 102], [4, 212, 328, 100], + [4, 212, 328, 100], [4, 212, 328, 100], [4, 212, 328, 100], [4, 212, 328, 100], [29, 195, 285, 120] + ], + "text": "", + "round": true, + "rotate": false, + "avatarOnTop": false +} \ No newline at end of file diff --git a/res/petpet/twist/data.json b/res/petpet/twist/data.json new file mode 100644 index 00000000..b9409320 --- /dev/null +++ b/res/petpet/twist/data.json @@ -0,0 +1,12 @@ +{ + "type": "GIF", + "avatar": "SINGLE", + "pos": [ + [25, 66, 80, 80], [25, 66, 80, 80], [23, 68, 80, 80], + [20, 69, 80, 80], [22, 68, 80, 80] + ], + "text": "", + "round": true, + "rotate": true, + "avatarOnTop": false +} \ No newline at end of file diff --git a/src/main/java/xmmt/dituon/ConfigJSON.kt b/src/main/java/xmmt/dituon/ConfigJSON.kt index a3504db4..1d9cccf0 100644 --- a/src/main/java/xmmt/dituon/ConfigJSON.kt +++ b/src/main/java/xmmt/dituon/ConfigJSON.kt @@ -2,12 +2,32 @@ package xmmt.dituon import kotlinx.serialization.* import kotlinx.serialization.json.Json +import kotlinx.serialization.json.JsonArray @Serializable data class ConfigJSON( - val command: String, val probability: Int, val antialias: Boolean + val version: Float, val command: String, val probability: Int, val antialias: Boolean, + val disabled: JsonArray, val resPath: String ) fun decode(str: String): ConfigJSON { return Json.decodeFromString(str) +} + +enum class Type { + GIF, IMG +} + +enum class Avatar { + SINGLE , DOUBLE +} + +@Serializable +data class DataJSON( + val type: Type, val avatar: Avatar, val pos: JsonArray, val text: String , + val round: Boolean, val rotate: Boolean, val avatarOnTop: Boolean +) + +fun getData(str: String): DataJSON{ + return Json.decodeFromString(str) } \ No newline at end of file diff --git a/src/main/java/xmmt/dituon/GifBuilder.java b/src/main/java/xmmt/dituon/GifBuilder.java new file mode 100644 index 00000000..1d75162f --- /dev/null +++ b/src/main/java/xmmt/dituon/GifBuilder.java @@ -0,0 +1,101 @@ +package xmmt.dituon; + +import javax.imageio.*; +import javax.imageio.metadata.IIOInvalidTreeException; +import javax.imageio.metadata.IIOMetadata; +import javax.imageio.metadata.IIOMetadataNode; +import javax.imageio.stream.ImageOutputStream; +import java.awt.image.RenderedImage; +import java.io.*; + +public class GifBuilder { + + protected ImageWriter writer; + protected ImageWriteParam params; + protected IIOMetadata metadata; + protected ImageOutputStream image; + protected InputStream output; + + public GifBuilder(int imageType, int delay, boolean loop) throws IOException { + writer = ImageIO.getImageWritersBySuffix("gif").next(); + params = writer.getDefaultWriteParam(); + + ImageTypeSpecifier imageTypeSpecifier = ImageTypeSpecifier.createFromBufferedImageType(imageType); + metadata = writer.getDefaultImageMetadata(imageTypeSpecifier, params); + + configureRootMetadata(delay, loop); + + ByteArrayOutputStream os = new ByteArrayOutputStream(); + image = ImageIO.createImageOutputStream(os); + writer.setOutput(image); + writer.prepareWriteSequence(null); + } + + public byte[] getBytes(ImageOutputStream ios) { + ByteArrayOutputStream bos = new ByteArrayOutputStream(255); + try { + ios.seek(0); + } catch (IOException e1) { + e1.printStackTrace(); + } + + while (true) { + try { + bos.write(ios.readByte()); + } catch (EOFException e) { + break; + } catch (IOException e) { + System.out.println("Error processing the Image Stream"); + break; + } + } + return bos.toByteArray(); + } + + private void configureRootMetadata(int delay, boolean loop) throws IIOInvalidTreeException { + String metaFormatName = metadata.getNativeMetadataFormatName(); + IIOMetadataNode root = (IIOMetadataNode) metadata.getAsTree(metaFormatName); + + IIOMetadataNode graphicsControlExtensionNode = getNode(root, "GraphicControlExtension"); + graphicsControlExtensionNode.setAttribute("disposalMethod", "none"); + graphicsControlExtensionNode.setAttribute("userInputFlag", "FALSE"); + graphicsControlExtensionNode.setAttribute("transparentColorFlag", "FALSE"); + graphicsControlExtensionNode.setAttribute("delayTime", Integer.toString(delay / 10)); + graphicsControlExtensionNode.setAttribute("transparentColorIndex", "0"); + + IIOMetadataNode appExtensionsNode = getNode(root, "ApplicationExtensions"); + IIOMetadataNode child = new IIOMetadataNode("ApplicationExtension"); + child.setAttribute("applicationID", "NETSCAPE"); + child.setAttribute("authenticationCode", "2.0"); + + int loopContinuously = loop ? 0 : 1; + child.setUserObject(new byte[]{ 0x1, (byte) (loopContinuously & 0xFF), (byte) (0)}); + appExtensionsNode.appendChild(child); + metadata.setFromTree(metaFormatName, root); + } + + private static IIOMetadataNode getNode(IIOMetadataNode rootNode, String nodeName){ + int nNodes = rootNode.getLength(); + for (int i = 0; i < nNodes; i++){ + if (rootNode.item(i).getNodeName().equalsIgnoreCase(nodeName)){ + return (IIOMetadataNode) rootNode.item(i); + } + } + IIOMetadataNode node = new IIOMetadataNode(nodeName); + rootNode.appendChild(node); + return(node); + } + + public void writeToSequence(RenderedImage img) throws IOException { + writer.writeToSequence(new IIOImage(img, null, metadata), params); + } + + public InputStream getOutput(){ + return output; + } + + public void close() throws IOException { + writer.endWriteSequence(); + output = new ByteArrayInputStream(getBytes(image)); + } +} \ No newline at end of file diff --git a/src/main/java/xmmt/dituon/GifMaker.java b/src/main/java/xmmt/dituon/GifMaker.java index c6261e4e..02752d6d 100644 --- a/src/main/java/xmmt/dituon/GifMaker.java +++ b/src/main/java/xmmt/dituon/GifMaker.java @@ -1,101 +1,95 @@ package xmmt.dituon; -import javax.imageio.*; -import javax.imageio.metadata.IIOInvalidTreeException; -import javax.imageio.metadata.IIOMetadata; -import javax.imageio.metadata.IIOMetadataNode; -import javax.imageio.stream.ImageOutputStream; -import java.awt.image.RenderedImage; -import java.io.*; +import net.mamoe.mirai.contact.Member; +import net.mamoe.mirai.message.data.Image; +import net.mamoe.mirai.utils.ExternalResource; -public class GifMaker { - - protected ImageWriter writer; - protected ImageWriteParam params; - protected IIOMetadata metadata; - protected ImageOutputStream image; - protected InputStream output; - - public GifMaker(int imageType, int delay, boolean loop) throws IOException { - writer = ImageIO.getImageWritersBySuffix("gif").next(); - params = writer.getDefaultWriteParam(); +import javax.imageio.ImageIO; +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.IOException; - ImageTypeSpecifier imageTypeSpecifier = ImageTypeSpecifier.createFromBufferedImageType(imageType); - metadata = writer.getDefaultImageMetadata(imageTypeSpecifier, params); +import static xmmt.dituon.ImageSynthesis.*; - configureRootMetadata(delay, loop); - - ByteArrayOutputStream os = new ByteArrayOutputStream(); - image = ImageIO.createImageOutputStream(os); - writer.setOutput(image); - writer.prepareWriteSequence(null); +public class GifMaker { + // 单头像GIF + public static Image makeGIF(Member m, String path, int[][] pos, boolean isAvatarOnTop, boolean isRotate, boolean isRound) { + return makeGIF(m, m.getAvatarUrl(), path, pos, isAvatarOnTop, isRotate, isRound); } - public byte[] getBytes(ImageOutputStream ios) { - ByteArrayOutputStream bos = new ByteArrayOutputStream(255); + public static Image makeGIF(Member m, String URL, String path, int[][] pos, + boolean isAvatarOnTop, boolean isRotate, boolean isRound) { + int i = 0; try { - ios.seek(0); - } catch (IOException e1) { - e1.printStackTrace(); - } - - while (true) { - try { - bos.write(ios.readByte()); - } catch (EOFException e) { - break; - } catch (IOException e) { - System.out.println("Error processing the Image Stream"); - break; + GifBuilder gifBuilder = new GifBuilder(ImageIO.read(new File(path + "0.png")).getType(), 65, true); + BufferedImage avatarImage = getAvatarImage(URL); + if (isRound) { + avatarImage = convertCircular(avatarImage); + } + for (int[] p : pos) { + File f = new File(path + i + ".png"); + i++; + BufferedImage sticker = ImageIO.read(f); + if (isRotate) { + gifBuilder.writeToSequence(synthesisImage(avatarImage, sticker, p, i, isAvatarOnTop)); + break; + } + gifBuilder.writeToSequence(synthesisImage(avatarImage, sticker, p, isAvatarOnTop)); } + gifBuilder.close(); + ExternalResource resource = ExternalResource.create(gifBuilder.getOutput()); + + Image image = m.uploadImage(resource); + resource.close(); + return image; + } catch (IOException ex) { + System.out.println("构造GIF失败,请检查 PetData.java"); + ex.printStackTrace(); } - return bos.toByteArray(); + return null; } - private void configureRootMetadata(int delay, boolean loop) throws IIOInvalidTreeException { - String metaFormatName = metadata.getNativeMetadataFormatName(); - IIOMetadataNode root = (IIOMetadataNode) metadata.getAsTree(metaFormatName); - - IIOMetadataNode graphicsControlExtensionNode = getNode(root, "GraphicControlExtension"); - graphicsControlExtensionNode.setAttribute("disposalMethod", "none"); - graphicsControlExtensionNode.setAttribute("userInputFlag", "FALSE"); - graphicsControlExtensionNode.setAttribute("transparentColorFlag", "FALSE"); - graphicsControlExtensionNode.setAttribute("delayTime", Integer.toString(delay / 10)); - graphicsControlExtensionNode.setAttribute("transparentColorIndex", "0"); - - IIOMetadataNode appExtensionsNode = getNode(root, "ApplicationExtensions"); - IIOMetadataNode child = new IIOMetadataNode("ApplicationExtension"); - child.setAttribute("applicationID", "NETSCAPE"); - child.setAttribute("authenticationCode", "2.0"); - - int loopContinuously = loop ? 0 : 1; - child.setUserObject(new byte[]{ 0x1, (byte) (loopContinuously & 0xFF), (byte) (0)}); - appExtensionsNode.appendChild(child); - metadata.setFromTree(metaFormatName, root); + // 两张头像GIF + public static Image makeGIF(Member m1, Member m2, String path, int[][] pos1, int[][] pos2, + boolean isAvatarOnTop, boolean isRotate, boolean isRound) { + return makeGIF(m1, m1.getAvatarUrl(), m2.getAvatarUrl(), path, pos1, pos2, isAvatarOnTop, isRotate, isRound); } - private static IIOMetadataNode getNode(IIOMetadataNode rootNode, String nodeName){ - int nNodes = rootNode.getLength(); - for (int i = 0; i < nNodes; i++){ - if (rootNode.item(i).getNodeName().equalsIgnoreCase(nodeName)){ - return (IIOMetadataNode) rootNode.item(i); + public static Image makeGIF(Member m, String m1URL, String m2URL, String path, int[][] pos1, int[][] pos2, + boolean isAvatarOnTop, boolean isRotate, boolean isRound) { + try { + GifBuilder gifBuilder = new GifBuilder(ImageIO.read(new File(path + "0.png")).getType(), 60, true); + BufferedImage avatarImage1 = getAvatarImage(m1URL); + BufferedImage avatarImage2 = getAvatarImage(m2URL); + + if (isRound) { + avatarImage1 = convertCircular(avatarImage1); + avatarImage2 = convertCircular(avatarImage2); } - } - IIOMetadataNode node = new IIOMetadataNode(nodeName); - rootNode.appendChild(node); - return(node); - } - public void writeToSequence(RenderedImage img) throws IOException { - writer.writeToSequence(new IIOImage(img, null, metadata), params); - } + for (int i = 0; i < pos1.length; i++) { + File f = new File(path + i + ".png"); + BufferedImage sticker = ImageIO.read(f); + + if (isRotate) { + gifBuilder.writeToSequence(synthesisImage( + sticker, avatarImage1, avatarImage2, pos1[i], pos2[i], i+1, isAvatarOnTop)); + break; + } + gifBuilder.writeToSequence(synthesisImage( + sticker, avatarImage1, avatarImage2, pos1[i], pos2[i], isAvatarOnTop)); + } - public InputStream getOutput(){ - return output; - } + gifBuilder.close(); + ExternalResource resource = ExternalResource.create(gifBuilder.getOutput()); - public void close() throws IOException { - writer.endWriteSequence(); - output = new ByteArrayInputStream(getBytes(image)); + Image image = m.uploadImage(resource); + resource.close(); + return image; + } catch (IOException ex) { + System.out.println("构造GIF失败,请检查 PetData"); + ex.printStackTrace(); + } + return null; } -} \ No newline at end of file +} diff --git a/src/main/java/xmmt/dituon/ImageMaker.java b/src/main/java/xmmt/dituon/ImageMaker.java new file mode 100644 index 00000000..35d3f2d6 --- /dev/null +++ b/src/main/java/xmmt/dituon/ImageMaker.java @@ -0,0 +1,80 @@ +package xmmt.dituon; + +import net.mamoe.mirai.contact.Member; +import net.mamoe.mirai.message.data.Image; +import net.mamoe.mirai.utils.ExternalResource; + +import javax.imageio.ImageIO; +import java.awt.image.BufferedImage; +import java.io.*; + +import static xmmt.dituon.ImageSynthesis.*; + +public class ImageMaker { + // 单头像生成图片 + public static Image makeImage(Member m, String path, int[] pos, + boolean isAvatarOnTop, boolean isRotate, boolean isRound) { + return makeImage(m, m.getAvatarUrl(), path, pos, isAvatarOnTop, isRotate, isRound); + } + + public static Image makeImage(Member m, String URL, String path, int[] pos, + boolean isAvatarOnTop, boolean isRotate, boolean isRound) { + try { + BufferedImage sticker = ImageIO.read(new File(path + "0.png")); + BufferedImage avatarImage = getAvatarImage(URL); + if (isRound) { + avatarImage = convertCircular(avatarImage); + } + ExternalResource res = ExternalResource.create(bufferedImageToInputStream( + synthesisImage(avatarImage, sticker, pos, isAvatarOnTop))); + Image img = m.uploadImage(res); + res.close(); + return img; + } catch (IOException ex) { + ex.printStackTrace(); + } + return null; + } + + // 双头像生成图片 + public static Image makeImage(Member m1, Member m2, String path, int[] pos1, int[] pos2, + boolean isAvatarOnTop, boolean isRotate, boolean isRound) { + return makeImage(m1, m1.getAvatarUrl(), m2.getAvatarUrl(), path, pos1, pos2, isAvatarOnTop, isRotate, isRound); + } + + public static Image makeImage(Member m, String m1URL, String m2URL, String path, int[] pos1, int[] pos2, + boolean isAvatarOnTop, boolean isRotate, boolean isRound) { + try { + GifBuilder gifBuilder = new GifBuilder(ImageIO.read(new File(path + "0.png")).getType(), 60, true); + BufferedImage avatarImage1 = getAvatarImage(m1URL); + BufferedImage avatarImage2 = getAvatarImage(m2URL); + + if (isRound) { + avatarImage1 = convertCircular(avatarImage1); + avatarImage2 = convertCircular(avatarImage2); + } + + BufferedImage sticker = ImageIO.read(new File(path + "0.png")); + + gifBuilder.writeToSequence(synthesisImage( + sticker, avatarImage1, avatarImage2, pos1, pos2, isAvatarOnTop)); + + gifBuilder.close(); + ExternalResource resource = ExternalResource.create(gifBuilder.getOutput()); + + Image image = m.uploadImage(resource); + resource.close(); + return image; + } catch (IOException ex) { + System.out.println("构造图片失败,请检查 PetData"); + ex.printStackTrace(); + } + return null; + } + + private static InputStream bufferedImageToInputStream(BufferedImage bf) throws IOException { + ByteArrayOutputStream os = new ByteArrayOutputStream(); + ImageIO.write(bf, "img", os); + return new ByteArrayInputStream(os.toByteArray()); + } +} diff --git a/src/main/java/xmmt/dituon/ImageSynthesis.java b/src/main/java/xmmt/dituon/ImageSynthesis.java index 0fdf502a..05352b01 100644 --- a/src/main/java/xmmt/dituon/ImageSynthesis.java +++ b/src/main/java/xmmt/dituon/ImageSynthesis.java @@ -1,112 +1,107 @@ package xmmt.dituon; -import net.mamoe.mirai.contact.Member; -import net.mamoe.mirai.message.data.Image; -import net.mamoe.mirai.utils.ExternalResource; - import javax.imageio.ImageIO; import java.awt.*; import java.awt.geom.Ellipse2D; import java.awt.image.BufferedImage; -import java.io.File; import java.io.IOException; import java.net.HttpURLConnection; import java.net.URL; public class ImageSynthesis { - public static Image sendImage(Member m, String path, int[][] pos, boolean isAvatarOnTop, boolean isRotate) { - int i = 0; - try { - GifMaker gifMaker = new GifMaker(ImageIO.read(new File(path + "0.png")).getType(), 65, true); - BufferedImage avatarImage = convertCircular(getAvatarImage(m.getAvatarUrl())); - BufferedImage newAvatarImage = new BufferedImage(avatarImage.getWidth(), avatarImage.getHeight(), avatarImage.getType()); - for (int[] p : pos) { - if (isRotate) { - Graphics2D rotateG2d = newAvatarImage.createGraphics(); - rotateG2d.rotate(Math.toRadians((double) (360 / pos.length) * (i + 1)), - avatarImage.getWidth() / 2, avatarImage.getHeight() / 2); - rotateG2d.drawImage(avatarImage, null, 0, 0); - } else { - newAvatarImage = avatarImage; - } - - File f = new File(path + i + ".png"); - i++; - BufferedImage sticker = ImageIO.read(f); - int x = p[0]; - int y = p[1]; - int w = p[2]; - int h = p[3]; - BufferedImage output = new BufferedImage(sticker.getWidth(), sticker.getHeight(), sticker.getType()); - Graphics2D g2d = output.createGraphics(); - g2d.setColor(Color.WHITE); - g2d.fillRect(0, 0, sticker.getWidth(), sticker.getHeight()); - g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, 1.0F)); - if (isAvatarOnTop) { - g2d.drawImage(sticker, 0, 0, sticker.getWidth(), sticker.getHeight(), null); - g2d.drawImage(newAvatarImage, x, y, w, h, null); - } else { - g2d.drawImage(newAvatarImage, x, y, w, h, null); - g2d.drawImage(sticker, 0, 0, sticker.getWidth(), sticker.getHeight(), null); - } - g2d.dispose(); - gifMaker.writeToSequence(output); - } - gifMaker.close(); - ExternalResource resource = ExternalResource.create(gifMaker.getOutput()); - - Image image = m.uploadImage(resource); - resource.close(); - return image; - } catch (IOException ex) { - System.out.println("(sendImage)构造GIF失败,请检查 PetData.java"); - ex.printStackTrace(); + + // 单头像合成,不旋转 + public static BufferedImage synthesisImage(BufferedImage avatarImage, BufferedImage sticker, int[] pos, boolean isAvatarOnTop) { + return synthesisImage(avatarImage, sticker, pos, 0, isAvatarOnTop); + } + + // 两个头像合成,不旋转 + public static BufferedImage synthesisImage(BufferedImage sticker, BufferedImage avatarImage1, BufferedImage avatarImage2, + int[] pos1, int[] pos2, boolean isAvatarOnTop) { + return synthesisImage(sticker, avatarImage1, avatarImage2, pos1, pos2, 0, isAvatarOnTop); + } + + // 单头像合成,旋转 + public static BufferedImage synthesisImage(BufferedImage avatarImage, BufferedImage sticker, int[] pos, + int rotateIndex, boolean isAvatarOnTop) { + BufferedImage newAvatarImage = new BufferedImage(avatarImage.getWidth(), avatarImage.getHeight(), avatarImage.getType()); + if (rotateIndex != 0F) { + Graphics2D rotateG2d = newAvatarImage.createGraphics(); + rotateG2d.rotate(Math.toRadians((float) (360 / pos.length) * (rotateIndex + 1)), + avatarImage.getWidth() / 2, avatarImage.getHeight() / 2); + rotateG2d.drawImage(avatarImage, null, 0, 0); + } else { + newAvatarImage = avatarImage; + } + + int x = pos[0]; + int y = pos[1]; + int w = pos[2]; + int h = pos[3]; + BufferedImage output = new BufferedImage(sticker.getWidth(), sticker.getHeight(), sticker.getType()); + Graphics2D g2d = output.createGraphics(); + g2d.setColor(Color.WHITE); + g2d.fillRect(0, 0, sticker.getWidth(), sticker.getHeight()); + g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, 1.0F)); + if (isAvatarOnTop) { + g2d.drawImage(sticker, 0, 0, sticker.getWidth(), sticker.getHeight(), null); + g2d.drawImage(newAvatarImage, x, y, w, h, null); + } else { + g2d.drawImage(newAvatarImage, x, y, w, h, null); + g2d.drawImage(sticker, 0, 0, sticker.getWidth(), sticker.getHeight(), null); } - return null; + g2d.dispose(); + return output; } - public static Image sendImage(Member m1, Member m2, String path, int[][] pos1, int[][] pos2) { - try { - GifMaker gifMaker = new GifMaker(ImageIO.read(new File(path + "0.png")).getType(), 60, true); - BufferedImage avatarImage1 = convertCircular(getAvatarImage(m1.getAvatarUrl())); - BufferedImage avatarImage2 = convertCircular(getAvatarImage(m2.getAvatarUrl())); - for (int i = 0; i < pos1.length; i++) { - File f = new File(path + i + ".png"); - BufferedImage sticker = ImageIO.read(f); - - int x1 = pos1[i][0]; - int y1 = pos1[i][1]; - int w1 = pos1[i][2]; - int h1 = pos1[i][3]; - - int x2 = pos2[i][0]; - int y2 = pos2[i][1]; - int w2 = pos2[i][2]; - int h2 = pos2[i][3]; - - BufferedImage output = new BufferedImage(sticker.getWidth(), sticker.getHeight(), sticker.getType()); - Graphics2D g2d = output.createGraphics(); - g2d.setColor(Color.WHITE); - g2d.fillRect(0, 0, sticker.getWidth(), sticker.getHeight()); - g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, 1.0F)); - g2d.drawImage(sticker, 0, 0, sticker.getWidth(), sticker.getHeight(), null); - g2d.drawImage(avatarImage1, x1, y1, w1, h1, null); - g2d.drawImage(avatarImage2, x2, y2, w2, h2, null); - g2d.dispose(); - gifMaker.writeToSequence(output); - } - - gifMaker.close(); - ExternalResource resource = ExternalResource.create(gifMaker.getOutput()); - - Image image = m1.uploadImage(resource); - resource.close(); - return image; - } catch (IOException ex) { - System.out.println("(sendImage)构造GIF失败,请检查 PetData.java"); - ex.printStackTrace(); + // 两个头像合成,旋转 + public static BufferedImage synthesisImage(BufferedImage sticker, BufferedImage avatarImage1, BufferedImage avatarImage2, + int[] pos1, int[] pos2, + int rotateIndex, boolean isAvatarOnTop) { + BufferedImage newAvatarImage1 = new BufferedImage(avatarImage1.getWidth(), avatarImage1.getHeight(), avatarImage1.getType()); + BufferedImage newAvatarImage2 = new BufferedImage(avatarImage1.getWidth(), avatarImage1.getHeight(), avatarImage1.getType()); + + if (rotateIndex != 0F) { + Graphics2D rotateG2d1 = newAvatarImage1.createGraphics(); + rotateG2d1.rotate(Math.toRadians((float) (360 / pos1.length) * (rotateIndex + 1)), + avatarImage1.getWidth() / 2, avatarImage1.getHeight() / 2); + rotateG2d1.drawImage(avatarImage1, null, 0, 0); + + Graphics2D rotateG2d2 = newAvatarImage2.createGraphics(); + rotateG2d2.rotate(Math.toRadians((float) (360 / pos1.length) * (rotateIndex + 1)), + avatarImage2.getWidth() / 2, avatarImage2.getHeight() / 2); + rotateG2d2.drawImage(avatarImage2, null, 0, 0); + } else { + newAvatarImage1 = avatarImage1; + newAvatarImage2 = avatarImage2; } - return null; + + int x1 = pos1[0]; + int y1 = pos1[1]; + int w1 = pos1[2]; + int h1 = pos1[3]; + + int x2 = pos2[0]; + int y2 = pos2[1]; + int w2 = pos2[2]; + int h2 = pos2[3]; + + BufferedImage output = new BufferedImage(sticker.getWidth(), sticker.getHeight(), sticker.getType()); + Graphics2D g2d = output.createGraphics(); + g2d.setColor(Color.WHITE); + g2d.fillRect(0, 0, sticker.getWidth(), sticker.getHeight()); + g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, 1.0F)); + if (isAvatarOnTop) { + g2d.drawImage(sticker, 0, 0, sticker.getWidth(), sticker.getHeight(), null); + g2d.drawImage(newAvatarImage1, x1, y1, w1, h1, null); + g2d.drawImage(newAvatarImage2, x2, y2, w2, h2, null); + } else { + g2d.drawImage(newAvatarImage1, x1, y1, w1, h1, null); + g2d.drawImage(newAvatarImage2, x2, y2, w2, h2, null); + g2d.drawImage(sticker, 0, 0, sticker.getWidth(), sticker.getHeight(), null); + } + g2d.dispose(); + return output; } public static BufferedImage convertCircular(BufferedImage input) throws IOException { @@ -115,7 +110,7 @@ public static BufferedImage convertCircular(BufferedImage input) throws IOExcept Graphics2D g2 = output.createGraphics(); g2.setClip(shape); - if (Petpet.antialias){ + if (PetData.antialias) { g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); } @@ -134,7 +129,7 @@ public static BufferedImage getAvatarImage(String URL) { image = ImageIO.read(conn.getInputStream()); conn.disconnect(); } catch (Exception e) { - System.out.println("获取头像失败\nHttpURLConnection: "+conn+"\nURL: "+URL); + System.out.println("获取头像失败\nHttpURLConnection: " + conn + "\nURL: " + URL); e.printStackTrace(); } finally { assert conn != null; diff --git a/src/main/java/xmmt/dituon/PetData.java b/src/main/java/xmmt/dituon/PetData.java index 122c85d6..b51199d7 100644 --- a/src/main/java/xmmt/dituon/PetData.java +++ b/src/main/java/xmmt/dituon/PetData.java @@ -1,157 +1,211 @@ package xmmt.dituon; +import kotlinx.serialization.json.JsonArray; +import kotlinx.serialization.json.JsonElement; import net.mamoe.mirai.contact.Group; import net.mamoe.mirai.contact.Member; +import java.io.*; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.HashMap; import java.util.Objects; +import java.util.Random; -import static xmmt.dituon.ImageSynthesis.sendImage; +import static xmmt.dituon.GifMaker.makeGIF; +import static xmmt.dituon.ImageMaker.makeImage; public class PetData { - public static void makeImage(Group group, Member from, Member to, int index) { - from = from.equals(to) ? group.getBotAsMember() : from; - - int[][] fromPos; - int[][] toPos; - int[][] pos; - - switch (index) { - case 0: - fromPos = new int[][]{ - {92, 64, 40, 40}, {135, 40, 40, 40}, {84, 105, 40, 40}, {80, 110, 40, 40}, - {155, 82, 40, 40}, {60, 96, 40, 40}, {50, 80, 40, 40}, {98, 55, 40, 40}, - {35, 65, 40, 40}, {38, 100, 40, 40}, {70, 80, 40, 40}, {84, 65, 40, 40}, - {75, 65, 40, 40} - }; - toPos = new int[][]{ - {58, 90, 50, 50}, {62, 95, 50, 50}, {42, 100, 50, 50}, {50, 100, 50, 50}, - {56, 100, 50, 50}, {18, 120, 50, 50}, {28, 110, 50, 50}, {54, 100, 50, 50}, - {46, 100, 50, 50}, {60, 100, 50, 50}, {35, 115, 50, 50}, {20, 120, 50, 50}, - {40, 96, 50, 50} - }; - group.sendMessage(Objects.requireNonNull( - sendImage(from, to, "./res/petpet/kiss/", fromPos, toPos))); - break; - case 1: - fromPos = new int[][]{ - {102, 95, 70, 80}, {108, 60, 50, 100}, {97, 18, 65, 95}, - {65, 5, 75, 75}, {95, 57, 100, 55}, {109, 107, 65, 75} - }; - toPos = new int[][]{ - {39, 91, 75, 75}, {49, 101, 75, 75}, {67, 98, 75, 75}, - {55, 86, 75, 75}, {61, 109, 75, 75}, {65, 101, 75, 75} - }; - group.sendMessage(Objects.requireNonNull( - sendImage(from, to, "./res/petpet/rub/", fromPos, toPos))); - break; - case 2: - fromPos = new int[][]{ - {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, - {289, 70, 33, 33}, {280, 73, 32, 32}, {259, 31, 35, 35}, {-50, 220, 175, 175} - }; - toPos = new int[][]{ - {108, 36, 32, 32}, {122, 36, 32, 32}, {0, 0, 0, 0}, {19, 129, 123, 123}, - {-50, 200, 185, 185}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0} - }; - group.sendMessage(Objects.requireNonNull( - sendImage(from, to, "./res/petpet/throw/", fromPos, toPos))); - break; - case 3: - pos = new int[][]{ - {14, 20, 98, 98}, {12, 33, 101, 85}, {8, 40, 110, 76}, {10, 33, 102, 84}, {12, 20, 98, 98} - }; - group.sendMessage(Objects.requireNonNull( - ImageSynthesis.sendImage(to, "./res/petpet/petpet/", pos, false, false))); - break; - case 4: - pos = new int[][]{ - {180, 60, 100, 100}, {184, 75, 100, 100}, {183, 98, 100, 100}, - {179, 118, 110, 100}, {156, 194, 150, 48}, {178, 136, 122, 69}, - {175, 66, 122, 85}, {170, 42, 130, 96}, {175, 34, 118, 95}, - {179, 35, 110, 93}, {180, 54, 102, 93}, {183, 58, 97, 92}, - {174, 35, 120, 94}, {179, 35, 109, 93}, {181, 54, 101, 92}, - {182, 59, 98, 92}, {183, 71, 90, 96}, {180, 131, 92, 101}, - {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0} - }; - group.sendMessage(Objects.requireNonNull( - ImageSynthesis.sendImage(to, "./res/petpet/play/", pos, true, false))); - break; - case 5: - pos = new int[][]{ - {87, 77, 220, 220}, {96, 85, 220, 220}, {92, 79, 220, 220}, {92, 78, 220, 220}, - {92, 75, 220, 220}, {92, 75, 220, 220}, {93, 76, 220, 220}, {90, 80, 220, 220} - }; - group.sendMessage(Objects.requireNonNull( - ImageSynthesis.sendImage(to, "./res/petpet/roll/", pos, false, true))); - break; - case 6: - pos = new int[][]{ - {90, 90, 105, 150}, {90, 83, 96, 172}, {90, 90, 106, 148}, - {88, 88, 97, 167}, {90, 85, 89, 179}, {90, 90, 106, 151}, - {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, - {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0} - }; - group.sendMessage(Objects.requireNonNull( - ImageSynthesis.sendImage(to, "./res/petpet/bite/", pos, false, false))); - break; - case 7: - pos = new int[][]{ - {25, 66, 80, 80}, {25, 66, 80, 80}, {23, 68, 80, 80}, - {20, 69, 80, 80}, {22, 68, 80, 80} - }; - group.sendMessage(Objects.requireNonNull( - ImageSynthesis.sendImage(to, "./res/petpet/twist/", pos, false, true))); - break; - case 8: - pos = new int[][]{ - {135, 240, 138, 47}, {135, 240, 138, 47}, {150, 190, 105, 95}, {150, 190, 105, 95}, - {148, 188, 106, 98}, {146, 196, 110, 88}, {145, 223, 112, 61}, {145, 223, 112, 61} - }; - group.sendMessage(Objects.requireNonNull( - ImageSynthesis.sendImage(to, "./res/petpet/pound/", pos, false, false))); - break; - case 9: - pos = new int[][]{ - {65, 128, 77, 72}, {67, 128, 73, 72}, {54, 139, 94, 61}, {57, 135, 86, 65} - }; - group.sendMessage(Objects.requireNonNull( - ImageSynthesis.sendImage(to, "./res/petpet/thump/", pos, false, false))); - break; - case 10: - pos = new int[][]{ - {60, 308, 210, 195}, {60, 308, 210, 198}, {45, 330, 250, 172}, {58, 320, 218, 180}, - {60, 310, 215, 193}, {40, 320, 250, 285}, {48, 308, 226, 192}, {51, 301, 223, 200} - }; - group.sendMessage(Objects.requireNonNull( - ImageSynthesis.sendImage(to, "./res/petpet/knock/", pos, false, false))); - break; - case 11: - pos = new int[][]{ - {82, 100, 130, 119}, {82, 94, 126, 125}, {82, 120, 128, 99}, {81, 164, 132, 55}, - {79, 163, 132, 55}, {82, 140, 127, 79}, {83, 152, 125, 67}, {75, 157, 140, 62}, - {72, 165, 144, 54}, {80, 132, 128, 87}, {81, 127, 127, 92}, {79, 111, 132, 108} - }; - group.sendMessage(Objects.requireNonNull( - ImageSynthesis.sendImage(to, "./res/petpet/suck/", pos, false, false))); - break; - case 12: - pos = new int[][]{ - {62, 143, 158, 113}, {52, 177, 173, 105}, {42, 192, 192, 92}, {46, 182, 184, 100}, - {54, 169, 174, 110}, {69, 128, 144, 135}, {65, 130, 152, 124} - }; - group.sendMessage(Objects.requireNonNull( - ImageSynthesis.sendImage(to, "./res/petpet/hammer/", pos, false, false))); - break; - case 13: - pos = new int[][]{ - {39, 169, 267, 141}, {40, 167, 264, 143}, {38, 174, 270, 135}, {40, 167, 264, 143}, {38, 174, 270, 135}, - {40, 167, 264, 143}, {38, 174, 270, 135}, {40, 167, 264, 143}, {38, 174, 270, 135}, {28, 176, 293, 134}, - {5, 215, 333, 96}, {10, 210, 321, 102}, {3, 210, 330, 104}, {4, 210, 328, 102}, {4, 212, 328, 100}, - {4, 212, 328, 100}, {4, 212, 328, 100}, {4, 212, 328, 100}, {4, 212, 328, 100}, {29, 195, 285, 120} - }; - group.sendMessage(Objects.requireNonNull( - ImageSynthesis.sendImage(to, "./res/petpet/tightly/", pos, false, false))); - break; + public static final float VERSION = 2.0F; + + public static boolean antialias = false; + public static String command = "pet"; + public static int randomMax = 40; + public static String resPath = "./res/petpet/"; + + static ArrayList disabledKey = new ArrayList<>(); + static ArrayList keyList = new ArrayList<>(); + static HashMap dataMap = new HashMap<>(); + + public static void readData() { + File dir = new File(resPath); + String[] children = dir.list(); + + if (children == null) { + System.out.println("无法读取文件,请检查" + resPath + "目录"); + return; + } + + for (String path : children) { + + File dataFile = new File(resPath + path + "/data.json"); + try { + DataJSON data = ConfigJSONKt.getData(getFileStr(dataFile)); + if (!disabledKey.contains(path)) { + keyList.add(path); + } + dataMap.put(path, data); + } catch (Exception ex) { + System.out.println("无法读取 " + path + "/data.json: \n\n" + ex); + } + } + + randomMax = (int) (keyList.size() / (randomMax * 0.01)); + System.out.println("Petpet 加载完毕 (共 " + keyList.size() + " 素材,已排除 " + disabledKey.size() + " )"); + } + + public static void readConfig() { + File configFile = new File("./plugins/petpet.json"); + try { + if (configFile.exists()) { + ConfigJSON config = ConfigJSONKt.decode(getFileStr(configFile)); + + if (config.getVersion() != VERSION) { + createConfig(configFile); + return; + } + + command = config.getCommand(); + antialias = config.getAntialias(); + randomMax = config.getProbability(); + + for (JsonElement path : config.getDisabled()) { + disabledKey.add(path.toString().replace("\"", "")); + } + + System.out.println("Petpet 初始化成功,使用 " + command + " 以生成GIF。"); + } else { + createConfig(configFile); + } + } catch (IOException ex) { + ex.printStackTrace(); + } catch (Exception ex) { // MissingFieldException + createConfig(configFile); + } + } + + private static void createConfig(File configFile) { + try { + String defaultConfig = "{\n" + + " \"version\": 2.0,\n" + + " \"command\": \"pet\",\n" + + " \"probability\": 30,\n" + + " \"antialias\": false,\n" + + " \"disabled\": []\n" + + " \"resPath\": \"./res/petpet/\",\n" + + "}"; + if (!configFile.createNewFile()) { + System.out.print("正在写入新版本配置文件"); + } + FileOutputStream defaultConfigOS = new FileOutputStream(configFile); + defaultConfigOS.write(defaultConfig.getBytes(StandardCharsets.UTF_8)); + System.out.println("写入配置文件成功,路径: Mirai/plugins/petpet.json"); + } catch (IOException ex) { + System.out.println("无法写入配置文件,请检查文件路径!"); + } + } + + private static String getFileStr(File file) throws IOException { + BufferedReader br = new BufferedReader(new FileReader(file)); + StringBuilder sb = new StringBuilder(); + String str; + while ((str = br.readLine()) != null) { + sb.append(str); } + br.close(); + return sb.toString(); + } + + public static void sendImage(Group group, Member from, Member to) { + sendImage(group, from, to, keyList.get(new Random().nextInt(keyList.size()))); + } + + public static void sendImage(Group group, Member from, Member to, boolean random) { + if (!random) { + sendImage(group, from, to); + return; + } + int r = new Random().nextInt(randomMax); + if (r >= keyList.size()) { + return; + } + sendImage(group, from, to, keyList.get(r)); + } + + public static void sendImage(Group group, Member from, Member to, String key) { + if (!dataMap.containsKey(key)) { + System.out.println("无效的key: " + key); + sendImage(group, from, to); + } + DataJSON data = dataMap.get(key); + key = resPath + key + "/"; + + try { + if (data.getType() == Type.GIF) { + if (data.getAvatar() == Avatar.SINGLE) { + int[][] pos = new int[data.getPos().getSize()][4]; + + int i = 0; + for (JsonElement je : data.getPos()) { + pos[i++] = JsonArrayToIntArray((JsonArray) je); + } + + group.sendMessage(Objects.requireNonNull(makeGIF(to, key, pos, + data.getAvatarOnTop(), data.getRotate(), data.getRound()))); + return; + } + if (data.getAvatar() == Avatar.DOUBLE) { + JsonArray fromJa = (JsonArray) data.getPos().get(0); + JsonArray toJa = (JsonArray) data.getPos().get(1); + + int[][] fromPos = new int[fromJa.getSize()][4]; + int[][] toPos = new int[toJa.getSize()][4]; + + int i = 0; + for (JsonElement fromJe : fromJa) { + fromPos[i++] = JsonArrayToIntArray((JsonArray) fromJe); + } + i = 0; + for (JsonElement toJe : toJa) { + toPos[i++] = JsonArrayToIntArray((JsonArray) toJe); + } + + group.sendMessage(Objects.requireNonNull(makeGIF( + from, to, key, fromPos, toPos, + data.getAvatarOnTop(), data.getRotate(), data.getRound()))); + return; + } + } + + if (data.getType() == Type.IMG){ + if (data.getAvatar() == Avatar.SINGLE) { + int[] pos = JsonArrayToIntArray(data.getPos()); + + group.sendMessage(Objects.requireNonNull(makeImage(to, key, pos, + data.getAvatarOnTop(), data.getRotate(), data.getRound()))); + return; + } + if (data.getAvatar() == Avatar.DOUBLE) { + int[] pos1 = JsonArrayToIntArray((JsonArray) data.getPos().get(0)); + int[] pos2 = JsonArrayToIntArray((JsonArray) data.getPos().get(1)); + + group.sendMessage(Objects.requireNonNull(makeImage(from, to, key, pos1, pos2, + data.getAvatarOnTop(), data.getRotate(), data.getRound()))); + return; + } + } + } catch (Exception ex) { + System.out.println("解析 " + key + "/data.json 出错"); + ex.printStackTrace(); + } + } + + private static int[] JsonArrayToIntArray(JsonArray ja) { + return new int[]{ + Integer.parseInt(ja.get(0).toString()), + Integer.parseInt(ja.get(1).toString()), + Integer.parseInt(ja.get(2).toString()), + Integer.parseInt(ja.get(3).toString()) + }; } } diff --git a/src/main/java/xmmt/dituon/Petpet.java b/src/main/java/xmmt/dituon/Petpet.java index e947b91c..99cbe64c 100644 --- a/src/main/java/xmmt/dituon/Petpet.java +++ b/src/main/java/xmmt/dituon/Petpet.java @@ -15,24 +15,18 @@ import net.mamoe.mirai.message.data.PlainText; import net.mamoe.mirai.message.data.QuoteReply; -import java.io.*; -import java.nio.charset.StandardCharsets; import java.util.ArrayList; -import java.util.Random; -import static xmmt.dituon.PetData.makeImage; +import static xmmt.dituon.PetData.*; public final class Petpet extends JavaPlugin { public static final Petpet INSTANCE = new Petpet(); + Bot bot = null; ArrayList disabledGroup = new ArrayList<>(); - public static boolean antialias = false; - public static String command = "pet"; - public static int randomMax = 40; - private Petpet() { - super(new JvmPluginDescriptionBuilder("xmmt.dituon.petpet", "1.4") + super(new JvmPluginDescriptionBuilder("xmmt.dituon.petpet", "2.0") .name("PetPet") .author("Dituon") .build()); @@ -41,6 +35,7 @@ private Petpet() { @Override public void onEnable() { readConfig(); + readData(); GlobalEventChannel.INSTANCE.subscribeOnce(BotOnlineEvent.class, e -> { if (bot == null) { bot = e.getBot(); @@ -55,9 +50,9 @@ private void onNudge(NudgeEvent e) { return; // 如果禁用了petpet就返回 } try { - makeImage((Group) e.getSubject(), (Member) e.getFrom(), (Member) e.getTarget(), new Random().nextInt(randomMax)); + sendImage((Group) e.getSubject(), (Member) e.getFrom(), (Member) e.getTarget(), true); } catch (Exception ex) { // 如果无法把被戳的对象转换为Member(只有Bot无法强制转换为Member对象) - makeImage((Group) e.getSubject(), (Member) e.getFrom(), ((Group) e.getSubject()).getBotAsMember(), new Random().nextInt(randomMax)); + sendImage((Group) e.getSubject(), (Member) e.getFrom(), ((Group) e.getSubject()).getBotAsMember(), true); } } @@ -78,55 +73,21 @@ private void onGroupMessage(GroupMessageEvent e) { && e.getMessage().contentToString().startsWith(command)) { At at = null; Member to = e.getSender(); - int index = new Random().nextInt(14); for (Message m : e.getMessage()) { if (m instanceof At) { // 遍历消息取出At的对象 at = (At) m; to = e.getGroup().get(at.getTarget()); } if (m instanceof PlainText && at != null) { - try { - index = Integer.parseInt(m.contentToString().replace(" ", "")); - } catch (NumberFormatException ignored) { - } - } - } - makeImage(e.getGroup(), e.getSender(), to, index); - } - } - - public void readConfig() { - File configFile = new File("./plugins/petpet.json"); - try { - if (configFile.exists()) { - BufferedReader configBr = new BufferedReader(new FileReader(configFile)); - StringBuilder configSb = new StringBuilder(); - String str; - while ((str = configBr.readLine()) != null) { - configSb.append(str); - } - configBr.close(); - ConfigJSON config = ConfigJSONKt.decode(configSb.toString()); - command = config.getCommand(); - antialias = config.getAntialias(); - randomMax = (int) (14 / (config.getProbability() * 0.01)); - getLogger().info("Petpet 初始化成功,使用 " + command + " 以生成GIF。"); - } else { - String defaultConfig = "{\n \"command\": \"pet\",\n \"probability\": 30,\n \"antialias\": false\n}"; - if (!configFile.createNewFile()) { - getLogger().error("无法创建配置文件,请检查权限!"); + sendImage(e.getGroup(), e.getSender(), to, m.contentToString().replace(" ", "")); return; } - FileOutputStream defaultConfigOS = new FileOutputStream(configFile); - defaultConfigOS.write(defaultConfig.getBytes(StandardCharsets.UTF_8)); - getLogger().info("创建配置文件成功,请去 Mirai/plugins/ 目录编辑 petpet.json"); - readConfig(); } - } catch (IOException ex) { - ex.printStackTrace(); + sendImage(e.getGroup(), e.getSender(), to); } } + private boolean isDisabled(Group group) { if (disabledGroup != null && !disabledGroup.isEmpty()) { return disabledGroup.contains(group);