Better image compression and added prev page thumbnail on edit page
This commit is contained in:
parent
31f01a2850
commit
2bf05c4690
8 changed files with 125 additions and 57 deletions
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -8111,6 +8111,9 @@ video {
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
background-color: white; }
|
background-color: white; }
|
||||||
|
|
||||||
|
.book-thumb.page-preview {
|
||||||
|
flex-basis: unset; }
|
||||||
|
|
||||||
.edit-page-controllers {
|
.edit-page-controllers {
|
||||||
border-radius: 15px;
|
border-radius: 15px;
|
||||||
background-color: rgba(134, 134, 134, 0.1); }
|
background-color: rgba(134, 134, 134, 0.1); }
|
||||||
|
|
|
@ -497,6 +497,9 @@ video{
|
||||||
background-color: white;
|
background-color: white;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.book-thumb.page-preview{
|
||||||
|
flex-basis: unset;
|
||||||
|
}
|
||||||
.edit-page-controllers{
|
.edit-page-controllers{
|
||||||
border-radius: 15px;
|
border-radius: 15px;
|
||||||
background-color: rgba(134, 134, 134, 0.1);
|
background-color: rgba(134, 134, 134, 0.1);
|
||||||
|
|
|
@ -86,7 +86,10 @@
|
||||||
<span>Edit</span>
|
<span>Edit</span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li :class="!editMode ? 'is-active' : ''" @click="editMode=false">
|
<li
|
||||||
|
:class="!editMode ? 'is-active' : ''"
|
||||||
|
@click="currentPage = -7;editMode=false"
|
||||||
|
>
|
||||||
<a>
|
<a>
|
||||||
<span class="icon is-small">
|
<span class="icon is-small">
|
||||||
<i class="fa fa-eye" aria-hidden="true"></i>
|
<i class="fa fa-eye" aria-hidden="true"></i>
|
||||||
|
@ -110,9 +113,9 @@
|
||||||
<div class="page-editor" v-else>
|
<div class="page-editor" v-else>
|
||||||
<div class="columns">
|
<div class="columns">
|
||||||
<!-- Croppa -->
|
<!-- Croppa -->
|
||||||
<div class="column is-flex">
|
<div class="column has-text-centered">
|
||||||
<div v-if="pages[currentPage].loaded">
|
<div v-if="pages[currentPage].loaded">
|
||||||
<h1 class="subtitle">{{pages[currentPage].text}}</h1>
|
<h1 class="subtitle is-3">{{pages[currentPage].text}}</h1>
|
||||||
<croppa
|
<croppa
|
||||||
v-model="pages[currentPage].croppa"
|
v-model="pages[currentPage].croppa"
|
||||||
:prevent-white-space="true"
|
:prevent-white-space="true"
|
||||||
|
@ -132,17 +135,12 @@
|
||||||
<div
|
<div
|
||||||
class="edit-page-controllers column is-3 is-flex-column is-justify-centered has-text-centered"
|
class="edit-page-controllers column is-3 is-flex-column is-justify-centered has-text-centered"
|
||||||
>
|
>
|
||||||
<div class="change-image">
|
|
||||||
<button class="button" @click="pages[currentPage].croppa.chooseFile()">
|
|
||||||
<i class="fa fa-fw fa-refresh"></i> Change Image
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div class="field" v-if="currentPage===0 && pages.length===1">
|
<div class="field" v-if="currentPage===0 && pages.length===1">
|
||||||
<label class="label">Page width</label>
|
<label class="label">Page width</label>
|
||||||
<input
|
<input
|
||||||
type="range"
|
type="range"
|
||||||
min="200"
|
:min="DEFAULT_PAGE_WIDTH-50"
|
||||||
max="600"
|
:max="DEFAULT_PAGE_WIDTH"
|
||||||
v-model="bookWidth"
|
v-model="bookWidth"
|
||||||
:disabled="!pages[currentPage].imageLoaded"
|
:disabled="!pages[currentPage].imageLoaded"
|
||||||
/>
|
/>
|
||||||
|
@ -150,7 +148,7 @@
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
class="button is-rounded is-outlined is-small"
|
class="button is-rounded is-outlined is-small"
|
||||||
:disabled="!pages[currentPage].imageLoaded"
|
:disabled="!pages[currentPage].imageLoaded || bookWidth<= DEFAULT_PAGE_WIDTH - 50"
|
||||||
@click="bookWidth-=2"
|
@click="bookWidth-=2"
|
||||||
>
|
>
|
||||||
<i class="fa fa-fw fa-minus"></i>
|
<i class="fa fa-fw fa-minus"></i>
|
||||||
|
@ -158,19 +156,40 @@
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
class="button is-rounded is-outlined is-small"
|
class="button is-rounded is-outlined is-small"
|
||||||
:disabled="!pages[currentPage].imageLoaded"
|
:disabled="!pages[currentPage].imageLoaded || bookWidth >= DEFAULT_PAGE_WIDTH"
|
||||||
@click="bookWidth+=2"
|
@click="bookWidth+=2"
|
||||||
>
|
>
|
||||||
<i class="fa fa-fw fa-plus"></i>
|
<i class="fa fa-fw fa-plus"></i>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="prev-page-preview" v-else>
|
||||||
|
<div
|
||||||
|
class="is-flex is-justify-centered"
|
||||||
|
v-if="pages[currentPage - 1] && pages[currentPage - 1].base64"
|
||||||
|
>
|
||||||
|
<div class="book-thumb page-preview">
|
||||||
|
<div class="book-text">
|
||||||
|
<div>Previouse Page</div>
|
||||||
|
</div>
|
||||||
|
<div class="book-cover">
|
||||||
|
<img
|
||||||
|
:src="pages[currentPage - 1] ? pages[currentPage - 1].base64: ''"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="book-text">
|
||||||
|
<div>{{pages[currentPage - 1].text}}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<hr class="is-fullwidth-container" />
|
||||||
<div class="field" v-if="currentPage===0 && pages.length===1">
|
<div class="field" v-if="currentPage===0 && pages.length===1">
|
||||||
<label class="label">Page height</label>
|
<label class="label">Page height</label>
|
||||||
<input
|
<input
|
||||||
type="range"
|
type="range"
|
||||||
min="200"
|
:min="DEFAULT_PAGE_HEIGHT-50"
|
||||||
max="600"
|
:max="DEFAULT_PAGE_HEIGHT"
|
||||||
v-model="bookHeight"
|
v-model="bookHeight"
|
||||||
:disabled="!pages[currentPage].imageLoaded"
|
:disabled="!pages[currentPage].imageLoaded"
|
||||||
/>
|
/>
|
||||||
|
@ -178,7 +197,7 @@
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
class="button is-rounded is-outlined is-small"
|
class="button is-rounded is-outlined is-small"
|
||||||
:disabled="!pages[currentPage].imageLoaded"
|
:disabled="!pages[currentPage].imageLoaded || bookWidth<= DEFAULT_PAGE_HEIGHT - 50"
|
||||||
@click="bookHeight-=2"
|
@click="bookHeight-=2"
|
||||||
>
|
>
|
||||||
<i class="fa fa-fw fa-minus"></i>
|
<i class="fa fa-fw fa-minus"></i>
|
||||||
|
@ -186,7 +205,7 @@
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
class="button is-rounded is-outlined is-small"
|
class="button is-rounded is-outlined is-small"
|
||||||
:disabled="!pages[currentPage].imageLoaded"
|
:disabled="!pages[currentPage].imageLoaded || bookWidth >= DEFAULT_PAGE_HEIGHT"
|
||||||
@click="bookHeight+=2"
|
@click="bookHeight+=2"
|
||||||
>
|
>
|
||||||
<i class="fa fa-fw fa-plus"></i>
|
<i class="fa fa-fw fa-plus"></i>
|
||||||
|
@ -238,8 +257,19 @@
|
||||||
<i class="fa fa-fw fa-rotate-right"></i>
|
<i class="fa fa-fw fa-rotate-right"></i>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="change-image">
|
||||||
|
<button
|
||||||
|
class="button is-fullwidth-container"
|
||||||
|
@click="pages[currentPage].croppa.chooseFile()"
|
||||||
|
>
|
||||||
|
<i class="fa fa-fw fa-refresh"></i> Change Image
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
<div class="remove-image" v-if="currentPage === pages.length-1">
|
<div class="remove-image" v-if="currentPage === pages.length-1">
|
||||||
<button class="button is-danger" @click="deleteLastPage()">
|
<button
|
||||||
|
class="button is-danger is-fullwidth-container"
|
||||||
|
@click="deleteLastPage()"
|
||||||
|
>
|
||||||
<i class="fa fa-fw fa-trash"></i> Delete Page
|
<i class="fa fa-fw fa-trash"></i> Delete Page
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
@ -321,6 +351,13 @@ import { mapGetters, mapActions } from "vuex";
|
||||||
import Flipbook from "../components/flipbook/flipbook.cjs.js";
|
import Flipbook from "../components/flipbook/flipbook.cjs.js";
|
||||||
import Croppa from "vue-croppa";
|
import Croppa from "vue-croppa";
|
||||||
import Services from "../../services";
|
import Services from "../../services";
|
||||||
|
|
||||||
|
const DEFAULT_PAGE_WIDTH = 350;
|
||||||
|
const DEFAULT_PAGE_HEIGHT = 350;
|
||||||
|
|
||||||
|
const DEFAULT_ZOOM = 500;
|
||||||
|
const MIME_TYPE = "image/jpeg";
|
||||||
|
const COMPRESSION_RATE = 0.4;
|
||||||
export default {
|
export default {
|
||||||
name: "EditBook",
|
name: "EditBook",
|
||||||
props: ["editBook"],
|
props: ["editBook"],
|
||||||
|
@ -344,14 +381,14 @@ export default {
|
||||||
console.log(lastPage, currentPage);
|
console.log(lastPage, currentPage);
|
||||||
if (this.pages[lastPage] && lastPage >= 0) {
|
if (this.pages[lastPage] && lastPage >= 0) {
|
||||||
const imageBlob = await this.pages[lastPage].croppa.promisedBlob(
|
const imageBlob = await this.pages[lastPage].croppa.promisedBlob(
|
||||||
"image/jpg",
|
MIME_TYPE,
|
||||||
0.8
|
COMPRESSION_RATE
|
||||||
);
|
);
|
||||||
if (imageBlob) {
|
if (imageBlob) {
|
||||||
let url = URL.createObjectURL(imageBlob);
|
let url = URL.createObjectURL(imageBlob);
|
||||||
this.pages[lastPage].base64 = this.pages[
|
this.pages[lastPage].base64 = this.pages[
|
||||||
lastPage
|
lastPage
|
||||||
].croppa.generateDataUrl("image/jpg", 0.8);
|
].croppa.generateDataUrl(MIME_TYPE, COMPRESSION_RATE);
|
||||||
this.pages[lastPage].image = url;
|
this.pages[lastPage].image = url;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -365,7 +402,7 @@ export default {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
this.pageRotation = 0;
|
this.pageRotation = 0;
|
||||||
this.pageZoom = 500;
|
this.pageZoom = DEFAULT_ZOOM;
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
pageRotation: function(newAngle) {
|
pageRotation: function(newAngle) {
|
||||||
|
@ -424,6 +461,22 @@ export default {
|
||||||
onCroppaImageLoaded() {
|
onCroppaImageLoaded() {
|
||||||
this.pages[this.currentPage].imageLoaded = true;
|
this.pages[this.currentPage].imageLoaded = true;
|
||||||
},
|
},
|
||||||
|
async promiseAllProgress(
|
||||||
|
promises: Promise<any>[],
|
||||||
|
callback: (done: number, total: number) => void
|
||||||
|
): Promise<any> {
|
||||||
|
let counter = 0;
|
||||||
|
callback(counter, promises.length);
|
||||||
|
for (let i = 0; i < promises.length; i++) {
|
||||||
|
const promise = promises[i];
|
||||||
|
promise.then(async val => {
|
||||||
|
counter++;
|
||||||
|
callback(counter, promises.length);
|
||||||
|
return val;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return Promise.all(promises);
|
||||||
|
},
|
||||||
async onUploadClicked() {
|
async onUploadClicked() {
|
||||||
//TODO: Better validations
|
//TODO: Better validations
|
||||||
if (!this.book.title || !this.book.title.length) {
|
if (!this.book.title || !this.book.title.length) {
|
||||||
|
@ -448,26 +501,31 @@ export default {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.uploading = true;
|
this.uploading = true;
|
||||||
const resp = await Services.ApiService.uploadBook({
|
try {
|
||||||
title: this.book.title,
|
const resp = await Services.ApiService.uploadBook({
|
||||||
author: this.book.author,
|
title: this.book.title,
|
||||||
ltr: this.book.ltr,
|
author: this.book.author,
|
||||||
pages: this.pages.map(
|
ltr: this.book.ltr,
|
||||||
p => p.base64 || p.croppa.generateDataUrl("image/jpg", 0.7)
|
pages: this.pages.map(
|
||||||
)
|
p =>
|
||||||
});
|
p.base64 || p.croppa.generateDataUrl(MIME_TYPE, COMPRESSION_RATE)
|
||||||
if (resp.code === 0) {
|
)
|
||||||
this.notify({
|
|
||||||
message: `Woop Woop!! ${this.book.title} has been added!`,
|
|
||||||
level: "success"
|
|
||||||
});
|
|
||||||
this.getUser();
|
|
||||||
this.$router.replace({ path: `/` });
|
|
||||||
} else {
|
|
||||||
this.notify({
|
|
||||||
message: `Something went wrong!`,
|
|
||||||
level: "danger"
|
|
||||||
});
|
});
|
||||||
|
if (resp.code === 0) {
|
||||||
|
this.notify({
|
||||||
|
message: `Woop Woop!! ${this.book.title} has been added!`,
|
||||||
|
level: "success"
|
||||||
|
});
|
||||||
|
this.getUser();
|
||||||
|
this.$router.replace({ path: `/` });
|
||||||
|
} else {
|
||||||
|
this.notify({
|
||||||
|
message: `Something went wrong!`,
|
||||||
|
level: "danger"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.log(`Error... ${e.message}`);
|
||||||
}
|
}
|
||||||
this.uploading = false;
|
this.uploading = false;
|
||||||
},
|
},
|
||||||
|
@ -489,8 +547,8 @@ export default {
|
||||||
console.log("In else");
|
console.log("In else");
|
||||||
const nextPage = lastPage + 1;
|
const nextPage = lastPage + 1;
|
||||||
const imageBlob = await this.pages[lastPage].croppa.promisedBlob(
|
const imageBlob = await this.pages[lastPage].croppa.promisedBlob(
|
||||||
"image/jpg",
|
MIME_TYPE,
|
||||||
0.8
|
COMPRESSION_RATE
|
||||||
);
|
);
|
||||||
if (!imageBlob) {
|
if (!imageBlob) {
|
||||||
this.notify({
|
this.notify({
|
||||||
|
@ -501,10 +559,12 @@ export default {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let url = URL.createObjectURL(imageBlob);
|
let url = URL.createObjectURL(imageBlob);
|
||||||
this.pages.base64 = this.pages[lastPage].croppa.generateDataUrl(
|
this.pages[lastPage].base64 = this.pages[
|
||||||
"image/jpg",
|
lastPage
|
||||||
0.8
|
].croppa.generateDataUrl(MIME_TYPE, COMPRESSION_RATE);
|
||||||
);
|
const c01 = this.pages[lastPage].croppa.generateDataUrl(MIME_TYPE, 0.1);
|
||||||
|
console.log(`COMPRESSION_RATE: ${this.pages[lastPage].base64.length}`);
|
||||||
|
console.log(`0.1: ${c01.length}`);
|
||||||
this.pages[lastPage].image = url;
|
this.pages[lastPage].image = url;
|
||||||
this.pages.push({
|
this.pages.push({
|
||||||
text: `Page ${nextPage}`,
|
text: `Page ${nextPage}`,
|
||||||
|
@ -566,16 +626,18 @@ export default {
|
||||||
rtl: true
|
rtl: true
|
||||||
},
|
},
|
||||||
pages: [],
|
pages: [],
|
||||||
bookWidth: 400,
|
bookWidth: DEFAULT_PAGE_WIDTH,
|
||||||
bookHeight: 600,
|
bookHeight: DEFAULT_PAGE_HEIGHT,
|
||||||
previewPages: [],
|
previewPages: [],
|
||||||
editMode: true,
|
editMode: true,
|
||||||
currentPage: -7,
|
currentPage: -7,
|
||||||
flipbookRef: false,
|
flipbookRef: false,
|
||||||
pageRotation: 0,
|
pageRotation: 0,
|
||||||
pageZoom: 500,
|
pageZoom: DEFAULT_ZOOM,
|
||||||
uploading: false,
|
uploading: false,
|
||||||
errors: {}
|
errors: {},
|
||||||
|
DEFAULT_PAGE_WIDTH,
|
||||||
|
DEFAULT_PAGE_HEIGHT
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -33,7 +33,7 @@ export default class ApiService {
|
||||||
return (await fetch('/api/v1/client/book/create', options)).json();
|
return (await fetch('/api/v1/client/book/create', options)).json();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(`uploadBook ERROR: ${e.message}`);
|
console.error(`uploadBook ERROR: ${e.message}`);
|
||||||
return e;
|
throw e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Reference in a new issue