use of com.xenoage.utils.math.geom.Size2f in project Zong by Xenoage.
the class GwtCanvasLayoutRenderer method paintToCanvas.
/**
* Paints the given page of the given {@link Layout} at the given zoom level
* into the given {@link CanvasElement}, which is resized to include the whole page.
* The size in pixel is also returned.
*/
public static Size2i paintToCanvas(Layout layout, int pageIndex, float zoom, com.google.gwt.canvas.client.Canvas canvas) {
Context2d context = canvas.getContext2d();
// compute size
Page page = layout.getPages().get(pageIndex);
Size2f pageSize = page.getFormat().getSize();
int width = Units.mmToPxInt(pageSize.width, zoom);
int height = Units.mmToPxInt(pageSize.height, zoom);
// resize canvas and coordinate space
canvas.setWidth(width + "px");
canvas.setHeight(height + "px");
// double resolution: smoother
int coordSpaceFactor = 2;
canvas.setCoordinateSpaceWidth(width * coordSpaceFactor);
canvas.setCoordinateSpaceHeight(height * coordSpaceFactor);
context.scale(coordSpaceFactor, coordSpaceFactor);
// white page
context.setFillStyle("white");
context.fillRect(0, 0, width, height);
// paint layout
LayoutRenderer.paintToCanvas(layout, pageIndex, zoom, origin, new GwtCanvas(context, CanvasFormat.Raster, CanvasDecoration.Interactive, CanvasIntegrity.Perfect));
return new Size2i(width, height);
}
use of com.xenoage.utils.math.geom.Size2f in project Zong by Xenoage.
the class OpenAction method loadDocument.
/**
* Loads the {@link Doc} at the given URL and stores information about
* the score in the database, if it is not already present.
*/
public Tuple2<ScoreDoc, Doc> loadDocument(String url, @MaybeNull UUID publicID) throws SQLException {
Connection db = Webserver.instance.getDBConnection();
ScoreDoc scoreDoc;
// public ID of the document
if (publicID == null)
publicID = UUID.randomUUID();
// may not exist yet
PreparedStatement stmt = stmt(db, "SELECT public_id FROM docs WHERE public_id = ?", publicID);
ResultSet res = stmt.executeQuery();
boolean error = res.next();
stmt.close();
if (error)
throw new SQLException("A document with this public ID already exists");
// load MusicXML document
try {
// open local or remote file
InputStream inputStream;
if (URLUtils.isAbsoluteURL(url)) {
inputStream = new URL(url).openStream();
} else {
inputStream = new FileInputStream(Webserver.webPath + url);
}
MusicXmlScoreDocFileInput in = new MusicXmlScoreDocFileInput();
scoreDoc = in.read(new JseInputStream(inputStream), null);
} catch (FileNotFoundException ex) {
throw new RuntimeException("file not found");
} catch (MalformedURLException ex) {
throw new RuntimeException("invalid URL: " + url);
} catch (IOException ex) {
throw new RuntimeException("can not read from URL: " + url);
}
// register file in database, if not already known
Layout layout = scoreDoc.getLayout();
boolean isDocKnown = Database.exists(db, "docs", "url = ?", "" + url);
if (!isDocKnown) {
Database.insert(db, "docs", "url, public_id, pages, last_access", "" + url, "" + publicID, layout.getPages().size(), unixTime());
}
// read information about the document
Doc doc = Doc.fromDB(db, "" + url);
// for new documents: save information
if (!isDocKnown) {
// page information
for (int iPage : range(layout.getPages())) {
Size2f pageSize = layout.getPages().get(iPage).getFormat().getSize();
new Page(doc.id, iPage, pageSize.width, pageSize.height).insertIntoDB(db);
}
}
return t(scoreDoc, doc);
}
use of com.xenoage.utils.math.geom.Size2f in project Zong by Xenoage.
the class PageAction method performTry.
@Override
public boolean performTry(Request request, Webserver server, HttpServletResponse response) throws SQLException, IOException {
PageRequest pageRequest = getAs(PageRequest.class, request);
Connection db = server.getDBConnection();
// get ID and number of pages of document
PreparedStatement stmtID = stmt(db, "SELECT id, pages FROM docs WHERE public_id = ?", pageRequest.id);
ResultSet resID = stmtID.executeQuery();
if (!resID.next()) {
stmtID.close();
return false;
}
int docID = resID.getInt(1);
int pages = resID.getInt(2);
stmtID.close();
// unknown page?
if (pageRequest.page < 0 || pageRequest.page >= pages) {
throw new IOException("unknown page");
}
// load size of first page
// if it does not exist (yet), wait a little bit and try again
PreparedStatement stmtFirstPageSize = stmt(db, "SELECT width, height FROM pageinfos WHERE doc_id = ? AND page = 0", docID);
ResultSet resFirstPageSize = stmtFirstPageSize.executeQuery();
if (!resFirstPageSize.next()) {
stmtFirstPageSize.close();
return false;
}
Size2f firstPageSize = new Size2f(resFirstPageSize.getFloat(1), resFirstPageSize.getFloat(2));
stmtFirstPageSize.close();
// unknown scaling?
int scaling = pageRequest.scaling.convertTo10000(firstPageSize);
boolean scalingExists = (ScaledPage.fromDB(db, docID, 0, scaling) != null);
if (!scalingExists) {
throw new IOException("unknown scaling");
}
// deliver page image
PreparedStatement stmtImage = stmt(db, "SELECT image FROM pages WHERE doc_id = ?" + " AND page = ? AND scaling = ?", docID, pageRequest.page, scaling);
ResultSet resImage = stmtImage.executeQuery();
if (!resImage.next()) {
stmtImage.close();
return false;
}
Blob blob = resImage.getBlob(1);
byte[] imageData = blob.getBytes(1, (int) blob.length());
stmtImage.close();
response.setHeader("Content-Type", "image/png");
response.getOutputStream().write(imageData);
// update access time
PreparedStatement stmtTime = stmt(db, "UPDATE docs SET last_access = ? WHERE id = ?", unixTime(), docID);
stmtTime.executeUpdate();
stmtTime.close();
return true;
}
use of com.xenoage.utils.math.geom.Size2f in project Zong by Xenoage.
the class CursorOutput method write.
public JsonObject write(ScoreDoc doc) {
JsonObject ret = new JsonObject();
// create midi sequence and mp mappings
Score score = doc.getScore();
val seq = MidiConverter.convertToSequence(score, optionsForFileExport, new JseMidiSequenceWriter());
// save time map
JsonArray jsonMPs = new JsonArray();
val timeMap = seq.getTimeMap();
for (int iRep : range(timeMap.getRepetitionsCount())) {
for (val time : timeMap.getTimesSorted(iRep)) {
val midiTime = timeMap.getByRepTime(iRep, time);
JsonObject jsonMP = new JsonObject();
jsonMP.addProperty("measure", time.measure);
jsonMP.addProperty("beat", "" + time.beat);
jsonMP.addProperty("ms", midiTime.ms);
jsonMPs.add(jsonMP);
}
}
ret.add("mps", jsonMPs);
// collect data
int measuresCount = score.getMeasuresCount();
ArrayList<System> systems = new ArrayList<>();
ArrayList<Measure> measures = new ArrayList<>();
for (int i = 0; i < measuresCount; i++) {
measures.add(new Measure());
}
int systemCount = 0;
Layout layout = doc.getLayout();
for (int iPage : range(layout.getPages())) {
Page page = layout.getPages().get(iPage);
Size2f pageSize = page.getFormat().getSize();
for (Frame frame : page.getFrames()) {
if (frame instanceof ScoreFrame) {
Point2f absPos = frame.getAbsolutePosition();
float offsetX = absPos.x - frame.getSize().width / 2;
float offsetY = absPos.y - frame.getSize().height / 2;
ScoreFrameLayout sfl = ((ScoreFrame) frame).getScoreFrameLayout();
for (SystemSpacing systemSpacing : sfl.getFrameSpacing().getSystems()) {
// read system data
int systemIndex = systemCount + systemSpacing.getSystemIndexInFrame();
while (systems.size() - 1 < systemIndex) systems.add(new System());
System system = systems.get(systemIndex);
system.page = iPage;
system.top = (offsetY + systemSpacing.offsetYMm) / pageSize.height;
system.bottom = (offsetY + systemSpacing.offsetYMm + systemSpacing.getHeightMm()) / pageSize.height;
// read measure beats
float systemOffsetX = systemSpacing.marginLeftMm;
for (int iMeasure : systemSpacing.getMeasures()) {
Measure measure = measures.get(iMeasure);
measure.system = systemIndex;
measure.left = (offsetX + systemOffsetX + systemSpacing.getMeasureStartMm(iMeasure)) / pageSize.width;
measure.right = (offsetX + systemOffsetX + systemSpacing.getMeasureEndMm(iMeasure)) / pageSize.width;
for (BeatOffset bo : systemSpacing.getColumn(iMeasure).getBeatOffsets()) {
measure.beats.put(bo.getBeat(), (offsetX + systemOffsetX + bo.getOffsetMm()) / pageSize.width);
}
}
}
systemCount += sfl.getFrameSpacing().getSystems().size();
}
}
}
// save systems
JsonArray jsonSystems = new JsonArray();
for (int i = 0; i < systems.size(); i++) {
System system = systems.get(i);
JsonObject jsonSystem = new JsonObject();
jsonSystem.addProperty("number", i);
jsonSystem.addProperty("page", system.page);
jsonSystem.addProperty("top", system.top);
jsonSystem.addProperty("bottom", system.bottom);
jsonSystems.add(jsonSystem);
}
ret.add("systems", jsonSystems);
// save measures
JsonArray jsonMeasures = new JsonArray();
for (int i = 0; i < measuresCount; i++) {
Measure measure = measures.get(i);
JsonObject jsonMeasure = new JsonObject();
jsonMeasure.addProperty("number", i);
jsonMeasure.addProperty("system", measure.system);
jsonMeasure.addProperty("left", measure.left);
jsonMeasure.addProperty("right", measure.right);
// beats
JsonArray jsonBeats = new JsonArray();
ArrayList<Fraction> sortedBeats = new ArrayList<>(measure.beats.keySet());
Collections.sort(sortedBeats);
for (Fraction beat : sortedBeats) {
JsonObject jsonBeat = new JsonObject();
jsonBeat.addProperty("at", "" + beat);
jsonBeat.addProperty("x", measure.beats.get(beat));
jsonBeats.add(jsonBeat);
}
jsonMeasure.add("beats", jsonBeats);
jsonMeasures.add(jsonMeasure);
}
ret.add("measures", jsonMeasures);
// save time cursors
JsonArray jsonTCs = new JsonArray();
for (int iRep : range(timeMap.getRepetitionsCount())) {
for (val time : timeMap.getTimesSorted(iRep)) {
val midiTime = timeMap.getByRepTime(iRep, time);
JsonObject jsonTC = new JsonObject();
jsonTC.addProperty("time", midiTime.ms);
Measure measure = measures.get(time.measure);
System system = systems.get(measure.system);
jsonTC.addProperty("page", system.page);
jsonTC.addProperty("top", system.top);
jsonTC.addProperty("left", measure.beats.get(time.beat));
jsonTC.addProperty("bottom", system.bottom);
jsonTCs.add(jsonTC);
}
}
ret.add("timecursors", jsonTCs);
return ret;
}
use of com.xenoage.utils.math.geom.Size2f in project Zong by Xenoage.
the class ScoreDocFactory method read.
/**
* Creates a {@link ScoreDoc} instance from the given score.
* TIDY: move elsewhere, e.g. in a ScoreDocFactory class
*/
public ScoreDoc read(Score score) throws InvalidFormatException, IOException {
// page format
LayoutFormat layoutFormat = Companion.getDefaultLayoutFormat();
Object oLayoutFormat = score.getMetaData().get("layoutformat");
if (oLayoutFormat instanceof LayoutFormat) {
layoutFormat = (LayoutFormat) oLayoutFormat;
}
LayoutDefaults layoutDefaults = new LayoutDefaults(layoutFormat);
// create the document
ScoreDoc ret = new ScoreDoc(score, layoutDefaults);
Layout layout = ret.getLayout();
// layout basics
PageFormat pageFormat = layoutFormat.getPageFormat(0);
Size2f frameSize = new Size2f(pageFormat.getUseableWidth(), pageFormat.getUseableHeight());
Point2f framePos = new Point2f(pageFormat.getMargins().getLeft() + frameSize.width / 2, pageFormat.getMargins().getTop() + frameSize.height / 2);
// layout the score to find out the needed space
Target target = Target.completeLayoutTarget(new ScoreLayoutArea(frameSize));
ScoreLayouter layouter = new ScoreLayouter(ret, target);
ScoreLayout scoreLayout = isErrorLayoutEnabled ? layouter.createScoreLayout() : layouter.createLayoutWithExceptions();
// create and fill at least one page
if (scoreLayout.frames.size() > 0) {
// normal layout: one frame per page
ScoreFrameChain chain = null;
for (int i = 0; i < scoreLayout.frames.size(); i++) {
Page page = new Page(pageFormat);
layout.addPage(page);
ScoreFrame frame = new ScoreFrame();
frame.setPosition(framePos);
frame.setSize(frameSize);
// TEST frame = frame.withHFill(NoHorizontalSystemFillingStrategy.getInstance());
page.addFrame(frame);
if (chain == null) {
chain = new ScoreFrameChain(score);
chain.setScoreLayout(scoreLayout);
}
chain.add(frame);
}
} else {
// no frames: create a single empty page
Page page = new Page(pageFormat);
layout.addPage(page);
}
return ret;
}
Aggregations