Skip to content

Commit

Permalink
feat(Core): start & end field in image & text element
Browse files Browse the repository at this point in the history
  • Loading branch information
Dituon committed Jan 30, 2025
1 parent e974854 commit dec2794
Show file tree
Hide file tree
Showing 13 changed files with 108 additions and 43 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@

- [ ] Message Hook
- [ ] 消息事件同步锁
- [ ] 自动更新

**Core**

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ public Map<String, Integer> getTemplateExpectedSize(PetpetModel model) {
continue;
}
var avatarEle = (AvatarModel) ele;
for (String key : avatarEle.data.getKey()) {
for (String key : avatarEle.template.getKey()) {
int size = Math.max(avatarEle.getExpectedWidth(), avatarEle.getExpectedHeight());
map.merge(key, size, Math::max);
}
Expand Down
4 changes: 4 additions & 0 deletions core/src/main/java/moe/dituon/petpet/core/GlobalContext.java
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,10 @@ public <T> void execImageProcess(List<T> elements, BiConsumer<Integer, T> functi
var latch = new CountDownLatch(elements.size());
for (int i = 0; i < elements.size(); i++) {
var element = elements.get(i);
if (element == null) {
latch.countDown();
continue;
}
int fi = i;
imageProcessExecutor.execute(() -> {
function.accept(fi, element);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,10 @@ public CanvasContext setCanvas(@NotNull BufferedImage canvas) {
}

public void setLength(int length) {
this.setLength(length, new int[this.frameList.isEmpty() ? 0 : this.frameList.get(0).delay]);
}

public void setLength(int length, int[] delays) {
if (this.length != 1) {
throw new IllegalStateException("setLength() can only be called on single frame canvas");
}
Expand All @@ -118,7 +122,7 @@ public void setLength(int length) {
list.add(first);
for (int i = 1; i < length; i++) {
//TODO: delay
list.add(new ImageFrame(ImageUtils.cloneImage(first.image), first.delay));
list.add(new ImageFrame(ImageUtils.cloneImage(first.image), delays[i % delays.length]));
}
this.frameList = new ImageFrameList(list);
this.graphicsList = new ArrayList<>(Collections.nCopies(length, null));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,9 @@ abstract class RenderedElement {
public abstract int getHeight();

public abstract int getLength();

public int getStartIndex() {
return 0;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ public EncodedImage draw(RequestContext requestContext) {
int height = rendered.getHeight();

canvasContext.putSize(this.elementIdMap.get(element), width, height);
maxLength = Math.max(maxLength, rendered.getLength());
maxLength = Math.max(maxLength, rendered.getLength() + rendered.getStartIndex());
if (element.getId() != null) {
canvasContext.putSize(element.getId(), width, height);
}
Expand All @@ -75,7 +75,9 @@ public EncodedImage draw(RequestContext requestContext) {
));
}
}
if (canvasContext.getLength() == 1) canvasContext.setLength(maxLength);
if (canvasContext.getLength() == 1) {
canvasContext.setLength(maxLength, this.template.getDelay());
}
for (ElementModel.RenderedElement ele : renderedElementList) {
ele.draw();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,11 @@
import moe.dituon.petpet.core.position.AvatarCoords;
import moe.dituon.petpet.template.element.AvatarTemplate;

import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.*;
import java.util.stream.Collectors;

public class AvatarModel implements ElementModel {
public final AvatarTemplate data;
public final AvatarTemplate template;
public final List<AvatarFrame> frames;
public final List<AvatarCoords> coords;
@Getter
Expand All @@ -26,15 +23,20 @@ public class AvatarModel implements ElementModel {
@Getter
public final boolean isDependsOnElementSize;

public final int startIndex;
public final int endIndex;

protected int expectedWidth = -1;
protected int expectedHeight = -1;

protected Set<String> dependentIds = null;

public AvatarModel(AvatarTemplate template) {
this.data = template;
this.template = template;

this.coords = template.getCoords();
this.startIndex = template.getStart();
this.endIndex = template.getEnd();
var tempFrames = new AvatarFrame[template.getMaxLength()];
for (int i = 0; i < template.getMaxLength(); i++) {
switch (ElementFrame.getNElement(coords, i).getType()) {
Expand Down Expand Up @@ -101,7 +103,7 @@ protected void initExpectedSize() {

@Override
public String getId() {
return this.data.getId();
return this.template.getId();
}

@Override
Expand All @@ -126,7 +128,7 @@ public Set<String> getDependentIds() {
}

public List<String> getRequestKeys() {
return this.data.getKey();
return this.template.getKey();
}

@Override
Expand Down Expand Up @@ -185,13 +187,18 @@ public RenderedElement(CanvasContext canvasContext, RequestContext requestContex
@Override
public void draw() {
int canvasLength = this.canvasContext.getLength();
final int absoluteEndIndex = endIndex >= 0 ? endIndex : (canvasLength + endIndex + 1);
var frameList = this.renderedFrames;
if (frameList.size() < canvasLength) {
var tempFrames = new ElementFrame.RenderedFrame[canvasLength];
for (int i = 0; i < canvasLength; i++) {
tempFrames[i] = frameList.get(i % frameList.size()).cloneByIndex(i);
if (i > absoluteEndIndex || i < startIndex) {
tempFrames[i] = null; // cannot draw
continue;
}
tempFrames[i] = frameList.get(i % frameList.size()).cloneByIndex(i - startIndex);
}
frameList = List.of(tempFrames);
frameList = Arrays.asList(tempFrames);
} else if (frameList.size() > canvasLength) {
frameList = frameList.subList(0, canvasLength);
}
Expand All @@ -200,5 +207,10 @@ public void draw() {
frame.draw(i);
});
}

@Override
public int getStartIndex() {
return startIndex;
}
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package moe.dituon.petpet.core.element.text;

import lombok.Getter;
import moe.dituon.petpet.core.GlobalContext;
import moe.dituon.petpet.core.context.CanvasContext;
import moe.dituon.petpet.core.context.RequestContext;
import moe.dituon.petpet.core.element.ElementFrame;
Expand Down Expand Up @@ -114,20 +115,17 @@ protected void initParagraph(GraphicsParagraph paragraph, int index) {
@Override
public void draw() {
int canvasLength = canvasContext.getLength();
final int absoluteEndIndex = endIndex >= 0 ? endIndex : (canvasLength + endIndex + 1);
var frameList = paragraphList;
if (paragraphList.size() <= canvasLength) {
frameList = repeatByLength(frameList, canvasLength);
frameList = repeatByLength(frameList, canvasLength, absoluteEndIndex);
}
for (int i = 0; i < canvasLength; i++) {
draw(frameList.get(i), i);
}
}

protected void draw(GraphicsParagraph paragraph, int i) {
paragraph.draw(
super.canvasContext.getGraphics(i),
super.canvasContext.createLengthContext(paragraph.width, paragraph.height)
);
GlobalContext.getInstance().execImageProcess(frameList, (i, p) -> {
p.draw(
super.canvasContext.getGraphics(i),
super.canvasContext.createLengthContext(p.width, p.height)
);
});
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ public class TextModel implements ElementModel {
protected final List<GraphicsParagraph> paragraphList;
@Getter
public final boolean isAbsolute;
public final int startIndex;
public final int endIndex;

public TextModel(TextTemplate template) {
this(template, true);
Expand All @@ -38,13 +40,17 @@ protected TextModel(TextTemplate template, boolean initFlag) {
this.template = template;
this.paragraphList = new ArrayList<>(template.getMaxLength());
this.isAbsolute = template.getCoords().stream().allMatch(TextXYWCoords::isAbsolute);
this.startIndex = template.getStart();
this.endIndex = template.getEnd();
if (initFlag) init(template);
}

protected TextModel(TextDynamicModel dynamicModel) {
this.template = dynamicModel.template;
this.paragraphList = dynamicModel.paragraphList;
this.isAbsolute = dynamicModel.isAbsolute;
this.startIndex = dynamicModel.startIndex;
this.endIndex = dynamicModel.endIndex;
init(template);
}

Expand Down Expand Up @@ -98,20 +104,23 @@ public static GraphicsParagraph createParagraph(
throw new UnknownError();
}

protected static List<GraphicsParagraph> repeatByLength(@NotNull List<GraphicsParagraph> list, int length) {
protected List<GraphicsParagraph> repeatByLength(@NotNull List<GraphicsParagraph> list, int length, int absoluteEndIndex) {
if (list.size() >= length) return list;
if (list.size() == 1) return Collections.nCopies(length, list.get(0));
if (list.size() == 1 && startIndex == 0 && absoluteEndIndex == length) {
return Collections.nCopies(length, list.get(0));
}
return IntStream.range(0, length)
.mapToObj(i -> list.get(i % list.size()))
.mapToObj(i -> (i > absoluteEndIndex || i < startIndex) ? null : list.get(i % list.size()))
.collect(Collectors.toList());
}

@Override
public void draw(CanvasContext canvasContext, RequestContext requestContext) {
int canvasLength = canvasContext.getLength();
final int absoluteEndIndex = endIndex >= 0 ? endIndex : (canvasLength + endIndex + 1);
var frameList = paragraphList;
if (paragraphList.size() <= canvasLength) {
frameList = repeatByLength(frameList, canvasLength);
frameList = repeatByLength(frameList, canvasLength, absoluteEndIndex);
}
GlobalContext.getInstance().execImageProcess(frameList, (i, p) -> {
p.draw(
Expand Down Expand Up @@ -152,6 +161,11 @@ public void draw() {
public int getLength() {
return template.getMaxLength();
}

@Override
public int getStartIndex() {
return startIndex;
}
}

public static TextModel createTextModel(TextTemplate template) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ data class AvatarTemplate(
@JsonNames("border_radius")
val borderRadius: BorderRadiusList = emptyList(),
val filter: ImageFilterListElement = ImageFilterList.EMPTY,
val start: Int = 0,
val end: Int = -1
) : ElementTemplate() {
@Transient
var basePath: File = systemPath
Expand Down Expand Up @@ -94,6 +96,8 @@ data class AvatarTemplate(
border = builder.border,
borderRadius = builder.borderRadius,
filter = builder.filter,
start = builder.start,
end = builder.end
)

companion object {
Expand Down Expand Up @@ -148,6 +152,10 @@ data class AvatarTemplate(
private set
var filter: ImageFilterList = ImageFilterList.EMPTY
private set
var start: Int = 0
private set
var end: Int = -1
private set

fun id(id: String) = apply { this.id = id }

Expand Down Expand Up @@ -199,6 +207,9 @@ data class AvatarTemplate(

fun filter(filter: ImageFilterList) = apply { this.filter = filter }

fun start(start: Int) = apply { this.start = start }
fun end(end: Int) = apply { this.end = end }

fun build() = AvatarTemplate(this)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,8 @@ data class TextTemplate(
// TODO
@JsonNames("border_radius")
val borderRadius: BorderRadiusList = emptyList(),
val start: Int = 0,
val end: Int = -1
) : ElementTemplate() {
@Transient
val maxLength: Int = maxOf(
Expand Down Expand Up @@ -167,6 +169,8 @@ data class TextTemplate(
strokeSize = builder.strokeSize,
background = builder.background,
borderRadius = builder.borderRadius,
start = builder.start,
end = builder.end
)

class Builder(
Expand Down Expand Up @@ -205,6 +209,10 @@ data class TextTemplate(
private set
var borderRadius: List<BorderRadius> = emptyList()
private set
var start: Int = 0
private set
var end: Int = -1
private set

fun id(id: String) = apply { this.id = id }

Expand Down Expand Up @@ -253,6 +261,9 @@ data class TextTemplate(
fun borderRadius(borderRadius: BorderRadius) = apply { this.borderRadius = mutableListOf(borderRadius) }
fun borderRadius(borderRadius: List<BorderRadius>) = apply { this.borderRadius = borderRadius }

fun start(start: Int) = apply { this.start = start }
fun end(end: Int) = apply { this.end = end }

fun build() = TextTemplate(this)
}
}
Expand Down
30 changes: 16 additions & 14 deletions docs/template/image.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,20 +12,22 @@
}
```

| **属性** | **类型** | **描述** | **默认值** |
|-------------------|----------------------------------------|-------------------|-------------|
| **key** | string | 与输入数据匹配的键名 | `"unknown"` |
| **default** | [ImageSrc](#imagesrc) | 默认图像地址, 别名为 `src` ||
| **coords** | [Coords](#coords) | 图像坐标 | 必须 |
| **crop** | [Crop](#crop) | 图像裁剪坐标 ||
| **fit** | [Fit](#fit) | 图像适应方式 | `fill` |
| **position** | [Offset](./length.md#offset) | 图像适应偏移 | `center` |
| **rotate** | [RotateTransition](#rotate-transition) | 图像旋转函数 | `false` |
| **angle** | float | 顺时针方向旋转角度,单位为度 | `0` |
| **origin** | [Offset](./length.md#offset) | 图像旋转原点 | `center` |
| **opacity** | float | 图像不透明度,取值范围[0, 1] | `1` |
| **border_radius** | [BorderRadius](#borderradius) | 边框圆角半径 | `0` |
| **filter** | [Filter](./filter.md#image-filter)[] | 图像滤镜 ||
| **属性** | **类型** | **描述** | **默认值** |
|-------------------|----------------------------------------|---------------------------------|-------------|
| **key** | string | 与输入数据匹配的键名 | `"unknown"` |
| **default** | [ImageSrc](#imagesrc) | 默认图像地址, 别名为 `src` ||
| **coords** | [Coords](#coords) | 图像坐标 | 必须 |
| **crop** | [Crop](#crop) | 图像裁剪坐标 ||
| **fit** | [Fit](#fit) | 图像适应方式 | `fill` |
| **position** | [Offset](./length.md#offset) | 图像适应偏移 | `center` |
| **rotate** | [RotateTransition](#rotate-transition) | 图像旋转函数 | `false` |
| **angle** | float | 顺时针方向旋转角度,单位为度 | `0` |
| **origin** | [Offset](./length.md#offset) | 图像旋转原点 | `center` |
| **opacity** | float | 图像不透明度,取值范围[0, 1] | `1` |
| **border_radius** | [BorderRadius](#borderradius) | 边框圆角半径 | `0` |
| **filter** | [Filter](./filter.md#image-filter)[] | 图像滤镜 ||
| **start** | int | 起始索引 | `0` |
| **end** | int | 结束索引 (负数时为末尾索引, 例如 `-1` 表示最后一帧) | `-1` |

## 动画

Expand Down
2 changes: 2 additions & 0 deletions docs/template/text.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
| **style** | [TextStyle](#text-style) | 文本样式 | `plain` |
| **stroke_color** | [Color](./types.md#color) | 文本描边颜色 | `none` |
| **stroke_size** | float | 文本描边大小, 单位为 px | `0px` |
| **start** | int | 起始索引 | `0` |
| **end** | int | 结束索引 (负数时为末尾索引, 例如 `-1` 表示最后一帧) | `-1` |

## 动画

Expand Down

0 comments on commit dec2794

Please sign in to comment.