Initial commit

This commit is contained in:
Olga Miller 2017-01-03 18:32:45 +01:00
commit 6a5cf6b221
83 changed files with 5443 additions and 0 deletions

View file

@ -0,0 +1,40 @@
/*
Copyright 2017 Olga Miller <olga.rgb@gmail.com>
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package om.sstvencoder.TextOverlay;
import java.io.IOException;
public interface IReader {
void beginRootObject() throws IOException;
void beginObject() throws IOException;
void endObject() throws IOException;
void beginArray() throws IOException;
void endArray() throws IOException;
boolean hasNext() throws IOException;
String readString() throws IOException;
boolean readBoolean() throws IOException;
float readFloat() throws IOException;
int readInt() throws IOException;
}

View file

@ -0,0 +1,40 @@
/*
Copyright 2017 Olga Miller <olga.rgb@gmail.com>
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package om.sstvencoder.TextOverlay;
import android.support.annotation.NonNull;
import java.io.IOException;
public interface IWriter {
void beginRootObject() throws IOException;
void beginObject(@NonNull String name) throws IOException;
void endObject() throws IOException;
void beginArray(@NonNull String name) throws IOException;
void endArray() throws IOException;
void write(@NonNull String name, String value) throws IOException;
void write(@NonNull String name, boolean value) throws IOException;
void write(@NonNull String name, float value) throws IOException;
void write(@NonNull String name, int value) throws IOException;
}

View file

@ -0,0 +1,96 @@
/*
Copyright 2017 Olga Miller <olga.rgb@gmail.com>
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package om.sstvencoder.TextOverlay;
import android.graphics.Color;
import java.io.Serializable;
public class Label implements Serializable {
private String mText;
private float mTextSize;
private String mFamilyName;
private boolean mBold, mItalic;
private int mForeColor, mBackColor;
public Label() {
mText = "";
mTextSize = 2.0f;
mFamilyName = null;
mBold = true;
mItalic = false;
mForeColor = Color.BLACK;
mBackColor = Color.TRANSPARENT;
}
public String getText() {
return mText;
}
public void setText(String text) {
if (text != null)
mText = text;
}
public float getTextSize() {
return mTextSize;
}
public void setTextSize(float textSize) {
if (textSize > 0f)
mTextSize = textSize;
}
public String getFamilyName() {
return mFamilyName;
}
public void setFamilyName(String familyName) {
mFamilyName = familyName;
}
public boolean getBold() {
return mBold;
}
public void setBold(boolean bold) {
mBold = bold;
}
public boolean getItalic() {
return mItalic;
}
public void setItalic(boolean italic) {
mItalic = italic;
}
public int getForeColor() {
return mForeColor;
}
public void setForeColor(int color) {
mForeColor = color;
}
public int getBackColor() {
return mBackColor;
}
public void setBackColor(int color) {
mBackColor = color;
}
}

View file

@ -0,0 +1,184 @@
/*
Copyright 2017 Olga Miller <olga.rgb@gmail.com>
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package om.sstvencoder.TextOverlay;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.support.annotation.NonNull;
import java.io.IOException;
import java.util.LinkedList;
import java.util.List;
import om.sstvencoder.Utility;
public class LabelCollection {
private class Size {
private float mW, mH;
Size(float w, float h) {
mW = w;
mH = h;
}
float width() {
return mW;
}
float height() {
return mH;
}
}
private final List<LabelContainer> mLabels;
private Size mScreenSize;
private float mTextSizeFactor;
private LabelContainer mActiveLabel, mEditLabel;
private float mPreviousX, mPreviousY;
public LabelCollection() {
mLabels = new LinkedList<>();
mPreviousX = 0f;
mPreviousY = 0f;
}
public void update(float w, float h) {
if (mScreenSize != null) {
float x = (w - mScreenSize.width()) / 2f;
float y = (h - mScreenSize.height()) / 2f;
for (LabelContainer label : mLabels)
label.offset(x, y);
}
mScreenSize = new Size(w, h);
mTextSizeFactor = getTextSizeFactor(w, h);
for (LabelContainer label : mLabels)
label.update(mTextSizeFactor, w, h);
}
private float getTextSizeFactor(float w, float h) {
Rect bounds = Utility.getEmbeddedRect((int) w, (int) h, 320, 240);
return 0.1f * bounds.height();
}
public void draw(Canvas canvas) {
for (LabelContainer label : mLabels)
label.draw(canvas);
if (mActiveLabel != null)
mActiveLabel.drawActive(canvas);
}
public void draw(Canvas canvas, Rect src, Rect dst) {
for (LabelContainer label : mLabels)
label.draw(canvas, src, dst);
}
public boolean moveLabelBegin(float x, float y) {
mActiveLabel = find(x, y);
if (mActiveLabel == null)
return false;
mLabels.remove(mActiveLabel);
mPreviousX = x;
mPreviousY = y;
return true;
}
public void moveLabel(float x, float y) {
mActiveLabel.offset(x - mPreviousX, y - mPreviousY);
mActiveLabel.update(mTextSizeFactor, mScreenSize.width(), mScreenSize.height());
mPreviousX = x;
mPreviousY = y;
}
public void moveLabelEnd() {
mLabels.add(mActiveLabel);
mActiveLabel = null;
mPreviousX = 0f;
mPreviousY = 0f;
}
public Label editLabelBegin(float x, float y) {
mEditLabel = find(x, y);
if (mEditLabel == null) {
mEditLabel = new LabelContainer(new Label());
mEditLabel.offset(x, y);
}
return mEditLabel.getContent();
}
public void editLabelEnd(Label label) {
if (label != null) { // not canceled
if ("".equals(label.getText().trim())) {
if (mLabels.contains(mEditLabel))
mLabels.remove(mEditLabel);
} else {
if (!mLabels.contains(mEditLabel))
mLabels.add(mEditLabel);
mEditLabel.setContent(label);
mEditLabel.update(mTextSizeFactor, mScreenSize.width(), mScreenSize.height());
}
}
mEditLabel = null;
}
private LabelContainer find(float x, float y) {
for (LabelContainer label : mLabels) {
if (label.contains(x, y))
return label;
}
return null;
}
private void add(LabelContainer label) {
if (mLabels.size() == 0)
mLabels.add(label);
else
mLabels.add(0, label);
}
public void write(@NonNull IWriter writer) throws IOException {
writer.beginRootObject();
{
writer.write("width", mScreenSize.width());
writer.write("height", mScreenSize.height());
writer.beginArray("labels");
{
for (LabelContainer label : mLabels)
label.write(writer);
}
writer.endArray();
}
writer.endObject();
}
public void read(@NonNull IReader reader) throws IOException {
reader.beginRootObject();
{
float w = reader.readFloat();
float h = reader.readFloat();
reader.beginArray();
{
while (reader.hasNext()) {
LabelContainer label = new LabelContainer(new Label());
label.read(reader);
add(label);
}
}
reader.endArray();
update(w, h);
}
reader.endObject();
}
}

View file

@ -0,0 +1,117 @@
/*
Copyright 2017 Olga Miller <olga.rgb@gmail.com>
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package om.sstvencoder.TextOverlay;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.support.annotation.NonNull;
import java.io.IOException;
class LabelContainer {
private Label mLabel;
private LabelPainter mPainter;
private float mX, mY; // left-bottom corner
LabelContainer(@NonNull Label label) {
mLabel = label;
mPainter = new LabelPainter(label);
mX = mY = 0f;
}
boolean contains(float x, float y) {
return mPainter.getBounds().contains(x, y);
}
void draw(Canvas canvas) {
mPainter.draw(canvas);
}
void drawActive(Canvas canvas) {
mPainter.drawActive(canvas);
}
void draw(Canvas canvas, Rect src, Rect dst) {
mPainter.draw(canvas, src, dst);
}
void offset(float x, float y) {
mX += x;
mY += y;
}
void update(float textSizeFactor, float screenW, float screenH) {
mPainter.update(textSizeFactor, screenW, screenH, mX, mY);
}
Label getContent() {
return mLabel;
}
void setContent(@NonNull Label label) {
mLabel = label;
mPainter.setLabel(label);
}
void write(IWriter writer) throws IOException {
writer.beginRootObject();
{
writer.write("position_x", mX);
writer.write("position_y", mY);
writer.beginObject("label");
{
writeLabel(writer, mLabel);
}
writer.endObject();
}
writer.endObject();
}
void read(IReader reader) throws IOException {
reader.beginRootObject();
{
mX = reader.readFloat();
mY = reader.readFloat();
reader.beginObject();
{
readLabel(reader, mLabel);
}
reader.endObject();
}
reader.endObject();
}
private void writeLabel(IWriter writer, Label label) throws IOException {
writer.write("text", label.getText());
writer.write("text_size", label.getTextSize());
writer.write("family_name", label.getFamilyName());
writer.write("bold", label.getBold());
writer.write("italic", label.getItalic());
writer.write("fore_color", label.getForeColor());
writer.write("back_color", label.getBackColor());
}
private void readLabel(IReader reader, Label label) throws IOException {
label.setText(reader.readString());
label.setTextSize(reader.readFloat());
label.setFamilyName(reader.readString());
label.setBold(reader.readBoolean());
label.setItalic(reader.readBoolean());
label.setForeColor(reader.readInt());
label.setBackColor(reader.readInt());
}
}

View file

@ -0,0 +1,303 @@
/*
Copyright 2017 Olga Miller <olga.rgb@gmail.com>
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package om.sstvencoder.TextOverlay;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Typeface;
import android.support.annotation.NonNull;
class LabelPainter {
private interface IDrawer {
void draw(Canvas canvas);
void drawShadow(Canvas canvas);
void draw(Canvas canvas, Rect src, Rect dst);
RectF getBounds();
}
private class InDrawer implements IDrawer {
private float mSizeFactor;
private float mX, mY;
private InDrawer(float sizeFactor, float x, float y) {
mSizeFactor = sizeFactor;
mX = x;
mY = y;
setPaintSettings(mSizeFactor);
}
@Override
public void draw(Canvas canvas) {
canvas.drawText(mLabel.getText(), mX, mY, mPaint);
}
@Override
public void drawShadow(Canvas canvas) {
RectF bounds = new RectF(getBounds());
float rx = 10f;
float ry = 10f;
mPaint.setColor(Color.LTGRAY);
mPaint.setAlpha(100);
mPaint.setStyle(Paint.Style.FILL);
canvas.drawRoundRect(bounds, rx, ry, mPaint);
mPaint.setAlpha(255);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setColor(Color.RED);
bounds.inset(-5.0f, -5.0f);
canvas.drawRoundRect(bounds, rx, ry, mPaint);
mPaint.setColor(Color.GREEN);
bounds.inset(1.0f, 1.0f);
canvas.drawRoundRect(bounds, rx, ry, mPaint);
mPaint.setColor(Color.BLUE);
bounds.inset(1.0f, 1.0f);
canvas.drawRoundRect(bounds, rx, ry, mPaint);
setPaintSettings(mSizeFactor);
}
@Override
public void draw(Canvas canvas, Rect src, Rect dst) {
float factor = (dst.height() / (float) src.height());
float x = (mX - src.left) * factor;
float y = (mY - src.top) * factor;
setTextSize(factor * mSizeFactor);
canvas.drawText(mLabel.getText(), x, y, mPaint);
setTextSize(mSizeFactor);
}
@Override
public RectF getBounds() {
RectF bounds = new RectF(getTextBounds());
bounds.offset(mX, mY);
return bounds;
}
private Rect getTextBounds() {
Rect bounds = new Rect();
String text = mLabel.getText();
mPaint.getTextBounds(text, 0, text.length(), bounds);
return bounds;
}
private void setPaintSettings(float sizeFactor) {
mPaint.setAlpha(255);
mPaint.setStyle(Paint.Style.FILL);
mPaint.setColor(mLabel.getForeColor());
mPaint.setTypeface(Typeface.create(mLabel.getFamilyName(), getTypeface()));
setTextSize(sizeFactor);
}
private void setTextSize(float sizeFactor) {
mPaint.setTextSize(mLabel.getTextSize() * sizeFactor);
}
private int getTypeface() {
int typeface = Typeface.NORMAL;
if (mLabel.getBold() && mLabel.getItalic())
typeface = Typeface.BOLD_ITALIC;
else {
if (mLabel.getBold())
typeface = Typeface.BOLD;
else if (mLabel.getItalic())
typeface = Typeface.ITALIC;
}
return typeface;
}
}
private class OutDrawer implements IDrawer {
private Path mPath;
private RectF mBoundsOutside;
private float mMinSize, mX, mY;
private OutDrawer(float min) {
mMinSize = min * 0.5f;
mPaint.setAlpha(255);
}
private void leftOut(RectF rect, float screenH) {
mX = 0f;
mY = Math.min(Math.max(mMinSize, rect.top + rect.height() * 0.5f), screenH - mMinSize);
mPath = getLeftAlignedTriangle(mX, mY, mMinSize);
mBoundsOutside = new RectF(mX, mY - mMinSize, mX + mMinSize, mY + mMinSize);
}
private void topOut(RectF rect, float screenW) {
mX = Math.min(Math.max(mMinSize, rect.left + rect.width() * 0.5f), screenW - mMinSize);
mY = 0f;
mPath = getTopAlignedTriangle(mX, mY, mMinSize);
mBoundsOutside = new RectF(mX - mMinSize, mY, mX + mMinSize * 0.5f, mY + mMinSize);
}
private void rightOut(RectF rect, float screenW, float screenH) {
mX = screenW;
mY = Math.min(Math.max(mMinSize, rect.top + rect.height() * 0.5f), screenH - mMinSize);
mPath = getRightAlignedTriangle(mX, mY, mMinSize);
mBoundsOutside = new RectF(mX - mMinSize, mY - mMinSize, mX, mY + mMinSize);
}
private void bottomOut(RectF rect, float screenW, float screenH) {
mX = Math.min(Math.max(mMinSize, rect.left + rect.width() * 0.5f), screenW - mMinSize);
mY = screenH;
mPath = getBottomAlignedTriangle(mX, mY, mMinSize);
mBoundsOutside = new RectF(mX - mMinSize, mY - mMinSize, mX + mMinSize, mY);
}
private Path getLeftAlignedTriangle(float x, float y, float r) {
Path path = new Path();
path.moveTo(x, y - r);
path.lineTo(x, y + r);
path.lineTo(x + r * 0.6f, y);
path.lineTo(x, y - r);
return path;
}
private Path getTopAlignedTriangle(float x, float y, float r) {
Path path = new Path();
path.moveTo(x - r, y);
path.lineTo(x, y + r * 0.6f);
path.lineTo(x + r, y);
path.lineTo(x - r, y);
return path;
}
private Path getRightAlignedTriangle(float x, float y, float r) {
Path path = new Path();
path.moveTo(x, y - r);
path.lineTo(x - r * 0.6f, y);
path.lineTo(x, y + r);
path.lineTo(x, y - r);
return path;
}
private Path getBottomAlignedTriangle(float x, float y, float r) {
Path path = new Path();
path.moveTo(x - r, y);
path.lineTo(x, y - r * 0.6f);
path.lineTo(x + r, y);
path.lineTo(x - r, y);
return path;
}
@Override
public void draw(Canvas canvas) {
mPaint.setColor(mLabel.getForeColor());
mPaint.setStyle(Paint.Style.FILL);
canvas.drawPath(mPath, mPaint);
mPaint.setColor(Color.WHITE);
mPaint.setStyle(Paint.Style.STROKE);
canvas.drawPath(mPath, mPaint);
}
@Override
public void draw(Canvas canvas, Rect src, Rect dst) {
}
@Override
public void drawShadow(Canvas canvas) {
float r = 2f * mMinSize;
mPaint.setColor(Color.LTGRAY);
mPaint.setAlpha(100);
mPaint.setStyle(Paint.Style.FILL);
canvas.drawCircle(mX, mY, r, mPaint);
mPaint.setAlpha(255);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setColor(Color.RED);
canvas.drawCircle(mX, mY, r + 1f, mPaint);
mPaint.setColor(Color.GREEN);
canvas.drawCircle(mX, mY, r, mPaint);
mPaint.setColor(Color.BLUE);
canvas.drawCircle(mX, mY, r - 1f, mPaint);
}
@Override
public RectF getBounds() {
return mBoundsOutside;
}
}
private final Paint mPaint;
private Label mLabel;
private IDrawer mDrawer;
LabelPainter(@NonNull Label label) {
mLabel = label;
mPaint = new Paint();
mPaint.setAntiAlias(true);
}
void draw(Canvas canvas) {
mDrawer.draw(canvas);
}
void drawActive(Canvas canvas) {
mDrawer.drawShadow(canvas);
mDrawer.draw(canvas);
}
void draw(Canvas canvas, Rect src, Rect dst) {
mDrawer.draw(canvas, src, dst);
}
RectF getBounds() {
return mDrawer.getBounds();
}
void setLabel(@NonNull Label label) {
mLabel = label;
}
void update(float sizeFactor, float screenW, float screenH, float x, float y) {
InDrawer inDrawer = new InDrawer(sizeFactor, x, y);
RectF rect = inDrawer.getBounds();
float minSize = 1.5f * sizeFactor;
OutDrawer outDrawer = null;
if (rect.right < minSize) { // left out
outDrawer = new OutDrawer(minSize);
outDrawer.leftOut(rect, screenH);
} else if (rect.bottom < minSize) {// top out
outDrawer = new OutDrawer(minSize);
outDrawer.topOut(rect, screenW);
} else if (rect.left > (screenW - minSize)) { // right out
outDrawer = new OutDrawer(minSize);
outDrawer.rightOut(rect, screenW, screenH);
} else if (rect.top > (screenH - minSize)) { // bottom out
outDrawer = new OutDrawer(minSize);
outDrawer.bottomOut(rect, screenW, screenH);
}
mDrawer = outDrawer == null ? inDrawer : outDrawer;
}
}