Transparent layers are now also stored with transparency

This commit is contained in:
Igor Zinken
2020-12-31 11:05:37 +01:00
parent 047226986d
commit eb0e024f6d
6 changed files with 30 additions and 10 deletions

View File

@@ -57,9 +57,9 @@ npm run lint
# TODO / Roadmap
* Implement loaders on document load/save, image export and dropbox import
* Canvas util : store transparency of images into saved document
* Drawing masks on a rotated layer that is panned (or mirrored) is broken
* Dragging of masks on rotated/mirror content is kinda broken
* Restoring of document with rotated layers (smaller than document size) restores at incorrect offset
* Pasted selections should appear in center
* Zoom should always be center based
* Restoring documents containing rotated text is inaccurate

View File

@@ -24,12 +24,22 @@ export const JPEG = "image/jpeg";
export const PNG = "image/png";
export const GIF = "image/gif";
const TRANSPARENT_TYPES = [ PNG, GIF ];
export const ACCEPTED_FILE_TYPES = [ JPEG, PNG, GIF ];
export const ACCEPTED_FILE_EXTENSIONS = [ "jpg", "jpeg", "png", "gif" ];
export const EXPORTABLE_FILE_TYPES = [ JPEG, PNG ];
export const isCompressableFileType = type => type === JPEG;
export const isTransparent = ({ name, type }) => {
if ( type === "dropbox" ) {
// files imported from Dropbox don't list their mime type, derive from filename instead
return name.includes( ".png" ) || name.includes( ".gif" );
}
return TRANSPARENT_TYPES.includes( type );
}
export const typeToExt = type => {
switch ( type ) {
default:

View File

@@ -33,7 +33,7 @@ const LayerFactory = {
*/
create({
name = "New Layer",
type = LAYER_GRAPHIC, source = null, mask = null,
type = LAYER_GRAPHIC, transparent = true, source = null, mask = null,
x = 0, y = 0, maskX = 0, maskY = 0, width = 1, height = 1, visible = true,
effects = {}, text = {}
} = {}) {
@@ -42,6 +42,7 @@ const LayerFactory = {
name,
type,
source,
transparent,
mask,
x,
y,
@@ -65,8 +66,9 @@ const LayerFactory = {
return {
n: layer.name,
t: layer.type,
s: imageToBase64( layer.source, layer.width, layer.height ),
m: imageToBase64( layer.mask, layer.width, layer.height ),
tr: layer.transparent,
s: imageToBase64( layer.source, layer.width, layer.height, layer.transparent ),
m: imageToBase64( layer.mask, layer.width, layer.height, true ),
x: layer.x,
y: layer.y,
x2: layer.maskX,
@@ -89,6 +91,7 @@ const LayerFactory = {
return LayerFactory.create({
name: layer.n,
type: layer.t,
transparent: layer.tr,
source,
mask,
x: layer.x,

View File

@@ -21,7 +21,8 @@
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
import { mapGetters, mapMutations, mapActions } from "vuex";
import { LAYER_IMAGE } from "@/definitions/layer-types";
import { isTransparent } from "@/definitions/image-types";
import { LAYER_IMAGE } from "@/definitions/layer-types";
export default {
computed: {
@@ -51,8 +52,10 @@ export default {
source: image,
type: LAYER_IMAGE,
name: file.name,
transparent: isTransparent( file ),
...size,
};
switch ( this.fileTarget) {
default:
case "layer":

View File

@@ -40,15 +40,15 @@ export const createCanvas = ( optWidth = 0, optHeight = 0 ) => {
return { cvs, ctx };
};
export const imageToBase64 = ( bitmap, width, height ) => {
export const imageToBase64 = ( bitmap, width, height, transparent ) => {
let cvs;
if ( bitmap instanceof Image ) {
({ cvs } = createCanvas( width, height ));
cvs.getContext( "2d" ).drawImage( bitmap, 0, 0 );
return cvs.toDataURL( JPEG ); // assume photographic content TODO: check transparency
return cvs.toDataURL( transparent ? PNG : JPEG );
} else if ( bitmap instanceof HTMLCanvasElement ) {
cvs = bitmap;
return cvs.toDataURL( PNG ); // assume transparent content
return cvs.toDataURL( PNG ); // Canvas sources are always transparent
}
return "";
};

View File

@@ -37,6 +37,7 @@ describe( "Layer factory", () => {
id: expect.any( String ),
name: expect.any( String ),
type: LAYER_GRAPHIC,
transparent: true,
source: null,
mask: null,
x: 0,
@@ -57,6 +58,7 @@ describe( "Layer factory", () => {
const layer = LayerFactory.create({
name: "foo",
type: LAYER_IMAGE,
transparent: false,
source: { src: "bitmap" },
mask: { src: "mask" },
x: 100,
@@ -77,6 +79,7 @@ describe( "Layer factory", () => {
id: expect.any( String ),
name: "foo",
type: LAYER_IMAGE,
transparent: false,
source: { src: "bitmap" },
mask: { src: "mask" },
x: 100,
@@ -102,6 +105,7 @@ describe( "Layer factory", () => {
const layer = LayerFactory.create({
name: "foo",
type: LAYER_IMAGE,
transparent: false,
source: { src: "bitmap" },
mask: { src: "mask" },
x: 100,
@@ -119,8 +123,8 @@ describe( "Layer factory", () => {
mockUpdateFn = jest.fn(( fn, data ) => data );
const serialized = LayerFactory.serialize( layer );
expect( mockUpdateFn ).toHaveBeenNthCalledWith( 1, "imageToBase64", layer.source, layer.width, layer.height );
expect( mockUpdateFn ).toHaveBeenNthCalledWith( 2, "imageToBase64", layer.mask, layer.width, layer.height );
expect( mockUpdateFn ).toHaveBeenNthCalledWith( 1, "imageToBase64", layer.source, layer.width, layer.height, layer.transparent );
expect( mockUpdateFn ).toHaveBeenNthCalledWith( 2, "imageToBase64", layer.mask, layer.width, layer.height, true );
expect( mockUpdateFn ).toHaveBeenNthCalledWith( 3, "serializeText", layer.text );
expect( mockUpdateFn ).toHaveBeenNthCalledWith( 4, "serializeEffect", layer.effects );